@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 ADDED
@@ -0,0 +1,7 @@
1
+ # @edux-design/popovers
2
+
3
+ ## 0.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Popovers
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,2 @@
1
+
2
+ export { }
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;
package/src/index.js ADDED
@@ -0,0 +1,9 @@
1
+ export {
2
+ PopoverProvider,
3
+ Popover,
4
+ PopoverTrigger,
5
+ PopoverAnchor,
6
+ PopoverPortal,
7
+ PopoverContent,
8
+ PopoverClose,
9
+ } from "./elements/Popover";