@edux-design/popovers 1.0.6 → 1.1.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 +17 -0
- package/README.md +14 -0
- package/dist/index.d.mts +129 -1
- package/dist/index.d.ts +129 -1
- package/dist/index.js +166 -20
- package/dist/index.mjs +165 -20
- package/docs/confirmation.md +118 -0
- package/package.json +10 -16
- package/src/demos/Popover.stories.jsx +0 -248
- package/src/elements/Popover.jsx +0 -156
- package/src/elements/Popover.test.jsx +0 -63
- package/src/index.js +0 -8
package/src/elements/Popover.jsx
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import React, { forwardRef } from "react";
|
|
2
|
-
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
3
|
-
import { cx } from "@edux-design/utils";
|
|
4
|
-
|
|
5
|
-
const POPOVER_Z_INDEX = 2147483646;
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Root Popover component.
|
|
9
|
-
*
|
|
10
|
-
* Wraps a `PopoverTrigger` (or `Popover.Anchor + Trigger`) and a `PopoverContent`.
|
|
11
|
-
* Supports both controlled and uncontrolled modes.
|
|
12
|
-
*
|
|
13
|
-
* @component
|
|
14
|
-
* @param {Object} props
|
|
15
|
-
* @param {boolean} [props.defaultOpen] – whether popover is open by default (uncontrolled mode)
|
|
16
|
-
* @param {boolean} [props.open] – controlled open state
|
|
17
|
-
* @param {(open: boolean) => void} [props.onOpenChange] – change handler for controlled mode
|
|
18
|
-
* @param {boolean} [props.modal=false] – whether to render modal behavior (blocking outside interactions) :contentReference[oaicite:1]{index=1}
|
|
19
|
-
* @param {React.ReactNode} props.children
|
|
20
|
-
* @returns JSX.Element
|
|
21
|
-
*/
|
|
22
|
-
export const Popover = PopoverPrimitive.Root;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* PopoverTrigger
|
|
26
|
-
*
|
|
27
|
-
* The interactive element that toggles opening/closing the popover.
|
|
28
|
-
*
|
|
29
|
-
* @component
|
|
30
|
-
* @param {React.ComponentProps<typeof PopoverPrimitive.Trigger>} props
|
|
31
|
-
* @example
|
|
32
|
-
* ```jsx
|
|
33
|
-
* <PopoverTrigger asChild>
|
|
34
|
-
* <button>Open Popover</button>
|
|
35
|
-
* </PopoverTrigger>
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export const PopoverTrigger = PopoverPrimitive.Trigger;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* PopoverAnchor
|
|
42
|
-
*
|
|
43
|
-
* Optional anchor component: if you want the PopoverContent positioned against an element
|
|
44
|
-
* other than the trigger. (Matches Radix’s `Popover.Anchor`) :contentReference[oaicite:2]{index=2}
|
|
45
|
-
*
|
|
46
|
-
* @component
|
|
47
|
-
* @param {React.ComponentProps<typeof PopoverPrimitive.Anchor>} props
|
|
48
|
-
*/
|
|
49
|
-
export const PopoverAnchor = PopoverPrimitive.Anchor;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* PopoverPortal
|
|
53
|
-
*
|
|
54
|
-
* Portal wrapper. You can use this if you need to override portal container or force mount.
|
|
55
|
-
*
|
|
56
|
-
* @component
|
|
57
|
-
* @param {React.ComponentProps<typeof PopoverPrimitive.Portal>} props
|
|
58
|
-
*/
|
|
59
|
-
export const PopoverPortal = PopoverPrimitive.Portal;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Props for PopoverContent component.
|
|
63
|
-
*
|
|
64
|
-
* @typedef {Object} PopoverContentProps
|
|
65
|
-
* @property {React.ReactNode} children – content inside the popover
|
|
66
|
-
* @property {"top"|"right"|"bottom"|"left"} [side="bottom"] – preferred side for popover placement
|
|
67
|
-
* @property {number} [sideOffset=8] – gap between trigger (or anchor) and the popover
|
|
68
|
-
* @property {"start"|"center"|"end"} [align="center"] – alignment along the cross-axis
|
|
69
|
-
* @property {number} [alignOffset=0] – offset for the alignment axis
|
|
70
|
-
* @property {boolean} [avoidCollisions=true] – whether to auto-adjust position to avoid clipping :contentReference[oaicite:3]{index=3}
|
|
71
|
-
* @property {boolean} [forceMount=false] – whether to always mount the content into the DOM
|
|
72
|
-
* @property {string} [className] – additional CSS / Tailwind classes
|
|
73
|
-
* @property {Object} [style] – inline style overrides
|
|
74
|
-
* @property {React.ComponentProps<typeof PopoverPrimitive.Content>} [contentProps] – any extra props forwarded to Radix’s Content
|
|
75
|
-
*/
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* PopoverContent
|
|
79
|
-
*
|
|
80
|
-
* The popover surface that appears. Renders in a Portal by default.
|
|
81
|
-
* You can override animation, styling, arrow, etc.
|
|
82
|
-
*
|
|
83
|
-
* @component
|
|
84
|
-
* @param {PopoverContentProps & React.RefAttributes<HTMLDivElement>} props
|
|
85
|
-
*/
|
|
86
|
-
export const PopoverContent = forwardRef(
|
|
87
|
-
(
|
|
88
|
-
{
|
|
89
|
-
children,
|
|
90
|
-
className,
|
|
91
|
-
style,
|
|
92
|
-
container,
|
|
93
|
-
portalProps = {},
|
|
94
|
-
side = "bottom",
|
|
95
|
-
sideOffset = 8,
|
|
96
|
-
align = "center",
|
|
97
|
-
alignOffset = 0,
|
|
98
|
-
avoidCollisions = true,
|
|
99
|
-
forceMount = false,
|
|
100
|
-
showArrow = false,
|
|
101
|
-
contentProps = {},
|
|
102
|
-
...restProps
|
|
103
|
-
},
|
|
104
|
-
ref
|
|
105
|
-
) => {
|
|
106
|
-
// Base styling; consuming apps can override via className or wrapping
|
|
107
|
-
const base =
|
|
108
|
-
"bg-fg-base text-fg-invert text-sm font-normal rounded-xl shadow-lg px-12 py-8 animate-fade-in";
|
|
109
|
-
// A transform to “nudge” content initially
|
|
110
|
-
const positioning = {
|
|
111
|
-
top: "translate-y-[-4px]",
|
|
112
|
-
right: "translate-x-[4px]",
|
|
113
|
-
bottom: "translate-y-[4px]",
|
|
114
|
-
left: "translate-x-[-4px]",
|
|
115
|
-
}[side];
|
|
116
|
-
|
|
117
|
-
return (
|
|
118
|
-
<PopoverPortal container={container} {...portalProps}>
|
|
119
|
-
<PopoverPrimitive.Content
|
|
120
|
-
ref={ref}
|
|
121
|
-
side={side}
|
|
122
|
-
sideOffset={sideOffset}
|
|
123
|
-
align={align}
|
|
124
|
-
alignOffset={alignOffset}
|
|
125
|
-
avoidCollisions={avoidCollisions}
|
|
126
|
-
forceMount={forceMount}
|
|
127
|
-
className={cx(positioning, className, "relative")}
|
|
128
|
-
style={{ zIndex: POPOVER_Z_INDEX, ...style }}
|
|
129
|
-
{...contentProps}
|
|
130
|
-
{...restProps}
|
|
131
|
-
>
|
|
132
|
-
{children}
|
|
133
|
-
{showArrow && (
|
|
134
|
-
<PopoverPrimitive.Arrow
|
|
135
|
-
className="fill-fg-base"
|
|
136
|
-
width={12}
|
|
137
|
-
height={8}
|
|
138
|
-
/>
|
|
139
|
-
)}
|
|
140
|
-
</PopoverPrimitive.Content>
|
|
141
|
-
</PopoverPortal>
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
);
|
|
145
|
-
|
|
146
|
-
PopoverContent.displayName = "PopoverContent";
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* PopoverClose
|
|
150
|
-
*
|
|
151
|
-
* A button or element inside the PopoverContent that triggers closing action.
|
|
152
|
-
*
|
|
153
|
-
* @component
|
|
154
|
-
* @param {React.ComponentProps<typeof PopoverPrimitive.Close>} props
|
|
155
|
-
*/
|
|
156
|
-
export const PopoverClose = PopoverPrimitive.Close;
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { render, screen } from "@testing-library/react";
|
|
3
|
-
import {
|
|
4
|
-
Popover,
|
|
5
|
-
PopoverTrigger,
|
|
6
|
-
PopoverContent,
|
|
7
|
-
PopoverClose,
|
|
8
|
-
} from "./Popover";
|
|
9
|
-
|
|
10
|
-
vi.mock("@radix-ui/react-popover", () => {
|
|
11
|
-
const Passthrough = ({ children, ...props }) => (
|
|
12
|
-
<div {...props}>{children}</div>
|
|
13
|
-
);
|
|
14
|
-
const Buttonish = ({ children, ...props }) => (
|
|
15
|
-
<button type="button" {...props}>
|
|
16
|
-
{children}
|
|
17
|
-
</button>
|
|
18
|
-
);
|
|
19
|
-
const Content = React.forwardRef(
|
|
20
|
-
({ sideOffset, alignOffset, avoidCollisions, forceMount, ...props }, ref) => (
|
|
21
|
-
<div ref={ref} data-testid="radix-content" {...props} />
|
|
22
|
-
)
|
|
23
|
-
);
|
|
24
|
-
Content.displayName = "RadixContent";
|
|
25
|
-
const Arrow = (props) => <div data-testid="popover-arrow" {...props} />;
|
|
26
|
-
|
|
27
|
-
return {
|
|
28
|
-
Provider: Passthrough,
|
|
29
|
-
Root: Passthrough,
|
|
30
|
-
Trigger: Buttonish,
|
|
31
|
-
Anchor: Passthrough,
|
|
32
|
-
Portal: Passthrough,
|
|
33
|
-
Content,
|
|
34
|
-
Close: Buttonish,
|
|
35
|
-
Arrow,
|
|
36
|
-
};
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe("PopoverContent", () => {
|
|
40
|
-
it("merges Tailwind classes and optionally renders arrow", () => {
|
|
41
|
-
render(
|
|
42
|
-
<PopoverContent className="custom" showArrow side="top" data-testid="content">
|
|
43
|
-
Body
|
|
44
|
-
</PopoverContent>
|
|
45
|
-
);
|
|
46
|
-
const content = screen.getByTestId("content");
|
|
47
|
-
expect(content).toHaveClass("custom");
|
|
48
|
-
expect(content).toHaveStyle({ zIndex: "2147483646" });
|
|
49
|
-
expect(screen.getByTestId("popover-arrow")).toBeInTheDocument();
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("plays nicely with Popover + Trigger exports", () => {
|
|
53
|
-
render(
|
|
54
|
-
<Popover>
|
|
55
|
-
<PopoverTrigger>Open</PopoverTrigger>
|
|
56
|
-
<PopoverContent>Panel</PopoverContent>
|
|
57
|
-
<PopoverClose>Close</PopoverClose>
|
|
58
|
-
</Popover>
|
|
59
|
-
);
|
|
60
|
-
expect(screen.getByText("Open")).toBeInTheDocument();
|
|
61
|
-
expect(screen.getAllByText(/close|panel/i).length).toBeGreaterThan(0);
|
|
62
|
-
});
|
|
63
|
-
});
|