aural-ui 4.0.1 → 4.2.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 +8 -1
- package/dist/components/aspect-ratio/AspectRatio.stories.tsx +290 -1228
- package/dist/components/avatar/Avatar.stories.tsx +219 -235
- package/dist/components/badge/Badge.stories.tsx +379 -116
- package/dist/components/banner/Banner.stories.tsx +445 -391
- package/dist/components/breadcrumb/Breadcrumb.stories.tsx +453 -199
- package/dist/components/button/Button.stories.tsx +585 -230
- package/dist/components/card/Card.stories.tsx +619 -301
- package/dist/components/char-count/CharCount.stories.tsx +350 -248
- package/dist/components/checkbox/Checkbox.stories.tsx +309 -167
- package/dist/components/chip/Chip.stories.tsx +362 -168
- package/dist/components/circular-loader/CircularLoader.stories.tsx +221 -636
- package/dist/components/clamp-lines/ClampLines.stories.tsx +246 -117
- package/dist/components/collapsible/Collapsible.stories.tsx +391 -252
- package/dist/components/command/Command.stories.tsx +530 -867
- package/dist/components/dialog/Dialog.stories.tsx +501 -950
- package/dist/components/divider/Divider.stories.tsx +264 -527
- package/dist/components/dot-loader/DotLoader.stories.tsx +256 -257
- package/dist/components/drawer/Drawer.stories.tsx +659 -1023
- package/dist/components/dropdown/Dropdown.stories.tsx +643 -1028
- package/dist/components/form/Form.stories.tsx +560 -274
- package/dist/components/helper-text/HelperText.stories.tsx +199 -200
- package/dist/components/hover-card/HoverCard.stories.tsx +318 -1254
- package/dist/components/icon-button/IconButton.stories.tsx +837 -194
- package/dist/components/if-else/if-else.stories.tsx +370 -83
- package/dist/components/input/Input.stories.tsx +436 -368
- package/dist/components/label/Label.stories.tsx +156 -154
- package/dist/components/list/List.stories.tsx +484 -835
- package/dist/components/marquee/Marquee.stories.tsx +356 -712
- package/dist/components/otp-inputs/OtpInputs.stories.tsx +352 -422
- package/dist/components/overlay/Overlay.stories.tsx +452 -824
- package/dist/components/pagination/Pagination.stories.tsx +721 -210
- package/dist/components/popover/Popover.stories.tsx +481 -896
- package/dist/components/radio/Radio.stories.tsx +432 -124
- package/dist/components/resizable/Resizable.stories.tsx +495 -799
- package/dist/components/scroll-area/ScrollArea.stories.tsx +383 -1059
- package/dist/components/search/Search.stories.tsx +312 -595
- package/dist/components/select/Select.stories.tsx +684 -789
- package/dist/components/sheet/Sheet.stories.tsx +671 -950
- package/dist/components/skelton/Skelton.stories.tsx +230 -764
- package/dist/components/slider/Slider.stories.tsx +383 -760
- package/dist/components/stepper/Stepper.stories.tsx +371 -514
- package/dist/components/switch/Switch.stories.tsx +461 -208
- package/dist/components/switch-case/SwitchCase.stories.tsx +367 -188
- package/dist/components/table/Table.stories.tsx +770 -916
- package/dist/components/tabs/Tabs.stories.tsx +458 -1455
- package/dist/components/tag/Tag.stories.tsx +714 -542
- package/dist/components/textarea/TextArea.stories.tsx +621 -562
- package/dist/components/thumbnail-tags/ThumbnailTags.stories.tsx +228 -154
- package/dist/components/toast/Toast.stories.tsx +452 -1339
- package/dist/components/toggle/Toggle.stories.tsx +488 -931
- package/dist/components/tooltip/Tooltip.stories.tsx +344 -1388
- package/dist/components/typography/Typography.stories.tsx +406 -89
- package/dist/hooks/use-change-state/UseChangeState.stories.tsx +309 -606
- package/dist/hooks/use-previous/UsePrevious.stories.tsx +367 -917
- package/dist/hooks/use-standalone-pagination/UseStandalonePagination.stories.tsx +639 -867
- package/dist/icons/Icons.stories.tsx +0 -12
- package/dist/icons/ai-avatar-icon/AiAvatarIcon.stories.tsx +223 -1060
- package/dist/icons/alert-icon/AlertIcon.stories.tsx +106 -968
- package/dist/icons/all-icons.tsx +37 -16
- package/dist/icons/angle-down-icon/AngleDownIcon.stories.tsx +137 -1010
- package/dist/icons/apple-logo-icon/AppleLogoIcon.stories.tsx +145 -935
- package/dist/icons/arrow-box-left-icon/ArrowBoxLeftIcon.stories.tsx +132 -1046
- package/dist/icons/arrow-corner-up-left-icon/ArrowCornerUpLeftIcon.stories.tsx +134 -986
- package/dist/icons/arrow-corner-up-right-icon/ArrowCornerUpRightIcon.stories.tsx +135 -1028
- package/dist/icons/arrow-left-icon/ArrowLeftIcon.stories.tsx +133 -971
- package/dist/icons/arrow-right-icon/ArrowRightIcon.stories.tsx +145 -1123
- package/dist/icons/arrow-right-up-icon/ArrowRightUpIcon.stories.tsx +143 -1252
- package/dist/icons/art-board-icon/ArtBoardIcon.stories.tsx +123 -632
- package/dist/icons/audio-bar-icon/AudioBarIcon.stories.tsx +141 -1223
- package/dist/icons/backward-ten-seconds-icon/BackwardTenSecondsIcon.stories.tsx +164 -1018
- package/dist/icons/bubble-check-icon/BubbleCheckIcon.stories.tsx +121 -1236
- package/dist/icons/bubble-crossed-icon/BubbleCrossedIcon.stories.tsx +121 -1213
- package/dist/icons/bubble-sparkle-icon/BubbleSparkleIcon.stories.tsx +116 -893
- package/dist/icons/camera-icon/CameraIcon.stories.tsx +109 -1254
- package/dist/icons/capital-a-letter-icon/CapitalALetterIcon.stories.tsx +114 -975
- package/dist/icons/chevron-double-left-icon/ChevronDoubleLeftIcon.stories.tsx +157 -994
- package/dist/icons/chevron-double-right-icon/ChevronDoubleRightIcon.stories.tsx +160 -992
- package/dist/icons/chevron-down-icon/ChevronDownIcon.stories.tsx +140 -970
- package/dist/icons/chevron-left-icon/ChevronLeftIcon.stories.tsx +126 -993
- package/dist/icons/chevron-right-icon/ChevronRightIcon.stories.tsx +144 -987
- package/dist/icons/chevron-up-icon/ChevronUpIcon.stories.tsx +141 -1007
- package/dist/icons/circle-tick-icon/CircleTickIcon.stories.tsx +147 -1187
- package/dist/icons/circular-play-icon/CircularPlayIcon.stories.tsx +110 -476
- package/dist/icons/coin-icon/CoinIcon.stories.tsx +120 -1364
- package/dist/icons/coin-toons-icon/CoinToonsIcon.stories.tsx +113 -1360
- package/dist/icons/column-wide-add-icon/ColumnWideAddIcon.stories.tsx +111 -942
- package/dist/icons/command-icon/CommandIcon.stories.tsx +124 -1087
- package/dist/icons/copy-icon/CopyIcon.stories.tsx +119 -996
- package/dist/icons/cross-circle-icon/CrossCircleIcon.stories.tsx +144 -1046
- package/dist/icons/cross-icon/CrossIcon.stories.tsx +136 -999
- package/dist/icons/download-icon/DownloadIcon.stories.tsx +123 -857
- package/dist/icons/edit-big-icon/EditBigIcon.stories.tsx +121 -1080
- package/dist/icons/email-icon/EmailIcon.stories.tsx +112 -979
- package/dist/icons/expand-icon/ExpandIcon.stories.tsx +109 -1146
- package/dist/icons/eye-close-icon/EyeCloseIcon.stories.tsx +141 -1068
- package/dist/icons/eye-open-icon/EyeOpenIcon.stories.tsx +140 -1081
- package/dist/icons/feature-shine-icon/FeatureShineIcon.stories.tsx +124 -1050
- package/dist/icons/file-chart-icon/FileChartIcon.stories.tsx +123 -1091
- package/dist/icons/file-text-icon/FileTextIcon.stories.tsx +122 -633
- package/dist/icons/filter-bar-row-icon/FilterBarRowIcon.stories.tsx +116 -1087
- package/dist/icons/forward-ten-seconds-icon/ForwardTenSecondsIcon.stories.tsx +166 -1020
- package/dist/icons/git-branch-icon/GitBranchIcon.stories.tsx +112 -1182
- package/dist/icons/git-fork-icon/GitForkIcon.stories.tsx +112 -1155
- package/dist/icons/globe-icon/GlobeIcon.stories.tsx +127 -325
- package/dist/icons/google-logo-icon/GoogleLogoIcon.stories.tsx +142 -985
- package/dist/icons/grip-vertical-icon/GripVerticalIcon.stories.tsx +116 -1217
- package/dist/icons/head-icon/HeadIcon.stories.tsx +108 -953
- package/dist/icons/heart-icon/HeartIcon.stories.tsx +117 -1060
- package/dist/icons/image-avatar-sparkle-icon/ImageAvatarSparkleIcon.stories.tsx +116 -716
- package/dist/icons/image-icon/ImageIcon.stories.tsx +102 -1164
- package/dist/icons/import-folder-icon/ImportFolderIcon.stories.tsx +108 -1233
- package/dist/icons/import-left-arrow-folder-icon/ImportLeftArrowFolderIcon.stories.tsx +133 -1289
- package/dist/icons/indian-flag-icon/IndianFlagIcon.stories.tsx +155 -1012
- package/dist/icons/instagram-icon/InstagramIcon.stories.tsx +158 -1438
- package/dist/icons/layout-column-icon/LayoutColumnIcon.stories.tsx +121 -1011
- package/dist/icons/layout-left-icon/LayoutLeftIcon.stories.tsx +116 -981
- package/dist/icons/layout-right-icon/LayoutRightIcon.stories.tsx +116 -979
- package/dist/icons/light-bulb-simple-icon/LightBulbSimpleIcon.stories.tsx +105 -1252
- package/dist/icons/linked-in-icon/LinkedInIcon.stories.tsx +151 -1554
- package/dist/icons/magic-book-icon/MagicBookIcon.stories.tsx +107 -1227
- package/dist/icons/magic-edit-icon/MagicEditIcon.stories.tsx +116 -707
- package/dist/icons/maintenance-icon/MaintenanceIcon.stories.tsx +119 -1226
- package/dist/icons/message-icon/MessageIcon.stories.tsx +111 -557
- package/dist/icons/minimize-icon/MinimizeIcon.stories.tsx +112 -1198
- package/dist/icons/moon-icon/MoonIcon.stories.tsx +117 -557
- package/dist/icons/move-horizontal-icon/MoveHorizontalIcon.stories.tsx +106 -1235
- package/dist/icons/move-vertical-icon/MoveVerticalIcon.stories.tsx +112 -1185
- package/dist/icons/musical-note-icon/MusicalNoteIcon.stories.tsx +116 -1012
- package/dist/icons/notepad-icon/NotepadIcon.stories.tsx +108 -1137
- package/dist/icons/notes-icon/NotesIcon.stories.tsx +116 -1138
- package/dist/icons/page-search-icon/PageSearchIcon.stories.tsx +106 -1146
- package/dist/icons/page-text-icon/PageTextIcon.stories.tsx +119 -719
- package/dist/icons/paint-roll-icon/PaintRollIcon.stories.tsx +110 -999
- package/dist/icons/paper-plane-icon/PaperPlaneIcon.stories.tsx +109 -912
- package/dist/icons/pause-icon/PauseIcon.stories.tsx +110 -1041
- package/dist/icons/pencil-icon/PencilIcon.stories.tsx +112 -1109
- package/dist/icons/phone-icon/PhoneIcon.stories.tsx +112 -1023
- package/dist/icons/plus-icon/PlusIcon.stories.tsx +103 -1132
- package/dist/icons/pocket-studio-icon/PocketStudioIcon.stories.tsx +104 -870
- package/dist/icons/scroll-down-icon/ScrollDownIcon.stories.tsx +99 -476
- package/dist/icons/search-icon/SearchIcon.stories.tsx +108 -1161
- package/dist/icons/setting-icon/SettingIcon.stories.tsx +104 -1009
- package/dist/icons/share-icon/ShareIcon.stories.tsx +117 -1064
- package/dist/icons/shield-icon/ShieldIcon.stories.tsx +114 -974
- package/dist/icons/site-logo-icon/SiteLogoIcon.stories.tsx +134 -1160
- package/dist/icons/skip-backward-icon/SkipBackwardIcon.stories.tsx +169 -1017
- package/dist/icons/skip-forward-icon/SkipForwardIcon.stories.tsx +161 -1016
- package/dist/icons/sparkles-soft-icon/SparklesSoftIcon.stories.tsx +102 -1001
- package/dist/icons/spinner-gradient-icon/SpinnerGradientIcon.stories.tsx +155 -593
- package/dist/icons/spinner-solid-icon/SpinnerSolidIcon.stories.tsx +155 -608
- package/dist/icons/spinner-solid-neutral-icon/SpinnerSolidINeutralcon.stories.tsx +142 -712
- package/dist/icons/star-icon/StarIcon.stories.tsx +120 -946
- package/dist/icons/store-coin-icon/StoreCoinIcon.stories.tsx +109 -1013
- package/dist/icons/suggestion-icon/SuggestionIcon.stories.tsx +113 -891
- package/dist/icons/sun-icon/SunIcon.stories.tsx +117 -864
- package/dist/icons/text-color-icon/TextColorIcon.stories.tsx +113 -989
- package/dist/icons/text-indicator-icon/TextIndicatorIcon.stories.tsx +120 -1027
- package/dist/icons/threads-icon/ThreadsIcon.stories.tsx +153 -1476
- package/dist/icons/tick-circle-icon/TickCircleIcon.stories.tsx +143 -1187
- package/dist/icons/tick-icon/TickIcon.stories.tsx +142 -1322
- package/dist/icons/trash-icon/TrashIcon.stories.tsx +105 -970
- package/dist/icons/twitter-x-icon/TwitterXIcon.stories.tsx +154 -1457
- package/dist/icons/upload-icon/UploadIcon.stories.tsx +112 -930
- package/dist/icons/vertical-menu-icon/VerticalMenuIcon.stories.tsx +115 -1019
- package/dist/icons/video-play-list-icon/VideoPlaylistIcon.stories.tsx +122 -1092
- package/dist/icons/voice-playing-icon/VoicePlayingIcon.stories.tsx +120 -1401
- package/dist/icons/volume-full-icon/VolumeFullIcon.stories.tsx +107 -1212
- package/dist/icons/volume-half-icon/VolumeHalfIcon.stories.tsx +109 -1122
- package/dist/icons/volume-off-icon/VolumeOffIcon.stories.tsx +112 -1124
- package/dist/icons/warning-icon/WarningIcon.stories.tsx +119 -1083
- package/dist/icons/youtube-icon/YoutubeIcon.stories.tsx +158 -983
- package/dist/index.cjs +90 -90
- package/dist/index.js +90 -90
- package/package.json +8 -3
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import React from "react"
|
|
1
|
+
import React, { useState } from "react"
|
|
2
2
|
import { Button } from "@components/button"
|
|
3
3
|
import Input from "@components/input"
|
|
4
4
|
import { Label } from "@components/label"
|
|
5
5
|
import type { Meta, StoryObj } from "@storybook/react-vite"
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { AuralComponentDocsPage } from "src/ui/story-spec/components/component-story-docs-page"
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
Popover,
|
|
@@ -14,43 +14,35 @@ import {
|
|
|
14
14
|
PopoverContent,
|
|
15
15
|
PopoverTrigger,
|
|
16
16
|
} from "."
|
|
17
|
-
import { IconButton } from "../icon-button"
|
|
18
17
|
|
|
19
18
|
const meta: Meta<typeof Popover> = {
|
|
20
19
|
title: "Components/UI/Popover",
|
|
21
20
|
component: Popover,
|
|
22
21
|
parameters: {
|
|
23
22
|
layout: "centered",
|
|
24
|
-
backgrounds: {
|
|
25
|
-
default: "dark",
|
|
26
|
-
values: [
|
|
27
|
-
{ name: "dark", value: "#0a0a0a" },
|
|
28
|
-
{ name: "light", value: "#ffffff" },
|
|
29
|
-
],
|
|
30
|
-
},
|
|
31
23
|
docs: {
|
|
32
24
|
description: {
|
|
33
|
-
component:
|
|
34
|
-
A
|
|
35
|
-
|
|
36
|
-
## Components Overview
|
|
37
|
-
|
|
38
|
-
- **Popover**: Root container managing state and context
|
|
39
|
-
- **PopoverTrigger**: Interactive element that opens the popover
|
|
40
|
-
- **PopoverContent**: The floating content panel with frosted glass effect
|
|
41
|
-
- **PopoverAnchor**: Custom positioning anchor point
|
|
42
|
-
- **PopoverArrow**: Optional arrow pointer to trigger
|
|
43
|
-
- **PopoverClose**: Button to close popover from within content
|
|
44
|
-
|
|
45
|
-
## Features
|
|
46
|
-
- Dark theme optimized with frosted glass effect
|
|
47
|
-
- Smooth CSS animations with direction awareness
|
|
48
|
-
- Comprehensive accessibility support
|
|
49
|
-
- Flexible positioning and anchoring
|
|
50
|
-
- Self-contained content management
|
|
51
|
-
- Portal rendering for proper stacking
|
|
52
|
-
`,
|
|
25
|
+
component:
|
|
26
|
+
"A compound floating panel built on Radix UI. Composed of Popover (root state), PopoverTrigger (toggle element), PopoverContent (frosted-glass panel with gradient top stroke), PopoverClose (dismiss button inside content), PopoverArrow (optional pointer), and PopoverAnchor (custom positioning reference). Portal-rendered for proper z-index stacking.",
|
|
53
27
|
},
|
|
28
|
+
page: () => (
|
|
29
|
+
<AuralComponentDocsPage
|
|
30
|
+
features={[
|
|
31
|
+
{
|
|
32
|
+
title: "Floating Panel",
|
|
33
|
+
description: "Portal z-index layering",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
title: "Compound Parts",
|
|
37
|
+
description: "Trigger, content, arrow",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
title: "Glass Aesthetic",
|
|
41
|
+
description: "Frosted top gradient",
|
|
42
|
+
},
|
|
43
|
+
]}
|
|
44
|
+
/>
|
|
45
|
+
),
|
|
54
46
|
},
|
|
55
47
|
},
|
|
56
48
|
tags: ["autodocs"],
|
|
@@ -59,1005 +51,598 @@ A comprehensive popover component system built on Radix UI with dark theme optim
|
|
|
59
51
|
export default meta
|
|
60
52
|
type Story = StoryObj<typeof meta>
|
|
61
53
|
|
|
62
|
-
//
|
|
63
|
-
export const PopoverRoot: Story = {
|
|
64
|
-
render: () => (
|
|
65
|
-
<div className="space-y-4">
|
|
66
|
-
<div className="text-center">
|
|
67
|
-
<h3 className="text-fm-primary mb-2 font-medium">
|
|
68
|
-
Popover Root Component
|
|
69
|
-
</h3>
|
|
70
|
-
<p className="text-fm-secondary text-sm">
|
|
71
|
-
The root Popover component manages state and provides context
|
|
72
|
-
</p>
|
|
73
|
-
</div>
|
|
74
|
-
|
|
75
|
-
<div className="flex justify-center gap-4">
|
|
76
|
-
{/* Uncontrolled Popover */}
|
|
77
|
-
<Popover>
|
|
78
|
-
<PopoverTrigger asChild>
|
|
79
|
-
<Button variant="outline">Uncontrolled</Button>
|
|
80
|
-
</PopoverTrigger>
|
|
81
|
-
<PopoverContent className="border-fm-divider-secondary rounded-lg border shadow-2xl">
|
|
82
|
-
<div className="p-4">
|
|
83
|
-
<p className="text-fm-primary text-sm">
|
|
84
|
-
This popover manages its own open/close state internally.
|
|
85
|
-
</p>
|
|
86
|
-
</div>
|
|
87
|
-
</PopoverContent>
|
|
88
|
-
</Popover>
|
|
54
|
+
// ─── Parts ───────────────────────────────────────────────────────────────────
|
|
89
55
|
|
|
90
|
-
|
|
91
|
-
<Popover defaultOpen={false}>
|
|
92
|
-
<PopoverTrigger asChild>
|
|
93
|
-
<Button variant="outline">Default Closed</Button>
|
|
94
|
-
</PopoverTrigger>
|
|
95
|
-
<PopoverContent className="border-fm-divider-secondary rounded-lg border shadow-2xl">
|
|
96
|
-
<div className="p-4">
|
|
97
|
-
<p className="text-fm-primary text-sm">
|
|
98
|
-
This popover starts in a closed state by default.
|
|
99
|
-
</p>
|
|
100
|
-
</div>
|
|
101
|
-
</PopoverContent>
|
|
102
|
-
</Popover>
|
|
103
|
-
|
|
104
|
-
{/* Modal Popover */}
|
|
105
|
-
<Popover modal>
|
|
106
|
-
<PopoverTrigger asChild>
|
|
107
|
-
<Button variant="outline">Modal Mode</Button>
|
|
108
|
-
</PopoverTrigger>
|
|
109
|
-
<PopoverContent className="border-fm-divider-secondary rounded-lg border shadow-2xl">
|
|
110
|
-
<div className="p-4">
|
|
111
|
-
<p className="text-fm-primary text-sm">
|
|
112
|
-
This is a modal popover that captures focus and blocks
|
|
113
|
-
interaction.
|
|
114
|
-
</p>
|
|
115
|
-
</div>
|
|
116
|
-
</PopoverContent>
|
|
117
|
-
</Popover>
|
|
118
|
-
</div>
|
|
119
|
-
</div>
|
|
120
|
-
),
|
|
56
|
+
export const Parts: Story = {
|
|
121
57
|
parameters: {
|
|
122
58
|
docs: {
|
|
123
59
|
description: {
|
|
124
60
|
story:
|
|
125
|
-
"
|
|
61
|
+
"Every sub-component shown individually with a description of its role in the compound pattern.",
|
|
126
62
|
},
|
|
127
63
|
},
|
|
128
64
|
},
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// 2. PopoverTrigger Component Examples
|
|
132
|
-
export const PopoverTriggerVariants: Story = {
|
|
133
65
|
render: () => (
|
|
134
|
-
<div className="space-y-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
Different types of trigger elements using asChild prop
|
|
141
|
-
</p>
|
|
142
|
-
</div>
|
|
143
|
-
|
|
144
|
-
<div className="grid grid-cols-2 gap-4">
|
|
145
|
-
{/* Button Trigger */}
|
|
66
|
+
<div className="w-full max-w-2xl space-y-10">
|
|
67
|
+
{/* PopoverTrigger */}
|
|
68
|
+
<div className="space-y-3">
|
|
69
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
70
|
+
PopoverTrigger
|
|
71
|
+
</h4>
|
|
146
72
|
<Popover>
|
|
147
73
|
<PopoverTrigger asChild>
|
|
148
|
-
<Button>
|
|
74
|
+
<Button variant="outline">Open Popover</Button>
|
|
149
75
|
</PopoverTrigger>
|
|
150
|
-
<PopoverContent className="
|
|
151
|
-
<
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
</p>
|
|
155
|
-
</div>
|
|
76
|
+
<PopoverContent className="rounded-lg p-4">
|
|
77
|
+
<p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
78
|
+
Triggered by the button above.
|
|
79
|
+
</p>
|
|
156
80
|
</PopoverContent>
|
|
157
81
|
</Popover>
|
|
82
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
|
|
83
|
+
<p className="text-fm-secondary font-fm-text text-fm-md leading-fm-xl">
|
|
84
|
+
The element that toggles the popover open/closed. Pass{" "}
|
|
85
|
+
<code>asChild</code> to render as any child element. Without{" "}
|
|
86
|
+
<code>asChild</code> it renders a plain <code><button></code>.
|
|
87
|
+
</p>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
158
90
|
|
|
159
|
-
|
|
160
|
-
|
|
91
|
+
{/* PopoverContent */}
|
|
92
|
+
<div className="space-y-3">
|
|
93
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
94
|
+
PopoverContent
|
|
95
|
+
</h4>
|
|
96
|
+
<Popover defaultOpen>
|
|
161
97
|
<PopoverTrigger asChild>
|
|
162
|
-
<Button
|
|
163
|
-
variant="text"
|
|
164
|
-
className="text-fm-info hover:text-fm-info-sec text-sm underline"
|
|
165
|
-
>
|
|
166
|
-
Click this link
|
|
167
|
-
</Button>
|
|
98
|
+
<Button variant="outline">Content panel (open)</Button>
|
|
168
99
|
</PopoverTrigger>
|
|
169
|
-
<PopoverContent className="
|
|
170
|
-
<
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
</
|
|
100
|
+
<PopoverContent className="rounded-lg p-4">
|
|
101
|
+
<p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
102
|
+
Frosted-glass panel with a gradient top stroke. Default width{" "}
|
|
103
|
+
<code>w-72</code>, max height <code>max-h-96</code>. Rendered in a
|
|
104
|
+
portal — safe across any stacking context.
|
|
105
|
+
</p>
|
|
175
106
|
</PopoverContent>
|
|
176
107
|
</Popover>
|
|
108
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
|
|
109
|
+
<p className="text-fm-secondary font-fm-text text-fm-md leading-fm-xl">
|
|
110
|
+
Accepts <code>align</code> (start / center / end), <code>side</code>{" "}
|
|
111
|
+
(top / right / bottom / left), and <code>sideOffset</code>. The
|
|
112
|
+
gradient top-stroke is always rendered automatically.
|
|
113
|
+
</p>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
177
116
|
|
|
178
|
-
|
|
179
|
-
|
|
117
|
+
{/* PopoverClose */}
|
|
118
|
+
<div className="space-y-3">
|
|
119
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
120
|
+
PopoverClose
|
|
121
|
+
</h4>
|
|
122
|
+
<Popover defaultOpen>
|
|
180
123
|
<PopoverTrigger asChild>
|
|
181
|
-
<
|
|
182
|
-
label="Icon Popover Button"
|
|
183
|
-
icon={<FeatureShineIcon />}
|
|
184
|
-
/>
|
|
124
|
+
<Button variant="outline">Open (with close button)</Button>
|
|
185
125
|
</PopoverTrigger>
|
|
186
|
-
<PopoverContent className="
|
|
187
|
-
<div className="
|
|
188
|
-
<p className="text-fm-primary text-sm">
|
|
189
|
-
|
|
126
|
+
<PopoverContent className="rounded-lg p-4">
|
|
127
|
+
<div className="flex items-center justify-between gap-4">
|
|
128
|
+
<p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
129
|
+
Click × to dismiss.
|
|
190
130
|
</p>
|
|
131
|
+
<PopoverClose asChild>
|
|
132
|
+
<Button variant="text" size="sm">
|
|
133
|
+
×
|
|
134
|
+
</Button>
|
|
135
|
+
</PopoverClose>
|
|
191
136
|
</div>
|
|
192
137
|
</PopoverContent>
|
|
193
138
|
</Popover>
|
|
139
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
|
|
140
|
+
<p className="text-fm-secondary font-fm-text text-fm-md leading-fm-xl">
|
|
141
|
+
Closes the popover from within the content panel. Use with{" "}
|
|
142
|
+
<code>asChild</code> to render as any button or icon. Must be placed
|
|
143
|
+
inside <code>PopoverContent</code>.
|
|
144
|
+
</p>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
194
147
|
|
|
195
|
-
|
|
196
|
-
|
|
148
|
+
{/* PopoverArrow */}
|
|
149
|
+
<div className="space-y-3">
|
|
150
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
151
|
+
PopoverArrow
|
|
152
|
+
</h4>
|
|
153
|
+
<Popover defaultOpen>
|
|
197
154
|
<PopoverTrigger asChild>
|
|
198
|
-
<
|
|
199
|
-
label="Profile Popover"
|
|
200
|
-
icon={null}
|
|
201
|
-
className="overflow-hidden"
|
|
202
|
-
>
|
|
203
|
-
<img
|
|
204
|
-
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=40&h=40&fit=crop&crop=face"
|
|
205
|
-
alt="Profile"
|
|
206
|
-
className="h-12 w-12 object-cover"
|
|
207
|
-
/>
|
|
208
|
-
</IconButton>
|
|
155
|
+
<Button variant="outline">Open (with arrow)</Button>
|
|
209
156
|
</PopoverTrigger>
|
|
210
|
-
<PopoverContent className="
|
|
211
|
-
<
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
</div>
|
|
157
|
+
<PopoverContent className="rounded-lg p-4" sideOffset={8}>
|
|
158
|
+
<p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
159
|
+
An arrow points back at the trigger.
|
|
160
|
+
</p>
|
|
161
|
+
<PopoverArrow className="fill-fm-surface-frosted/20" />
|
|
216
162
|
</PopoverContent>
|
|
217
163
|
</Popover>
|
|
164
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
|
|
165
|
+
<p className="text-fm-secondary font-fm-text text-fm-md leading-fm-xl">
|
|
166
|
+
Optional SVG arrow rendered inside <code>PopoverContent</code>.
|
|
167
|
+
Inherits positioning from the content and rotates automatically
|
|
168
|
+
based on side.
|
|
169
|
+
</p>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
{/* PopoverAnchor */}
|
|
174
|
+
<div className="space-y-3">
|
|
175
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
176
|
+
PopoverAnchor
|
|
177
|
+
</h4>
|
|
178
|
+
<Popover defaultOpen>
|
|
179
|
+
<div className="flex items-center gap-4">
|
|
180
|
+
<PopoverAnchor asChild>
|
|
181
|
+
<div className="border-fm-divider-secondary rounded-lg border px-4 py-2">
|
|
182
|
+
<span className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm">
|
|
183
|
+
Anchor element
|
|
184
|
+
</span>
|
|
185
|
+
</div>
|
|
186
|
+
</PopoverAnchor>
|
|
187
|
+
<PopoverTrigger asChild>
|
|
188
|
+
<Button variant="outline" size="sm">
|
|
189
|
+
Trigger
|
|
190
|
+
</Button>
|
|
191
|
+
</PopoverTrigger>
|
|
192
|
+
</div>
|
|
193
|
+
<PopoverContent className="rounded-lg p-4">
|
|
194
|
+
<p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
195
|
+
Positioned relative to the anchor box, not the trigger.
|
|
196
|
+
</p>
|
|
197
|
+
</PopoverContent>
|
|
198
|
+
</Popover>
|
|
199
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border p-4">
|
|
200
|
+
<p className="text-fm-secondary font-fm-text text-fm-md leading-fm-xl">
|
|
201
|
+
Decouples the visual anchor from the trigger. The popover positions
|
|
202
|
+
itself relative to <code>PopoverAnchor</code> while the trigger
|
|
203
|
+
retains click behavior. Useful for inline text flows or custom
|
|
204
|
+
layouts.
|
|
205
|
+
</p>
|
|
206
|
+
</div>
|
|
218
207
|
</div>
|
|
219
208
|
</div>
|
|
220
209
|
),
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ─── Configurations ──────────────────────────────────────────────────────────
|
|
213
|
+
|
|
214
|
+
export const Configurations: Story = {
|
|
221
215
|
parameters: {
|
|
222
216
|
docs: {
|
|
223
217
|
description: {
|
|
224
218
|
story:
|
|
225
|
-
"
|
|
219
|
+
"Positioning axes (side + align), sideOffset values, with close button, with arrow, and the anchored variant — all as live examples.",
|
|
226
220
|
},
|
|
227
221
|
},
|
|
228
222
|
},
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// 3. PopoverContent Component Examples
|
|
232
|
-
export const PopoverContentVariants: Story = {
|
|
233
223
|
render: () => (
|
|
234
|
-
<div className="space-y-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
<PopoverContent className="border-fm-divider-secondary w-56 rounded-lg border shadow-2xl">
|
|
253
|
-
<div className="p-3">
|
|
254
|
-
<p className="text-fm-primary text-sm">
|
|
255
|
-
Simple text content in a popover.
|
|
256
|
-
</p>
|
|
257
|
-
</div>
|
|
258
|
-
</PopoverContent>
|
|
259
|
-
</Popover>
|
|
260
|
-
|
|
261
|
-
{/* Rich Content */}
|
|
262
|
-
<Popover>
|
|
263
|
-
<PopoverTrigger asChild>
|
|
264
|
-
<Button variant="outline" size="sm">
|
|
265
|
-
Rich Content
|
|
266
|
-
</Button>
|
|
267
|
-
</PopoverTrigger>
|
|
268
|
-
<PopoverContent className="border-fm-divider-secondary w-72 rounded-lg border shadow-2xl">
|
|
269
|
-
<div className="space-y-3 p-4">
|
|
270
|
-
<div className="flex items-center gap-3">
|
|
271
|
-
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-blue-600">
|
|
272
|
-
<span className="text-fm-primary text-sm font-medium">
|
|
273
|
-
JD
|
|
274
|
-
</span>
|
|
275
|
-
</div>
|
|
276
|
-
<div>
|
|
277
|
-
<h4 className="text-fm-primary font-medium">John Doe</h4>
|
|
278
|
-
<p className="text-fm-secondary text-xs">
|
|
279
|
-
Software Developer
|
|
224
|
+
<div className="w-full max-w-3xl space-y-8">
|
|
225
|
+
{/* Side positioning */}
|
|
226
|
+
<div className="space-y-4">
|
|
227
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
228
|
+
Side — side prop
|
|
229
|
+
</h4>
|
|
230
|
+
<div className="flex flex-wrap justify-center gap-4">
|
|
231
|
+
{(["top", "right", "bottom", "left"] as const).map((side) => (
|
|
232
|
+
<div key={side} className="space-y-2 text-center">
|
|
233
|
+
<Popover>
|
|
234
|
+
<PopoverTrigger asChild>
|
|
235
|
+
<Button variant="outline" size="sm">
|
|
236
|
+
{side}
|
|
237
|
+
</Button>
|
|
238
|
+
</PopoverTrigger>
|
|
239
|
+
<PopoverContent side={side} className="w-40 rounded-lg p-3">
|
|
240
|
+
<p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
241
|
+
Opens to the <strong>{side}</strong>.
|
|
280
242
|
</p>
|
|
281
|
-
</
|
|
282
|
-
</
|
|
283
|
-
<p className="text-fm-secondary text-sm">
|
|
284
|
-
|
|
243
|
+
</PopoverContent>
|
|
244
|
+
</Popover>
|
|
245
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
246
|
+
{side}
|
|
285
247
|
</p>
|
|
286
248
|
</div>
|
|
287
|
-
|
|
288
|
-
</
|
|
289
|
-
|
|
290
|
-
{/* Custom Styled Content */}
|
|
291
|
-
<Popover>
|
|
292
|
-
<PopoverTrigger asChild>
|
|
293
|
-
<Button variant="outline" size="sm">
|
|
294
|
-
Custom Style
|
|
295
|
-
</Button>
|
|
296
|
-
</PopoverTrigger>
|
|
297
|
-
<PopoverContent className="w-64 rounded-lg border border-purple-500/30 bg-gradient-to-b from-purple-900/90 to-blue-900/90 shadow-2xl">
|
|
298
|
-
<div className="p-4">
|
|
299
|
-
<h4 className="text-fm-primary mb-2 font-medium">Custom Theme</h4>
|
|
300
|
-
<p className="text-fm-secondary text-sm">
|
|
301
|
-
PopoverContent with custom gradient background and purple theme.
|
|
302
|
-
</p>
|
|
303
|
-
</div>
|
|
304
|
-
</PopoverContent>
|
|
305
|
-
</Popover>
|
|
249
|
+
))}
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
306
252
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
253
|
+
{/* Alignment */}
|
|
254
|
+
<div className="space-y-4">
|
|
255
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
256
|
+
Alignment — align prop
|
|
257
|
+
</h4>
|
|
258
|
+
<div className="flex flex-wrap justify-center gap-4">
|
|
259
|
+
{(["start", "center", "end"] as const).map((align) => (
|
|
260
|
+
<div key={align} className="space-y-2 text-center">
|
|
261
|
+
<Popover>
|
|
262
|
+
<PopoverTrigger asChild>
|
|
263
|
+
<Button variant="outline" size="sm">
|
|
264
|
+
{align}
|
|
265
|
+
</Button>
|
|
266
|
+
</PopoverTrigger>
|
|
267
|
+
<PopoverContent align={align} className="rounded-lg p-3">
|
|
268
|
+
<p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
269
|
+
Aligned <strong>{align}</strong> to trigger.
|
|
270
|
+
</p>
|
|
271
|
+
</PopoverContent>
|
|
272
|
+
</Popover>
|
|
273
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
274
|
+
{align}
|
|
318
275
|
</p>
|
|
319
276
|
</div>
|
|
320
|
-
|
|
321
|
-
</Popover>
|
|
322
|
-
</div>
|
|
323
|
-
</div>
|
|
324
|
-
),
|
|
325
|
-
parameters: {
|
|
326
|
-
docs: {
|
|
327
|
-
description: {
|
|
328
|
-
story:
|
|
329
|
-
"PopoverContent examples with different styling approaches: simple, rich content, custom themes, and borderless variants.",
|
|
330
|
-
},
|
|
331
|
-
},
|
|
332
|
-
},
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// 4. PopoverAnchor Component Example
|
|
336
|
-
export const PopoverAnchorExample: Story = {
|
|
337
|
-
render: () => {
|
|
338
|
-
const [anchorEl, setAnchorEl] = React.useState<HTMLDivElement | null>(null)
|
|
339
|
-
|
|
340
|
-
return (
|
|
341
|
-
<div className="space-y-6">
|
|
342
|
-
<div className="text-center">
|
|
343
|
-
<h3 className="text-fm-primary mb-2 font-medium">
|
|
344
|
-
PopoverAnchor Component
|
|
345
|
-
</h3>
|
|
346
|
-
<p className="text-fm-secondary text-sm">
|
|
347
|
-
Position popover relative to a different element than the trigger
|
|
348
|
-
</p>
|
|
277
|
+
))}
|
|
349
278
|
</div>
|
|
279
|
+
</div>
|
|
350
280
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
<span className="text-fm-primary text-center text-xs font-medium">
|
|
358
|
-
Anchor
|
|
359
|
-
<br />
|
|
360
|
-
Point
|
|
361
|
-
</span>
|
|
362
|
-
</div>
|
|
363
|
-
|
|
364
|
-
{/* Trigger (separate from anchor) */}
|
|
281
|
+
{/* With close button */}
|
|
282
|
+
<div className="space-y-4">
|
|
283
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
284
|
+
With Close Button
|
|
285
|
+
</h4>
|
|
286
|
+
<div className="flex justify-center">
|
|
365
287
|
<Popover>
|
|
366
|
-
<PopoverAnchor
|
|
367
|
-
style={{
|
|
368
|
-
position: "absolute",
|
|
369
|
-
left: anchorEl?.offsetLeft || 0,
|
|
370
|
-
top: anchorEl?.offsetTop || 0,
|
|
371
|
-
width: anchorEl?.offsetWidth || 0,
|
|
372
|
-
height: anchorEl?.offsetHeight || 0,
|
|
373
|
-
}}
|
|
374
|
-
/>
|
|
375
288
|
<PopoverTrigger asChild>
|
|
376
|
-
<Button variant="outline">Open
|
|
289
|
+
<Button variant="outline">Open panel</Button>
|
|
377
290
|
</PopoverTrigger>
|
|
378
|
-
<PopoverContent className="
|
|
379
|
-
<
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
</p>
|
|
388
|
-
<div className="bg-fm-surface-secondary text-fm-tertiary rounded p-2 text-xs">
|
|
389
|
-
<strong>Note:</strong> The popover appears near the anchor
|
|
390
|
-
point even though the trigger is elsewhere.
|
|
291
|
+
<PopoverContent className="w-64 rounded-lg p-4">
|
|
292
|
+
<div className="flex items-start justify-between gap-3">
|
|
293
|
+
<div className="space-y-1">
|
|
294
|
+
<p className="text-fm-primary font-fm-text text-fm-md leading-fm-md font-semibold">
|
|
295
|
+
Quick note
|
|
296
|
+
</p>
|
|
297
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
298
|
+
Dismiss with the × button.
|
|
299
|
+
</p>
|
|
391
300
|
</div>
|
|
301
|
+
<PopoverClose asChild>
|
|
302
|
+
<button className="text-fm-tertiary hover:text-fm-primary text-lg leading-none transition-colors outline-none">
|
|
303
|
+
×
|
|
304
|
+
</button>
|
|
305
|
+
</PopoverClose>
|
|
392
306
|
</div>
|
|
393
307
|
</PopoverContent>
|
|
394
308
|
</Popover>
|
|
395
309
|
</div>
|
|
396
|
-
|
|
397
|
-
{/* Multiple Anchors Example */}
|
|
398
|
-
<div className="mt-8">
|
|
399
|
-
<h4 className="text-fm-primary mb-4 text-center font-medium">
|
|
400
|
-
Multiple Anchor Points
|
|
401
|
-
</h4>
|
|
402
|
-
<div className="flex justify-center gap-4">
|
|
403
|
-
{["Anchor A", "Anchor B", "Anchor C"].map((label) => {
|
|
404
|
-
const [anchor, setAnchor] = React.useState<HTMLDivElement | null>(
|
|
405
|
-
null
|
|
406
|
-
)
|
|
407
|
-
|
|
408
|
-
return (
|
|
409
|
-
<div key={label} className="space-y-2 text-center">
|
|
410
|
-
<div
|
|
411
|
-
ref={setAnchor}
|
|
412
|
-
className="flex h-16 w-16 items-center justify-center rounded-lg border border-green-400 bg-green-600"
|
|
413
|
-
>
|
|
414
|
-
<span className="text-fm-primary text-xs font-medium">
|
|
415
|
-
{label}
|
|
416
|
-
</span>
|
|
417
|
-
</div>
|
|
418
|
-
|
|
419
|
-
<Popover>
|
|
420
|
-
<PopoverAnchor
|
|
421
|
-
style={{
|
|
422
|
-
position: "absolute",
|
|
423
|
-
left: anchor?.offsetLeft || 0,
|
|
424
|
-
top: anchor?.offsetTop || 0,
|
|
425
|
-
width: anchor?.offsetWidth || 0,
|
|
426
|
-
height: anchor?.offsetHeight || 0,
|
|
427
|
-
}}
|
|
428
|
-
/>
|
|
429
|
-
<PopoverTrigger asChild>
|
|
430
|
-
<Button size="sm" variant="outline">
|
|
431
|
-
Open {label}
|
|
432
|
-
</Button>
|
|
433
|
-
</PopoverTrigger>
|
|
434
|
-
<PopoverContent className="border-fm-divider-secondary rounded-lg border shadow-2xl">
|
|
435
|
-
<div className="p-3">
|
|
436
|
-
<p className="text-fm-primary text-sm">
|
|
437
|
-
Content for {label}
|
|
438
|
-
</p>
|
|
439
|
-
</div>
|
|
440
|
-
</PopoverContent>
|
|
441
|
-
</Popover>
|
|
442
|
-
</div>
|
|
443
|
-
)
|
|
444
|
-
})}
|
|
445
|
-
</div>
|
|
446
|
-
</div>
|
|
447
310
|
</div>
|
|
448
|
-
)
|
|
449
|
-
},
|
|
450
|
-
parameters: {
|
|
451
|
-
docs: {
|
|
452
|
-
description: {
|
|
453
|
-
story:
|
|
454
|
-
"PopoverAnchor examples showing how to position popovers relative to different elements than their triggers, including single and multiple anchor scenarios.",
|
|
455
|
-
},
|
|
456
|
-
},
|
|
457
|
-
},
|
|
458
|
-
}
|
|
459
311
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
<
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
<div className="grid grid-cols-2 gap-6">
|
|
474
|
-
{/* Default Arrow */}
|
|
475
|
-
<Popover>
|
|
476
|
-
<PopoverTrigger asChild>
|
|
477
|
-
<Button variant="outline">Default Arrow</Button>
|
|
478
|
-
</PopoverTrigger>
|
|
479
|
-
<PopoverContent className="border-fm-divider-secondary rounded-lg border shadow-2xl">
|
|
480
|
-
<PopoverArrow className="fill-white/10" />
|
|
481
|
-
<div className="p-3">
|
|
482
|
-
<p className="text-fm-primary text-sm">
|
|
483
|
-
Default semi-transparent arrow
|
|
484
|
-
</p>
|
|
485
|
-
</div>
|
|
486
|
-
</PopoverContent>
|
|
487
|
-
</Popover>
|
|
488
|
-
|
|
489
|
-
{/* Solid Arrow */}
|
|
490
|
-
<Popover>
|
|
491
|
-
<PopoverTrigger asChild>
|
|
492
|
-
<Button variant="outline">Solid Arrow</Button>
|
|
493
|
-
</PopoverTrigger>
|
|
494
|
-
<PopoverContent className="bg-fm-surface-primary rounded-lg border border-gray-600 shadow-2xl">
|
|
495
|
-
<PopoverArrow className="fill-gray-800" />
|
|
496
|
-
<div className="p-3">
|
|
497
|
-
<p className="text-fm-primary text-sm">
|
|
498
|
-
Solid arrow matching background
|
|
499
|
-
</p>
|
|
500
|
-
</div>
|
|
501
|
-
</PopoverContent>
|
|
502
|
-
</Popover>
|
|
503
|
-
|
|
504
|
-
{/* Colored Arrow */}
|
|
505
|
-
<Popover>
|
|
506
|
-
<PopoverTrigger asChild>
|
|
507
|
-
<Button variant="outline">Colored Arrow</Button>
|
|
508
|
-
</PopoverTrigger>
|
|
509
|
-
<PopoverContent className="rounded-lg border border-blue-700 bg-blue-900 shadow-2xl">
|
|
510
|
-
<PopoverArrow className="fill-blue-700" />
|
|
511
|
-
<div className="p-3">
|
|
512
|
-
<p className="text-fm-primary text-sm">
|
|
513
|
-
Colored arrow with theme accent
|
|
514
|
-
</p>
|
|
515
|
-
</div>
|
|
516
|
-
</PopoverContent>
|
|
517
|
-
</Popover>
|
|
518
|
-
|
|
519
|
-
{/* Large Arrow */}
|
|
520
|
-
<Popover>
|
|
521
|
-
<PopoverTrigger asChild>
|
|
522
|
-
<Button variant="outline">Large Arrow</Button>
|
|
523
|
-
</PopoverTrigger>
|
|
524
|
-
<PopoverContent className="border-fm-divider-secondary rounded-lg border shadow-2xl">
|
|
525
|
-
<PopoverArrow className="h-4 w-4 fill-white/10" />
|
|
526
|
-
<div className="p-3">
|
|
527
|
-
<p className="text-fm-primary text-sm">Larger arrow size</p>
|
|
528
|
-
</div>
|
|
529
|
-
</PopoverContent>
|
|
530
|
-
</Popover>
|
|
531
|
-
|
|
532
|
-
{/* Gradient Arrow */}
|
|
533
|
-
<Popover>
|
|
534
|
-
<PopoverTrigger asChild>
|
|
535
|
-
<Button variant="outline">Gradient Arrow</Button>
|
|
536
|
-
</PopoverTrigger>
|
|
537
|
-
<PopoverContent className="rounded-lg border border-purple-600 bg-gradient-to-b from-purple-800 to-pink-800 shadow-2xl">
|
|
538
|
-
<PopoverArrow className="fill-purple-700" />
|
|
539
|
-
<div className="p-3">
|
|
540
|
-
<p className="text-fm-primary text-sm">
|
|
541
|
-
Arrow with gradient background
|
|
312
|
+
{/* With arrow */}
|
|
313
|
+
<div className="space-y-4">
|
|
314
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
315
|
+
With Arrow
|
|
316
|
+
</h4>
|
|
317
|
+
<div className="flex justify-center">
|
|
318
|
+
<Popover>
|
|
319
|
+
<PopoverTrigger asChild>
|
|
320
|
+
<Button variant="outline">Open with arrow</Button>
|
|
321
|
+
</PopoverTrigger>
|
|
322
|
+
<PopoverContent className="w-56 rounded-lg p-4" sideOffset={10}>
|
|
323
|
+
<p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
324
|
+
The arrow points back at the trigger.
|
|
542
325
|
</p>
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
{/* No Arrow */}
|
|
548
|
-
<Popover>
|
|
549
|
-
<PopoverTrigger asChild>
|
|
550
|
-
<Button variant="outline">No Arrow</Button>
|
|
551
|
-
</PopoverTrigger>
|
|
552
|
-
<PopoverContent className="border-fm-divider-secondary rounded-lg border shadow-2xl">
|
|
553
|
-
<div className="p-3">
|
|
554
|
-
<p className="text-fm-primary text-sm">Popover without arrow</p>
|
|
555
|
-
</div>
|
|
556
|
-
</PopoverContent>
|
|
557
|
-
</Popover>
|
|
326
|
+
<PopoverArrow className="fill-fm-surface-frosted/20" />
|
|
327
|
+
</PopoverContent>
|
|
328
|
+
</Popover>
|
|
329
|
+
</div>
|
|
558
330
|
</div>
|
|
559
331
|
|
|
560
|
-
{/*
|
|
561
|
-
<div className="
|
|
562
|
-
<h4 className="text-fm-
|
|
563
|
-
|
|
332
|
+
{/* Anchored variant */}
|
|
333
|
+
<div className="space-y-4">
|
|
334
|
+
<h4 className="text-fm-secondary font-fm-text text-fm-md leading-fm-md font-medium">
|
|
335
|
+
Anchored Variant
|
|
564
336
|
</h4>
|
|
565
|
-
<div className="flex justify-center
|
|
566
|
-
|
|
567
|
-
<
|
|
337
|
+
<div className="flex justify-center">
|
|
338
|
+
<Popover>
|
|
339
|
+
<div className="flex items-center gap-3">
|
|
340
|
+
<PopoverAnchor asChild>
|
|
341
|
+
<div className="border-fm-divider-secondary min-w-32 rounded-lg border px-3 py-2">
|
|
342
|
+
<span className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
343
|
+
Search field
|
|
344
|
+
</span>
|
|
345
|
+
</div>
|
|
346
|
+
</PopoverAnchor>
|
|
568
347
|
<PopoverTrigger asChild>
|
|
569
|
-
<Button
|
|
570
|
-
{side}
|
|
571
|
-
</Button>
|
|
348
|
+
<Button size="sm">Suggest</Button>
|
|
572
349
|
</PopoverTrigger>
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
</div>
|
|
581
|
-
</PopoverContent>
|
|
582
|
-
</Popover>
|
|
583
|
-
))}
|
|
350
|
+
</div>
|
|
351
|
+
<PopoverContent className="w-64 rounded-lg p-4">
|
|
352
|
+
<p className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
353
|
+
Positioned over the anchor, not the trigger button.
|
|
354
|
+
</p>
|
|
355
|
+
</PopoverContent>
|
|
356
|
+
</Popover>
|
|
584
357
|
</div>
|
|
585
358
|
</div>
|
|
586
359
|
</div>
|
|
587
360
|
),
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// ─── Interactive ──────────────────────────────────────────────────────────────
|
|
364
|
+
|
|
365
|
+
export const Interactive: Story = {
|
|
588
366
|
parameters: {
|
|
589
367
|
docs: {
|
|
590
368
|
description: {
|
|
591
369
|
story:
|
|
592
|
-
"
|
|
370
|
+
"Live popovers with action panels inside — add to playlist and share options — demonstrating real audio-app workflows with controlled state.",
|
|
593
371
|
},
|
|
594
372
|
},
|
|
595
373
|
},
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
374
|
+
render: () => {
|
|
375
|
+
const AddToPlaylist = () => {
|
|
376
|
+
const [selected, setSelected] = useState<string[]>([])
|
|
377
|
+
const [newName, setNewName] = useState("")
|
|
378
|
+
|
|
379
|
+
const playlists = [
|
|
380
|
+
"Late Night Drives",
|
|
381
|
+
"Morning Workout",
|
|
382
|
+
"Focus Mode",
|
|
383
|
+
"Weekend Vibes",
|
|
384
|
+
]
|
|
385
|
+
|
|
386
|
+
const toggle = (name: string) =>
|
|
387
|
+
setSelected((prev) =>
|
|
388
|
+
prev.includes(name) ? prev.filter((p) => p !== name) : [...prev, name]
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
return (
|
|
613
392
|
<Popover>
|
|
614
393
|
<PopoverTrigger asChild>
|
|
615
|
-
<Button variant="outline"
|
|
394
|
+
<Button variant="outline" size="sm">
|
|
395
|
+
+ Add to Playlist
|
|
396
|
+
</Button>
|
|
616
397
|
</PopoverTrigger>
|
|
617
|
-
<PopoverContent className="
|
|
618
|
-
<
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
<h4 className="text-fm-primary font-medium">Settings</h4>
|
|
622
|
-
<PopoverClose asChild>
|
|
623
|
-
<Button variant="text" size="sm">
|
|
624
|
-
✕
|
|
625
|
-
</Button>
|
|
626
|
-
</PopoverClose>
|
|
627
|
-
</div>
|
|
628
|
-
<p className="text-fm-secondary text-sm">
|
|
629
|
-
Close button in the header
|
|
398
|
+
<PopoverContent className="w-72 rounded-xl">
|
|
399
|
+
<div className="space-y-4 p-4">
|
|
400
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold tracking-widest uppercase">
|
|
401
|
+
Add to Playlist
|
|
630
402
|
</p>
|
|
631
|
-
</div>
|
|
632
|
-
</PopoverContent>
|
|
633
|
-
</Popover>
|
|
634
403
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
404
|
+
<div className="space-y-1">
|
|
405
|
+
{playlists.map((pl) => (
|
|
406
|
+
<button
|
|
407
|
+
key={pl}
|
|
408
|
+
onClick={() => toggle(pl)}
|
|
409
|
+
className="hover:bg-fm-surface-secondary flex w-full items-center justify-between rounded-lg px-3 py-2 transition-colors"
|
|
410
|
+
>
|
|
411
|
+
<span className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
412
|
+
{pl}
|
|
413
|
+
</span>
|
|
414
|
+
{selected.includes(pl) && (
|
|
415
|
+
<span className="text-fm-positive font-fm-text text-fm-xs leading-fm-xs">
|
|
416
|
+
✓
|
|
417
|
+
</span>
|
|
418
|
+
)}
|
|
419
|
+
</button>
|
|
420
|
+
))}
|
|
421
|
+
</div>
|
|
422
|
+
|
|
423
|
+
<div className="border-fm-divider-secondary space-y-2 border-t pt-3">
|
|
424
|
+
<Label className="text-fm-secondary font-fm-text text-fm-xs leading-fm-xs">
|
|
425
|
+
New playlist
|
|
426
|
+
</Label>
|
|
427
|
+
<div className="flex gap-2">
|
|
428
|
+
<Input
|
|
429
|
+
value={newName}
|
|
430
|
+
onChange={(e) => setNewName(e.target.value)}
|
|
431
|
+
placeholder="Playlist name…"
|
|
432
|
+
className="text-fm-sm flex-1"
|
|
433
|
+
/>
|
|
434
|
+
<PopoverClose asChild>
|
|
435
|
+
<Button
|
|
436
|
+
size="sm"
|
|
437
|
+
disabled={!newName.trim()}
|
|
438
|
+
onClick={() => setNewName("")}
|
|
439
|
+
>
|
|
440
|
+
Create
|
|
441
|
+
</Button>
|
|
442
|
+
</PopoverClose>
|
|
443
|
+
</div>
|
|
654
444
|
</div>
|
|
655
445
|
</div>
|
|
656
446
|
</PopoverContent>
|
|
657
447
|
</Popover>
|
|
448
|
+
)
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const ShareOptions = () => {
|
|
452
|
+
const [copied, setCopied] = useState(false)
|
|
453
|
+
|
|
454
|
+
const copy = () => {
|
|
455
|
+
setCopied(true)
|
|
456
|
+
setTimeout(() => setCopied(false), 1500)
|
|
457
|
+
}
|
|
658
458
|
|
|
659
|
-
|
|
459
|
+
return (
|
|
660
460
|
<Popover>
|
|
661
461
|
<PopoverTrigger asChild>
|
|
662
|
-
<Button variant="outline"
|
|
462
|
+
<Button variant="outline" size="sm">
|
|
463
|
+
Share Track
|
|
464
|
+
</Button>
|
|
663
465
|
</PopoverTrigger>
|
|
664
|
-
<PopoverContent className="
|
|
665
|
-
<PopoverArrow className="fill-white/10" />
|
|
466
|
+
<PopoverContent className="w-72 rounded-xl">
|
|
666
467
|
<div className="space-y-4 p-4">
|
|
667
468
|
<div className="flex items-center justify-between">
|
|
668
|
-
<
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
✕
|
|
672
|
-
</Button>
|
|
673
|
-
</PopoverClose>
|
|
674
|
-
</div>
|
|
675
|
-
|
|
676
|
-
<div className="space-y-2">
|
|
677
|
-
<PopoverClose asChild>
|
|
678
|
-
<button className="text-fm-primary hover:bg-fm-surface-secondary w-full rounded px-3 py-2 text-left text-sm">
|
|
679
|
-
Save and Close
|
|
680
|
-
</button>
|
|
681
|
-
</PopoverClose>
|
|
469
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold tracking-widest uppercase">
|
|
470
|
+
Share
|
|
471
|
+
</p>
|
|
682
472
|
<PopoverClose asChild>
|
|
683
|
-
<button className="text-fm-
|
|
684
|
-
|
|
473
|
+
<button className="text-fm-tertiary hover:text-fm-primary text-lg leading-none transition-colors outline-none">
|
|
474
|
+
×
|
|
685
475
|
</button>
|
|
686
476
|
</PopoverClose>
|
|
687
|
-
<button className="text-fm-primary hover:bg-fm-surface-secondary w-full rounded px-3 py-2 text-left text-sm">
|
|
688
|
-
Keep Open
|
|
689
|
-
</button>
|
|
690
477
|
</div>
|
|
691
|
-
</div>
|
|
692
|
-
</PopoverContent>
|
|
693
|
-
</Popover>
|
|
694
478
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
<PopoverClose asChild>
|
|
711
|
-
<Button variant="text" size="sm">
|
|
712
|
-
<svg
|
|
713
|
-
className="h-4 w-4"
|
|
714
|
-
fill="none"
|
|
715
|
-
stroke="currentColor"
|
|
716
|
-
viewBox="0 0 24 24"
|
|
717
|
-
>
|
|
718
|
-
<path
|
|
719
|
-
strokeLinecap="round"
|
|
720
|
-
strokeLinejoin="round"
|
|
721
|
-
strokeWidth={2}
|
|
722
|
-
d="M6 18L18 6M6 6l12 12"
|
|
723
|
-
/>
|
|
724
|
-
</svg>
|
|
725
|
-
</Button>
|
|
726
|
-
</PopoverClose>
|
|
727
|
-
</div>
|
|
728
|
-
</div>
|
|
729
|
-
</PopoverContent>
|
|
730
|
-
</Popover>
|
|
731
|
-
|
|
732
|
-
{/* Text Close Link */}
|
|
733
|
-
<Popover>
|
|
734
|
-
<PopoverTrigger asChild>
|
|
735
|
-
<Button variant="outline">Text Close</Button>
|
|
736
|
-
</PopoverTrigger>
|
|
737
|
-
<PopoverContent className="border-fm-divider-secondary w-64 rounded-lg border shadow-2xl">
|
|
738
|
-
<PopoverArrow className="fill-white/10" />
|
|
739
|
-
<div className="space-y-3 p-4">
|
|
740
|
-
<h4 className="text-fm-primary font-medium">Quick Tip</h4>
|
|
741
|
-
<p className="text-fm-secondary text-sm">
|
|
742
|
-
Use keyboard shortcuts to speed up your workflow.
|
|
743
|
-
</p>
|
|
744
|
-
<div className="text-right">
|
|
745
|
-
<PopoverClose asChild>
|
|
746
|
-
<button className="text-fm-info hover:text-fm-info-sec text-sm underline">
|
|
747
|
-
Got it, thanks!
|
|
479
|
+
<div className="space-y-2">
|
|
480
|
+
{[
|
|
481
|
+
"Copy Link",
|
|
482
|
+
"Share to Profile",
|
|
483
|
+
"Send to Friend",
|
|
484
|
+
"Embed",
|
|
485
|
+
].map((action) => (
|
|
486
|
+
<button
|
|
487
|
+
key={action}
|
|
488
|
+
onClick={action === "Copy Link" ? copy : undefined}
|
|
489
|
+
className="hover:bg-fm-surface-secondary flex w-full items-center gap-3 rounded-lg px-3 py-2 text-left transition-colors"
|
|
490
|
+
>
|
|
491
|
+
<span className="text-fm-primary font-fm-text text-fm-sm leading-fm-sm">
|
|
492
|
+
{action === "Copy Link" && copied ? "Copied!" : action}
|
|
493
|
+
</span>
|
|
748
494
|
</button>
|
|
749
|
-
|
|
495
|
+
))}
|
|
750
496
|
</div>
|
|
751
|
-
</div>
|
|
752
|
-
</PopoverContent>
|
|
753
|
-
</Popover>
|
|
754
497
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
</PopoverTrigger>
|
|
760
|
-
<PopoverContent className="border-fm-divider-secondary w-72 rounded-lg border shadow-2xl">
|
|
761
|
-
<PopoverArrow className="fill-white/10" />
|
|
762
|
-
<div className="space-y-3 p-4">
|
|
763
|
-
<h4 className="text-fm-primary font-medium">Quick Actions</h4>
|
|
764
|
-
<div className="grid grid-cols-2 gap-2">
|
|
765
|
-
<PopoverClose asChild>
|
|
766
|
-
<Button size="sm" variant="outline">
|
|
767
|
-
Copy
|
|
768
|
-
</Button>
|
|
769
|
-
</PopoverClose>
|
|
770
|
-
<PopoverClose asChild>
|
|
771
|
-
<Button size="sm" variant="outline">
|
|
772
|
-
Share
|
|
773
|
-
</Button>
|
|
774
|
-
</PopoverClose>
|
|
775
|
-
<PopoverClose asChild>
|
|
776
|
-
<Button size="sm" variant="outline">
|
|
777
|
-
Download
|
|
778
|
-
</Button>
|
|
779
|
-
</PopoverClose>
|
|
780
|
-
<PopoverClose asChild>
|
|
781
|
-
<Button size="sm" variant="outline">
|
|
782
|
-
Delete
|
|
783
|
-
</Button>
|
|
784
|
-
</PopoverClose>
|
|
498
|
+
<div className="border-fm-divider-secondary border-t pt-3">
|
|
499
|
+
<p className="text-fm-tertiary font-fm-text text-fm-xs leading-fm-xs">
|
|
500
|
+
Midnight Rain · Taylor Swift · Midnights
|
|
501
|
+
</p>
|
|
785
502
|
</div>
|
|
786
|
-
<p className="text-fm-tertiary text-xs">
|
|
787
|
-
Actions will close the popover automatically
|
|
788
|
-
</p>
|
|
789
503
|
</div>
|
|
790
504
|
</PopoverContent>
|
|
791
505
|
</Popover>
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
render: () => (
|
|
808
|
-
<div className="space-y-6">
|
|
809
|
-
<div className="text-center">
|
|
810
|
-
<h3 className="text-fm-primary mb-2 font-medium">
|
|
811
|
-
Complete Integration
|
|
812
|
-
</h3>
|
|
813
|
-
<p className="text-fm-secondary text-sm">
|
|
814
|
-
All components working together in real-world scenarios
|
|
815
|
-
</p>
|
|
816
|
-
</div>
|
|
817
|
-
|
|
818
|
-
<div className="flex justify-center gap-4">
|
|
819
|
-
{/* Complete User Menu */}
|
|
506
|
+
)
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const EQSettings = () => {
|
|
510
|
+
const bands = [
|
|
511
|
+
{ label: "Bass", freq: "80 Hz", default: 3 },
|
|
512
|
+
{ label: "Low Mid", freq: "500 Hz", default: 0 },
|
|
513
|
+
{ label: "High Mid", freq: "3 kHz", default: -1 },
|
|
514
|
+
{ label: "Treble", freq: "10 kHz", default: -2 },
|
|
515
|
+
]
|
|
516
|
+
const [values, setValues] = useState<Record<string, number>>(
|
|
517
|
+
Object.fromEntries(bands.map(({ label, default: d }) => [label, d]))
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
return (
|
|
820
521
|
<Popover>
|
|
821
522
|
<PopoverTrigger asChild>
|
|
822
|
-
<Button variant="
|
|
823
|
-
|
|
824
|
-
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=32&h=32&fit=crop&crop=face"
|
|
825
|
-
alt="Profile"
|
|
826
|
-
className="border-fm-divider-secondary h-8 w-8 rounded-full border"
|
|
827
|
-
/>
|
|
828
|
-
<span className="text-sm">John Doe</span>
|
|
829
|
-
<svg
|
|
830
|
-
className="text-fm-secondary h-4 w-4"
|
|
831
|
-
fill="none"
|
|
832
|
-
stroke="currentColor"
|
|
833
|
-
viewBox="0 0 24 24"
|
|
834
|
-
>
|
|
835
|
-
<path
|
|
836
|
-
strokeLinecap="round"
|
|
837
|
-
strokeLinejoin="round"
|
|
838
|
-
strokeWidth={2}
|
|
839
|
-
d="M19 9l-7 7-7-7"
|
|
840
|
-
/>
|
|
841
|
-
</svg>
|
|
523
|
+
<Button variant="outline" size="sm">
|
|
524
|
+
EQ Settings
|
|
842
525
|
</Button>
|
|
843
526
|
</PopoverTrigger>
|
|
844
|
-
<PopoverContent
|
|
845
|
-
align="end"
|
|
846
|
-
className="border-fm-divider-secondary w-80 rounded-lg border shadow-2xl"
|
|
847
|
-
>
|
|
848
|
-
<PopoverArrow className="fill-white/10" />
|
|
527
|
+
<PopoverContent className="w-72 rounded-xl">
|
|
849
528
|
<div className="space-y-4 p-4">
|
|
850
|
-
{/* Header with close */}
|
|
851
529
|
<div className="flex items-center justify-between">
|
|
852
|
-
<
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
530
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold tracking-widest uppercase">
|
|
531
|
+
Equalizer
|
|
532
|
+
</p>
|
|
533
|
+
<button
|
|
534
|
+
onClick={() =>
|
|
535
|
+
setValues(
|
|
536
|
+
Object.fromEntries(
|
|
537
|
+
bands.map(({ label, default: d }) => [label, d])
|
|
538
|
+
)
|
|
539
|
+
)
|
|
540
|
+
}
|
|
541
|
+
className="text-fm-tertiary hover:text-fm-primary font-fm-text text-fm-xs leading-fm-xs transition-colors"
|
|
542
|
+
>
|
|
543
|
+
Reset
|
|
544
|
+
</button>
|
|
858
545
|
</div>
|
|
859
546
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
547
|
+
<div className="space-y-3">
|
|
548
|
+
{bands.map(({ label, freq }) => (
|
|
549
|
+
<div key={label} className="space-y-1">
|
|
550
|
+
<div className="flex items-center justify-between">
|
|
551
|
+
<span className="text-fm-secondary font-fm-text text-fm-xs leading-fm-xs">
|
|
552
|
+
{label} · {freq}
|
|
553
|
+
</span>
|
|
554
|
+
<span className="text-fm-primary font-fm-text text-fm-xs leading-fm-xs w-12 text-right">
|
|
555
|
+
{values[label] > 0 ? "+" : ""}
|
|
556
|
+
{values[label]} dB
|
|
557
|
+
</span>
|
|
558
|
+
</div>
|
|
559
|
+
<input
|
|
560
|
+
type="range"
|
|
561
|
+
min={-12}
|
|
562
|
+
max={12}
|
|
563
|
+
step={1}
|
|
564
|
+
value={values[label]}
|
|
565
|
+
onChange={(e) =>
|
|
566
|
+
setValues((v) => ({
|
|
567
|
+
...v,
|
|
568
|
+
[label]: Number(e.target.value),
|
|
569
|
+
}))
|
|
570
|
+
}
|
|
571
|
+
className="accent-fm-primary h-1 w-full"
|
|
572
|
+
/>
|
|
871
573
|
</div>
|
|
872
|
-
|
|
574
|
+
))}
|
|
873
575
|
</div>
|
|
874
576
|
|
|
875
|
-
|
|
876
|
-
<div className="grid grid-cols-2 gap-2">
|
|
577
|
+
<div className="flex gap-2 pt-1">
|
|
877
578
|
<PopoverClose asChild>
|
|
878
|
-
<Button size="sm"
|
|
879
|
-
|
|
579
|
+
<Button size="sm" className="flex-1">
|
|
580
|
+
Apply
|
|
880
581
|
</Button>
|
|
881
582
|
</PopoverClose>
|
|
882
583
|
<PopoverClose asChild>
|
|
883
|
-
<Button
|
|
884
|
-
|
|
584
|
+
<Button variant="outline" size="sm">
|
|
585
|
+
Cancel
|
|
885
586
|
</Button>
|
|
886
587
|
</PopoverClose>
|
|
887
588
|
</div>
|
|
888
|
-
|
|
889
|
-
{/* Menu Items */}
|
|
890
|
-
<div className="space-y-1">
|
|
891
|
-
<PopoverClose asChild>
|
|
892
|
-
<button className="text-fm-primary hover:bg-fm-surface-secondary flex w-full items-center gap-2 rounded px-3 py-2 text-left text-sm">
|
|
893
|
-
<svg
|
|
894
|
-
className="h-4 w-4"
|
|
895
|
-
fill="none"
|
|
896
|
-
stroke="currentColor"
|
|
897
|
-
viewBox="0 0 24 24"
|
|
898
|
-
>
|
|
899
|
-
<path
|
|
900
|
-
strokeLinecap="round"
|
|
901
|
-
strokeLinejoin="round"
|
|
902
|
-
strokeWidth={2}
|
|
903
|
-
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
|
904
|
-
/>
|
|
905
|
-
</svg>
|
|
906
|
-
My Documents
|
|
907
|
-
</button>
|
|
908
|
-
</PopoverClose>
|
|
909
|
-
<PopoverClose asChild>
|
|
910
|
-
<button className="text-fm-primary hover:bg-fm-surface-secondary flex w-full items-center gap-2 rounded px-3 py-2 text-left text-sm">
|
|
911
|
-
<svg
|
|
912
|
-
className="h-4 w-4"
|
|
913
|
-
fill="none"
|
|
914
|
-
stroke="currentColor"
|
|
915
|
-
viewBox="0 0 24 24"
|
|
916
|
-
>
|
|
917
|
-
<path
|
|
918
|
-
strokeLinecap="round"
|
|
919
|
-
strokeLinejoin="round"
|
|
920
|
-
strokeWidth={2}
|
|
921
|
-
d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"
|
|
922
|
-
/>
|
|
923
|
-
</svg>
|
|
924
|
-
Billing
|
|
925
|
-
</button>
|
|
926
|
-
</PopoverClose>
|
|
927
|
-
<PopoverClose asChild>
|
|
928
|
-
<button className="text-fm-primary hover:bg-fm-surface-secondary flex w-full items-center gap-2 rounded px-3 py-2 text-left text-sm">
|
|
929
|
-
<svg
|
|
930
|
-
className="h-4 w-4"
|
|
931
|
-
fill="none"
|
|
932
|
-
stroke="currentColor"
|
|
933
|
-
viewBox="0 0 24 24"
|
|
934
|
-
>
|
|
935
|
-
<path
|
|
936
|
-
strokeLinecap="round"
|
|
937
|
-
strokeLinejoin="round"
|
|
938
|
-
strokeWidth={2}
|
|
939
|
-
d="M18.364 5.636l-3.536 3.536m0 5.656l3.536 3.536M9.172 9.172L5.636 5.636m3.536 9.192l-3.536 3.536M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-5 0a4 4 0 11-8 0 4 4 0 018 0z"
|
|
940
|
-
/>
|
|
941
|
-
</svg>
|
|
942
|
-
Help & Support
|
|
943
|
-
</button>
|
|
944
|
-
</PopoverClose>
|
|
945
|
-
</div>
|
|
946
|
-
|
|
947
|
-
{/* Sign Out */}
|
|
948
|
-
<div className="border-fm-divider-secondary border-t pt-3">
|
|
949
|
-
<PopoverClose asChild>
|
|
950
|
-
<button className="text-fm-icon-negative hover:bg-fm-surface-secondary flex w-full items-center gap-2 rounded px-3 py-2 text-left text-sm">
|
|
951
|
-
<svg
|
|
952
|
-
className="h-4 w-4"
|
|
953
|
-
fill="none"
|
|
954
|
-
stroke="currentColor"
|
|
955
|
-
viewBox="0 0 24 24"
|
|
956
|
-
>
|
|
957
|
-
<path
|
|
958
|
-
strokeLinecap="round"
|
|
959
|
-
strokeLinejoin="round"
|
|
960
|
-
strokeWidth={2}
|
|
961
|
-
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
|
|
962
|
-
/>
|
|
963
|
-
</svg>
|
|
964
|
-
Sign Out
|
|
965
|
-
</button>
|
|
966
|
-
</PopoverClose>
|
|
967
|
-
</div>
|
|
968
589
|
</div>
|
|
969
590
|
</PopoverContent>
|
|
970
591
|
</Popover>
|
|
592
|
+
)
|
|
593
|
+
}
|
|
971
594
|
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
<
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
595
|
+
return (
|
|
596
|
+
<div className="w-full p-8">
|
|
597
|
+
<div className="mx-auto max-w-3xl space-y-6">
|
|
598
|
+
<div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
|
599
|
+
{/* Controls panel */}
|
|
600
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary space-y-5 rounded-xl border p-5">
|
|
601
|
+
<p className="text-fm-primary font-fm-brand text-fm-sm leading-fm-sm font-semibold tracking-widest uppercase">
|
|
602
|
+
Track Actions
|
|
603
|
+
</p>
|
|
604
|
+
<p className="text-fm-secondary font-fm-text text-fm-sm leading-fm-sm">
|
|
605
|
+
Open any popover to interact with a live action panel.
|
|
606
|
+
</p>
|
|
607
|
+
<div className="border-fm-divider-secondary border-t pt-4" />
|
|
608
|
+
<div className="space-y-3">
|
|
609
|
+
<AddToPlaylist />
|
|
610
|
+
<ShareOptions />
|
|
611
|
+
<EQSettings />
|
|
988
612
|
</div>
|
|
613
|
+
</div>
|
|
989
614
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
<Label htmlFor="email" className="text-fm-primary text-sm">
|
|
1004
|
-
Email
|
|
1005
|
-
</Label>
|
|
1006
|
-
<Input
|
|
1007
|
-
id="email"
|
|
1008
|
-
defaultValue="john@example.com"
|
|
1009
|
-
className="border-fm-divider-secondary bg-fm-surface-secondary text-fm-primary placeholder:text-fm-tertiary"
|
|
1010
|
-
/>
|
|
1011
|
-
</div>
|
|
1012
|
-
<div>
|
|
1013
|
-
<Label htmlFor="role" className="text-fm-primary text-sm">
|
|
1014
|
-
Role
|
|
1015
|
-
</Label>
|
|
1016
|
-
<select
|
|
1017
|
-
id="role"
|
|
1018
|
-
className="border-fm-divider-secondary bg-fm-surface-secondary text-fm-primary focus-visible:ring-fm-divider-secondary w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:outline-none"
|
|
1019
|
-
>
|
|
1020
|
-
<option value="developer">Developer</option>
|
|
1021
|
-
<option value="designer">Designer</option>
|
|
1022
|
-
<option value="manager">Manager</option>
|
|
1023
|
-
</select>
|
|
615
|
+
{/* Preview stage */}
|
|
616
|
+
<div className="flex flex-col gap-3 lg:col-span-2">
|
|
617
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary flex-1 space-y-3 rounded-xl border p-5">
|
|
618
|
+
<p className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm">
|
|
619
|
+
Now playing
|
|
620
|
+
</p>
|
|
621
|
+
<div className="space-y-1">
|
|
622
|
+
<p className="text-fm-primary font-fm-brand text-fm-xl leading-fm-xl font-semibold">
|
|
623
|
+
Midnight Rain
|
|
624
|
+
</p>
|
|
625
|
+
<p className="text-fm-secondary font-fm-text text-fm-md leading-fm-md">
|
|
626
|
+
Taylor Swift · Midnights · 2022
|
|
627
|
+
</p>
|
|
1024
628
|
</div>
|
|
1025
|
-
<div>
|
|
1026
|
-
<
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
rows={3}
|
|
1032
|
-
className="border-fm-divider-secondary bg-fm-surface-secondary text-fm-primary placeholder:text-fm-tertiary focus-visible:ring-fm-divider-secondary w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:outline-none"
|
|
1033
|
-
defaultValue="Software developer passionate about creating great user experiences."
|
|
1034
|
-
/>
|
|
629
|
+
<div className="border-fm-divider-secondary border-t pt-3">
|
|
630
|
+
<p className="text-fm-tertiary font-fm-text text-fm-sm leading-fm-sm">
|
|
631
|
+
Use the action buttons on the left to open interactive
|
|
632
|
+
popovers: add this track to a playlist, share it, or adjust
|
|
633
|
+
the equalizer.
|
|
634
|
+
</p>
|
|
1035
635
|
</div>
|
|
1036
636
|
</div>
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
<Button size="sm">Save Changes</Button>
|
|
1042
|
-
</PopoverClose>
|
|
1043
|
-
<PopoverClose asChild>
|
|
1044
|
-
<Button size="sm" variant="outline">
|
|
1045
|
-
Cancel
|
|
1046
|
-
</Button>
|
|
1047
|
-
</PopoverClose>
|
|
637
|
+
<div className="border-fm-divider-secondary bg-fm-surface-secondary rounded-lg border px-4 py-3">
|
|
638
|
+
<code className="text-fm-secondary text-fm-md leading-fm-md font-(--font-fm-mono)">
|
|
639
|
+
{`<Popover><PopoverTrigger asChild>…</PopoverTrigger><PopoverContent>…<PopoverClose /></PopoverContent></Popover>`}
|
|
640
|
+
</code>
|
|
1048
641
|
</div>
|
|
1049
642
|
</div>
|
|
1050
|
-
</
|
|
1051
|
-
</
|
|
643
|
+
</div>
|
|
644
|
+
</div>
|
|
1052
645
|
</div>
|
|
1053
|
-
|
|
1054
|
-
),
|
|
1055
|
-
parameters: {
|
|
1056
|
-
docs: {
|
|
1057
|
-
description: {
|
|
1058
|
-
story:
|
|
1059
|
-
"Complete integration examples showing all popover components working together in realistic user interface scenarios.",
|
|
1060
|
-
},
|
|
1061
|
-
},
|
|
646
|
+
)
|
|
1062
647
|
},
|
|
1063
648
|
}
|