@edux-design/popovers 0.0.1
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/CHANGELOG.md +7 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +110 -0
- package/dist/index.mjs +68 -0
- package/package.json +37 -0
- package/src/demos/Popover.stories.jsx +199 -0
- package/src/elements/Popover.jsx +165 -0
- package/src/index.js +9 -0
package/CHANGELOG.md
ADDED
package/dist/index.d.mts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/index.js
|
|
30
|
+
var index_exports = {};
|
|
31
|
+
__export(index_exports, {
|
|
32
|
+
Popover: () => Popover,
|
|
33
|
+
PopoverAnchor: () => PopoverAnchor,
|
|
34
|
+
PopoverClose: () => PopoverClose,
|
|
35
|
+
PopoverContent: () => PopoverContent,
|
|
36
|
+
PopoverPortal: () => PopoverPortal,
|
|
37
|
+
PopoverProvider: () => PopoverProvider,
|
|
38
|
+
PopoverTrigger: () => PopoverTrigger
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(index_exports);
|
|
41
|
+
|
|
42
|
+
// src/elements/Popover.jsx
|
|
43
|
+
var import_react = __toESM(require("react"));
|
|
44
|
+
var PopoverPrimitive = __toESM(require("@radix-ui/react-popover"));
|
|
45
|
+
var import_utils = require("@edux-design/utils");
|
|
46
|
+
var PopoverProvider = PopoverPrimitive.Provider;
|
|
47
|
+
var Popover = PopoverPrimitive.Root;
|
|
48
|
+
var PopoverTrigger = PopoverPrimitive.Trigger;
|
|
49
|
+
var PopoverAnchor = PopoverPrimitive.Anchor;
|
|
50
|
+
var PopoverPortal = PopoverPrimitive.Portal;
|
|
51
|
+
var PopoverContent = (0, import_react.forwardRef)(
|
|
52
|
+
({
|
|
53
|
+
children,
|
|
54
|
+
className,
|
|
55
|
+
style,
|
|
56
|
+
side = "bottom",
|
|
57
|
+
sideOffset = 8,
|
|
58
|
+
align = "center",
|
|
59
|
+
alignOffset = 0,
|
|
60
|
+
avoidCollisions = true,
|
|
61
|
+
forceMount = false,
|
|
62
|
+
contentProps = {},
|
|
63
|
+
...restProps
|
|
64
|
+
}, ref) => {
|
|
65
|
+
const base = "bg-fg-base text-fg-invert text-sm font-normal rounded-xl shadow-lg px-12 py-8 animate-fade-in";
|
|
66
|
+
const positioning = {
|
|
67
|
+
top: "translate-y-[-4px]",
|
|
68
|
+
right: "translate-x-[4px]",
|
|
69
|
+
bottom: "translate-y-[4px]",
|
|
70
|
+
left: "translate-x-[-4px]"
|
|
71
|
+
}[side];
|
|
72
|
+
return /* @__PURE__ */ import_react.default.createElement(PopoverPortal, null, /* @__PURE__ */ import_react.default.createElement(
|
|
73
|
+
PopoverPrimitive.Content,
|
|
74
|
+
{
|
|
75
|
+
ref,
|
|
76
|
+
side,
|
|
77
|
+
sideOffset,
|
|
78
|
+
align,
|
|
79
|
+
alignOffset,
|
|
80
|
+
avoidCollisions,
|
|
81
|
+
forceMount,
|
|
82
|
+
className: (0, import_utils.cx)(base, positioning, className, "relative"),
|
|
83
|
+
style,
|
|
84
|
+
...contentProps,
|
|
85
|
+
...restProps
|
|
86
|
+
},
|
|
87
|
+
children,
|
|
88
|
+
/* @__PURE__ */ import_react.default.createElement(
|
|
89
|
+
PopoverPrimitive.Arrow,
|
|
90
|
+
{
|
|
91
|
+
className: "fill-fg-base",
|
|
92
|
+
width: 12,
|
|
93
|
+
height: 8
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
));
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
PopoverContent.displayName = "PopoverContent";
|
|
100
|
+
var PopoverClose = PopoverPrimitive.Close;
|
|
101
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
102
|
+
0 && (module.exports = {
|
|
103
|
+
Popover,
|
|
104
|
+
PopoverAnchor,
|
|
105
|
+
PopoverClose,
|
|
106
|
+
PopoverContent,
|
|
107
|
+
PopoverPortal,
|
|
108
|
+
PopoverProvider,
|
|
109
|
+
PopoverTrigger
|
|
110
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// src/elements/Popover.jsx
|
|
2
|
+
import React, { forwardRef } from "react";
|
|
3
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
4
|
+
import { cx } from "@edux-design/utils";
|
|
5
|
+
var PopoverProvider = PopoverPrimitive.Provider;
|
|
6
|
+
var Popover = PopoverPrimitive.Root;
|
|
7
|
+
var PopoverTrigger = PopoverPrimitive.Trigger;
|
|
8
|
+
var PopoverAnchor = PopoverPrimitive.Anchor;
|
|
9
|
+
var PopoverPortal = PopoverPrimitive.Portal;
|
|
10
|
+
var PopoverContent = forwardRef(
|
|
11
|
+
({
|
|
12
|
+
children,
|
|
13
|
+
className,
|
|
14
|
+
style,
|
|
15
|
+
side = "bottom",
|
|
16
|
+
sideOffset = 8,
|
|
17
|
+
align = "center",
|
|
18
|
+
alignOffset = 0,
|
|
19
|
+
avoidCollisions = true,
|
|
20
|
+
forceMount = false,
|
|
21
|
+
contentProps = {},
|
|
22
|
+
...restProps
|
|
23
|
+
}, ref) => {
|
|
24
|
+
const base = "bg-fg-base text-fg-invert text-sm font-normal rounded-xl shadow-lg px-12 py-8 animate-fade-in";
|
|
25
|
+
const positioning = {
|
|
26
|
+
top: "translate-y-[-4px]",
|
|
27
|
+
right: "translate-x-[4px]",
|
|
28
|
+
bottom: "translate-y-[4px]",
|
|
29
|
+
left: "translate-x-[-4px]"
|
|
30
|
+
}[side];
|
|
31
|
+
return /* @__PURE__ */ React.createElement(PopoverPortal, null, /* @__PURE__ */ React.createElement(
|
|
32
|
+
PopoverPrimitive.Content,
|
|
33
|
+
{
|
|
34
|
+
ref,
|
|
35
|
+
side,
|
|
36
|
+
sideOffset,
|
|
37
|
+
align,
|
|
38
|
+
alignOffset,
|
|
39
|
+
avoidCollisions,
|
|
40
|
+
forceMount,
|
|
41
|
+
className: cx(base, positioning, className, "relative"),
|
|
42
|
+
style,
|
|
43
|
+
...contentProps,
|
|
44
|
+
...restProps
|
|
45
|
+
},
|
|
46
|
+
children,
|
|
47
|
+
/* @__PURE__ */ React.createElement(
|
|
48
|
+
PopoverPrimitive.Arrow,
|
|
49
|
+
{
|
|
50
|
+
className: "fill-fg-base",
|
|
51
|
+
width: 12,
|
|
52
|
+
height: 8
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
));
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
PopoverContent.displayName = "PopoverContent";
|
|
59
|
+
var PopoverClose = PopoverPrimitive.Close;
|
|
60
|
+
export {
|
|
61
|
+
Popover,
|
|
62
|
+
PopoverAnchor,
|
|
63
|
+
PopoverClose,
|
|
64
|
+
PopoverContent,
|
|
65
|
+
PopoverPortal,
|
|
66
|
+
PopoverProvider,
|
|
67
|
+
PopoverTrigger
|
|
68
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@edux-design/popovers",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"sideEffects": [
|
|
6
|
+
"**/*.css"
|
|
7
|
+
],
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"lint": "eslint . --max-warnings 0",
|
|
18
|
+
"build": "tsup src/index.js --format esm,cjs --dts",
|
|
19
|
+
"dev": "tsup src/index.js --watch --format esm,cjs --dts",
|
|
20
|
+
"generate:component": "turbo gen react-component",
|
|
21
|
+
"check-types": "tsc --noEmit"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"typescript": "^5.9.2",
|
|
25
|
+
"tailwindcss": "^4.1.12",
|
|
26
|
+
"postcss": "^8.5.6",
|
|
27
|
+
"tsup": "^8.5.0",
|
|
28
|
+
"@tailwindcss/cli": "^4.1.12",
|
|
29
|
+
"@tailwindcss/postcss": "^4.1.12"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"react": "^19.1.0",
|
|
33
|
+
"react-dom": "^19.1.0",
|
|
34
|
+
"@radix-ui/react-popover": "1.1.15",
|
|
35
|
+
"@edux-design/utils": "*"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Popover,
|
|
4
|
+
PopoverTrigger,
|
|
5
|
+
PopoverContent,
|
|
6
|
+
PopoverClose,
|
|
7
|
+
} from "./../index";
|
|
8
|
+
import { Button } from "@edux-design/buttons";
|
|
9
|
+
import { cx } from "@edux-design/utils";
|
|
10
|
+
|
|
11
|
+
const meta = {
|
|
12
|
+
title: "Components/Popover",
|
|
13
|
+
component: Popover,
|
|
14
|
+
parameters: {
|
|
15
|
+
layout: "centered",
|
|
16
|
+
docs: {
|
|
17
|
+
description: {
|
|
18
|
+
component: `
|
|
19
|
+
Radix-based **Popover** component.
|
|
20
|
+
|
|
21
|
+
Use for contextual overlays triggered by a click, such as menus, mini-editors, or form helpers.
|
|
22
|
+
|
|
23
|
+
Built with [@radix-ui/react-popover](https://www.radix-ui.com/primitives/docs/components/popover).
|
|
24
|
+
`,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
argTypes: {
|
|
29
|
+
side: {
|
|
30
|
+
control: "select",
|
|
31
|
+
options: ["top", "right", "bottom", "left"],
|
|
32
|
+
description: "Placement of the popover relative to its trigger.",
|
|
33
|
+
table: { defaultValue: { summary: "bottom" } },
|
|
34
|
+
},
|
|
35
|
+
align: {
|
|
36
|
+
control: "select",
|
|
37
|
+
options: ["start", "center", "end"],
|
|
38
|
+
description: "Alignment of the popover along the cross axis.",
|
|
39
|
+
table: { defaultValue: { summary: "center" } },
|
|
40
|
+
},
|
|
41
|
+
sideOffset: {
|
|
42
|
+
control: { type: "number", min: 0, step: 1 },
|
|
43
|
+
description: "Gap between the trigger and popover.",
|
|
44
|
+
table: { defaultValue: { summary: 8 } },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
export default meta;
|
|
49
|
+
/**
|
|
50
|
+
* ───────────────────────────────────────────────
|
|
51
|
+
* 📍 Basic Popover
|
|
52
|
+
* ───────────────────────────────────────────────
|
|
53
|
+
*/
|
|
54
|
+
export const Basic = {
|
|
55
|
+
render: (args) => (
|
|
56
|
+
<Popover>
|
|
57
|
+
<PopoverTrigger asChild>
|
|
58
|
+
<Button variant="primary">Open Popover</Button>
|
|
59
|
+
</PopoverTrigger>
|
|
60
|
+
|
|
61
|
+
<PopoverContent {...args}>
|
|
62
|
+
<div className="space-y-4 w-[200px]">
|
|
63
|
+
<p>This is a simple popover content.</p>
|
|
64
|
+
<PopoverClose asChild>
|
|
65
|
+
<Button variant="secondary" size="sm">
|
|
66
|
+
Close
|
|
67
|
+
</Button>
|
|
68
|
+
</PopoverClose>
|
|
69
|
+
</div>
|
|
70
|
+
</PopoverContent>
|
|
71
|
+
</Popover>
|
|
72
|
+
),
|
|
73
|
+
args: {
|
|
74
|
+
side: "bottom",
|
|
75
|
+
align: "center",
|
|
76
|
+
sideOffset: 8,
|
|
77
|
+
},
|
|
78
|
+
parameters: {
|
|
79
|
+
docs: {
|
|
80
|
+
description: {
|
|
81
|
+
story: "A basic popover triggered by a button click.",
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* ───────────────────────────────────────────────
|
|
89
|
+
* 🎨 Custom Content
|
|
90
|
+
* ───────────────────────────────────────────────
|
|
91
|
+
*/
|
|
92
|
+
export const CustomContent = {
|
|
93
|
+
render: (args) => (
|
|
94
|
+
<Popover>
|
|
95
|
+
<PopoverTrigger asChild>
|
|
96
|
+
<Button variant="primary">Show Custom Popover</Button>
|
|
97
|
+
</PopoverTrigger>
|
|
98
|
+
<PopoverContent
|
|
99
|
+
{...args}
|
|
100
|
+
className={cx(
|
|
101
|
+
"rounded-2xl border border-fg-subtle bg-fg-base p-16 w-[240px]",
|
|
102
|
+
"shadow-lg"
|
|
103
|
+
)}
|
|
104
|
+
>
|
|
105
|
+
<h3 className="font-semibold text-base mb-4">Popover title</h3>
|
|
106
|
+
<p className="text-sm text-fg-subtle">
|
|
107
|
+
You can render **anything** inside here — forms, menus, etc.
|
|
108
|
+
</p>
|
|
109
|
+
<div className="mt-8 flex justify-end">
|
|
110
|
+
<PopoverClose asChild>
|
|
111
|
+
<Button variant="bare" size="sm">
|
|
112
|
+
Dismiss
|
|
113
|
+
</Button>
|
|
114
|
+
</PopoverClose>
|
|
115
|
+
</div>
|
|
116
|
+
</PopoverContent>
|
|
117
|
+
</Popover>
|
|
118
|
+
),
|
|
119
|
+
args: {
|
|
120
|
+
side: "top",
|
|
121
|
+
},
|
|
122
|
+
parameters: {
|
|
123
|
+
docs: {
|
|
124
|
+
description: {
|
|
125
|
+
story:
|
|
126
|
+
"Demonstrates custom content styling, with title, text, and custom buttons.",
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* ───────────────────────────────────────────────
|
|
134
|
+
* ⚙️ Controlled Popover
|
|
135
|
+
* ───────────────────────────────────────────────
|
|
136
|
+
*/
|
|
137
|
+
export const Controlled = {
|
|
138
|
+
render: (args) => {
|
|
139
|
+
const [open, setOpen] = useState(false);
|
|
140
|
+
return (
|
|
141
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
142
|
+
<PopoverTrigger asChild>
|
|
143
|
+
<Button variant="primary">
|
|
144
|
+
{open ? "Close Popover" : "Open Controlled Popover"}
|
|
145
|
+
</Button>
|
|
146
|
+
</PopoverTrigger>
|
|
147
|
+
<PopoverContent {...args}>
|
|
148
|
+
<div className="w-[220px] text-sm">
|
|
149
|
+
<p>This popover is **controlled** externally using React state.</p>
|
|
150
|
+
<div className="mt-6 flex justify-end">
|
|
151
|
+
<Button variant="bare" size="sm" onClick={() => setOpen(false)}>
|
|
152
|
+
Close
|
|
153
|
+
</Button>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</PopoverContent>
|
|
157
|
+
</Popover>
|
|
158
|
+
);
|
|
159
|
+
},
|
|
160
|
+
parameters: {
|
|
161
|
+
docs: {
|
|
162
|
+
description: {
|
|
163
|
+
story:
|
|
164
|
+
"Shows how to control the popover’s open state externally via React state.",
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* ───────────────────────────────────────────────
|
|
172
|
+
* 📐 All Sides Example
|
|
173
|
+
* ───────────────────────────────────────────────
|
|
174
|
+
*/
|
|
175
|
+
export const Sides = {
|
|
176
|
+
render: () => (
|
|
177
|
+
<div className="grid grid-cols-2 gap-16">
|
|
178
|
+
{["top", "right", "bottom", "left"].map((side) => (
|
|
179
|
+
<Popover key={side}>
|
|
180
|
+
<PopoverTrigger asChild>
|
|
181
|
+
<Button variant="secondary">Side: {side}</Button>
|
|
182
|
+
</PopoverTrigger>
|
|
183
|
+
<PopoverContent side={side}>
|
|
184
|
+
<p className="w-[140px] text-center">
|
|
185
|
+
Popover on <strong>{side}</strong>
|
|
186
|
+
</p>
|
|
187
|
+
</PopoverContent>
|
|
188
|
+
</Popover>
|
|
189
|
+
))}
|
|
190
|
+
</div>
|
|
191
|
+
),
|
|
192
|
+
parameters: {
|
|
193
|
+
docs: {
|
|
194
|
+
description: {
|
|
195
|
+
story: "Showcases popovers appearing on all sides of the trigger.",
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import React, { forwardRef } from "react";
|
|
2
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
3
|
+
import { cx } from "@edux-design/utils";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* PopoverProvider
|
|
7
|
+
*
|
|
8
|
+
* Optional provider to wrap your app (if you want to set shared defaults / context).
|
|
9
|
+
* It delegates to Radix’s Provider.
|
|
10
|
+
*
|
|
11
|
+
* @component
|
|
12
|
+
* @example
|
|
13
|
+
* ```jsx
|
|
14
|
+
* <PopoverProvider>
|
|
15
|
+
* <YourUI />
|
|
16
|
+
* </PopoverProvider>
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export const PopoverProvider = PopoverPrimitive.Provider;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Root Popover component.
|
|
23
|
+
*
|
|
24
|
+
* Wraps a `PopoverTrigger` (or `Popover.Anchor + Trigger`) and a `PopoverContent`.
|
|
25
|
+
* Supports both controlled and uncontrolled modes.
|
|
26
|
+
*
|
|
27
|
+
* @component
|
|
28
|
+
* @param {Object} props
|
|
29
|
+
* @param {boolean} [props.defaultOpen] – whether popover is open by default (uncontrolled mode)
|
|
30
|
+
* @param {boolean} [props.open] – controlled open state
|
|
31
|
+
* @param {(open: boolean) => void} [props.onOpenChange] – change handler for controlled mode
|
|
32
|
+
* @param {boolean} [props.modal=false] – whether to render modal behavior (blocking outside interactions) :contentReference[oaicite:1]{index=1}
|
|
33
|
+
* @param {React.ReactNode} props.children
|
|
34
|
+
* @returns JSX.Element
|
|
35
|
+
*/
|
|
36
|
+
export const Popover = PopoverPrimitive.Root;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* PopoverTrigger
|
|
40
|
+
*
|
|
41
|
+
* The interactive element that toggles opening/closing the popover.
|
|
42
|
+
*
|
|
43
|
+
* @component
|
|
44
|
+
* @param {React.ComponentProps<typeof PopoverPrimitive.Trigger>} props
|
|
45
|
+
* @example
|
|
46
|
+
* ```jsx
|
|
47
|
+
* <PopoverTrigger asChild>
|
|
48
|
+
* <button>Open Popover</button>
|
|
49
|
+
* </PopoverTrigger>
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export const PopoverTrigger = PopoverPrimitive.Trigger;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* PopoverAnchor
|
|
56
|
+
*
|
|
57
|
+
* Optional anchor component: if you want the PopoverContent positioned against an element
|
|
58
|
+
* other than the trigger. (Matches Radix’s `Popover.Anchor`) :contentReference[oaicite:2]{index=2}
|
|
59
|
+
*
|
|
60
|
+
* @component
|
|
61
|
+
* @param {React.ComponentProps<typeof PopoverPrimitive.Anchor>} props
|
|
62
|
+
*/
|
|
63
|
+
export const PopoverAnchor = PopoverPrimitive.Anchor;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* PopoverPortal
|
|
67
|
+
*
|
|
68
|
+
* Portal wrapper. You can use this if you need to override portal container or force mount.
|
|
69
|
+
*
|
|
70
|
+
* @component
|
|
71
|
+
* @param {React.ComponentProps<typeof PopoverPrimitive.Portal>} props
|
|
72
|
+
*/
|
|
73
|
+
export const PopoverPortal = PopoverPrimitive.Portal;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Props for PopoverContent component.
|
|
77
|
+
*
|
|
78
|
+
* @typedef {Object} PopoverContentProps
|
|
79
|
+
* @property {React.ReactNode} children – content inside the popover
|
|
80
|
+
* @property {"top"|"right"|"bottom"|"left"} [side="bottom"] – preferred side for popover placement
|
|
81
|
+
* @property {number} [sideOffset=8] – gap between trigger (or anchor) and the popover
|
|
82
|
+
* @property {"start"|"center"|"end"} [align="center"] – alignment along the cross-axis
|
|
83
|
+
* @property {number} [alignOffset=0] – offset for the alignment axis
|
|
84
|
+
* @property {boolean} [avoidCollisions=true] – whether to auto-adjust position to avoid clipping :contentReference[oaicite:3]{index=3}
|
|
85
|
+
* @property {boolean} [forceMount=false] – whether to always mount the content into the DOM
|
|
86
|
+
* @property {string} [className] – additional CSS / Tailwind classes
|
|
87
|
+
* @property {Object} [style] – inline style overrides
|
|
88
|
+
* @property {React.ComponentProps<typeof PopoverPrimitive.Content>} [contentProps] – any extra props forwarded to Radix’s Content
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* PopoverContent
|
|
93
|
+
*
|
|
94
|
+
* The popover surface that appears. Renders in a Portal by default.
|
|
95
|
+
* You can override animation, styling, arrow, etc.
|
|
96
|
+
*
|
|
97
|
+
* @component
|
|
98
|
+
* @param {PopoverContentProps & React.RefAttributes<HTMLDivElement>} props
|
|
99
|
+
*/
|
|
100
|
+
export const PopoverContent = forwardRef(
|
|
101
|
+
(
|
|
102
|
+
{
|
|
103
|
+
children,
|
|
104
|
+
className,
|
|
105
|
+
style,
|
|
106
|
+
side = "bottom",
|
|
107
|
+
sideOffset = 8,
|
|
108
|
+
align = "center",
|
|
109
|
+
alignOffset = 0,
|
|
110
|
+
avoidCollisions = true,
|
|
111
|
+
forceMount = false,
|
|
112
|
+
contentProps = {},
|
|
113
|
+
...restProps
|
|
114
|
+
},
|
|
115
|
+
ref
|
|
116
|
+
) => {
|
|
117
|
+
// Base styling; consuming apps can override via className or wrapping
|
|
118
|
+
const base =
|
|
119
|
+
"bg-fg-base text-fg-invert text-sm font-normal rounded-xl shadow-lg px-12 py-8 animate-fade-in";
|
|
120
|
+
// A transform to “nudge” content initially (you can enhance animation later)
|
|
121
|
+
const positioning = {
|
|
122
|
+
top: "translate-y-[-4px]",
|
|
123
|
+
right: "translate-x-[4px]",
|
|
124
|
+
bottom: "translate-y-[4px]",
|
|
125
|
+
left: "translate-x-[-4px]",
|
|
126
|
+
}[side];
|
|
127
|
+
|
|
128
|
+
return (
|
|
129
|
+
<PopoverPortal>
|
|
130
|
+
<PopoverPrimitive.Content
|
|
131
|
+
ref={ref}
|
|
132
|
+
side={side}
|
|
133
|
+
sideOffset={sideOffset}
|
|
134
|
+
align={align}
|
|
135
|
+
alignOffset={alignOffset}
|
|
136
|
+
avoidCollisions={avoidCollisions}
|
|
137
|
+
forceMount={forceMount}
|
|
138
|
+
className={cx(base, positioning, className, "relative")}
|
|
139
|
+
style={style}
|
|
140
|
+
{...contentProps}
|
|
141
|
+
{...restProps}
|
|
142
|
+
>
|
|
143
|
+
{children}
|
|
144
|
+
<PopoverPrimitive.Arrow
|
|
145
|
+
className="fill-fg-base"
|
|
146
|
+
width={12}
|
|
147
|
+
height={8}
|
|
148
|
+
/>
|
|
149
|
+
</PopoverPrimitive.Content>
|
|
150
|
+
</PopoverPortal>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
PopoverContent.displayName = "PopoverContent";
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* PopoverClose
|
|
159
|
+
*
|
|
160
|
+
* A button or element inside the PopoverContent that triggers closing action.
|
|
161
|
+
*
|
|
162
|
+
* @component
|
|
163
|
+
* @param {React.ComponentProps<typeof PopoverPrimitive.Close>} props
|
|
164
|
+
*/
|
|
165
|
+
export const PopoverClose = PopoverPrimitive.Close;
|