@monolith-forensics/monolith-ui 1.3.112-dev.2 → 1.3.113

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.
@@ -0,0 +1,23 @@
1
+ import { useFloating, useInteractions } from "@floating-ui/react";
2
+ import { PopoverTransitionProps } from "./Popover.types";
3
+ export interface PopoverContextValue {
4
+ opened: boolean;
5
+ refs: ReturnType<typeof useFloating>["refs"];
6
+ context: ReturnType<typeof useFloating>["context"];
7
+ floatingStyles: ReturnType<typeof useFloating>["floatingStyles"];
8
+ getReferenceProps: ReturnType<typeof useInteractions>["getReferenceProps"];
9
+ getFloatingProps: ReturnType<typeof useInteractions>["getFloatingProps"];
10
+ withArrow: boolean;
11
+ arrowSize: number;
12
+ arrowRadius: number;
13
+ arrowRef: React.MutableRefObject<HTMLDivElement | null>;
14
+ withinPortal: boolean;
15
+ trapFocus: boolean;
16
+ returnFocus: boolean;
17
+ keepMounted: boolean;
18
+ zIndex: number;
19
+ dropdownId: string;
20
+ transitionProps: PopoverTransitionProps;
21
+ }
22
+ export declare const PopoverContext: import("react").Context<PopoverContextValue | null>;
23
+ export declare const usePopoverContext: () => PopoverContextValue;
@@ -0,0 +1,9 @@
1
+ import { createContext, useContext } from "react";
2
+ export const PopoverContext = createContext(null);
3
+ export const usePopoverContext = () => {
4
+ const context = useContext(PopoverContext);
5
+ if (!context) {
6
+ throw new Error("Popover components must be used within Popover");
7
+ }
8
+ return context;
9
+ };
@@ -0,0 +1,7 @@
1
+ import { PopoverDropdownProps, PopoverProps, PopoverTargetProps } from "./Popover.types";
2
+ type PopoverCompound = React.FC<PopoverProps> & {
3
+ Target: React.FC<PopoverTargetProps>;
4
+ Dropdown: React.FC<PopoverDropdownProps>;
5
+ };
6
+ export declare const Popover: PopoverCompound;
7
+ export {};
@@ -0,0 +1,124 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useUncontrolled } from "@mantine/hooks";
3
+ import { arrow, autoUpdate, flip, FloatingDelayGroup, offset, shift, size, useClick, useDismiss, useFloating, useFocus, useHover, useInteractions, useRole, } from "@floating-ui/react";
4
+ import { useId, useMemo, useRef } from "react";
5
+ import { PopoverContext } from "./Popover.context";
6
+ import { PopoverTarget } from "./PopoverTarget";
7
+ import { PopoverDropdown } from "./PopoverDropdown";
8
+ const PopoverRoot = ({ children, opened, defaultOpened = false, onChange, trigger = "click", disabled = false, position = "bottom", offset: offsetValue = 8, openDelay = 75, closeDelay = 100, closeOnClickOutside = true, closeOnEscape = true, withinPortal = true, trapFocus = false, returnFocus = true, keepMounted = false, withArrow = false, arrowSize = 8, arrowRadius = 2, zIndex = 1500, role = "dialog", width, matchTargetWidth = false, shiftPadding = 8, flipPadding = 8, withDelayGroup = false, delayGroupTimeoutMs = 250, transitionProps = {}, }) => {
9
+ const [_opened, setOpened] = useUncontrolled({
10
+ value: opened,
11
+ defaultValue: defaultOpened,
12
+ finalValue: false,
13
+ onChange,
14
+ });
15
+ const arrowRef = useRef(null);
16
+ const dropdownId = useId();
17
+ const resolvedArrowSize = Math.max(arrowSize, 6);
18
+ const { refs, floatingStyles, context } = useFloating({
19
+ open: _opened,
20
+ onOpenChange: (nextOpen) => {
21
+ if (!disabled) {
22
+ setOpened(nextOpen);
23
+ }
24
+ },
25
+ placement: position,
26
+ middleware: [
27
+ offset(offsetValue + (withArrow ? resolvedArrowSize / 2 : 0)),
28
+ flip({ padding: flipPadding }),
29
+ shift({ padding: shiftPadding }),
30
+ size({
31
+ apply({ rects, elements }) {
32
+ if (matchTargetWidth) {
33
+ elements.floating.style.width = `${rects.reference.width}px`;
34
+ }
35
+ if (width !== undefined) {
36
+ elements.floating.style.width =
37
+ typeof width === "number" ? `${width}px` : width;
38
+ }
39
+ },
40
+ }),
41
+ ...(withArrow
42
+ ? [
43
+ arrow({
44
+ element: arrowRef,
45
+ padding: 8,
46
+ }),
47
+ ]
48
+ : []),
49
+ ],
50
+ whileElementsMounted: autoUpdate,
51
+ });
52
+ const click = useClick(context, {
53
+ enabled: !disabled && trigger === "click",
54
+ event: "click",
55
+ toggle: true,
56
+ });
57
+ const hover = useHover(context, {
58
+ enabled: !disabled && trigger === "hover",
59
+ delay: { open: openDelay, close: closeDelay },
60
+ move: false,
61
+ });
62
+ const focus = useFocus(context, {
63
+ enabled: !disabled && trigger === "hover",
64
+ visibleOnly: true,
65
+ });
66
+ const dismiss = useDismiss(context, {
67
+ enabled: !disabled,
68
+ outsidePress: closeOnClickOutside,
69
+ escapeKey: closeOnEscape,
70
+ });
71
+ const roleInteraction = useRole(context, { role });
72
+ const { getReferenceProps, getFloatingProps } = useInteractions([
73
+ click,
74
+ hover,
75
+ focus,
76
+ dismiss,
77
+ roleInteraction,
78
+ ]);
79
+ const contextValue = useMemo(() => ({
80
+ opened: _opened,
81
+ refs,
82
+ context,
83
+ floatingStyles,
84
+ getReferenceProps,
85
+ getFloatingProps,
86
+ withArrow,
87
+ arrowSize,
88
+ arrowRadius,
89
+ arrowRef,
90
+ withinPortal,
91
+ trapFocus,
92
+ returnFocus,
93
+ keepMounted,
94
+ zIndex,
95
+ dropdownId,
96
+ transitionProps,
97
+ }), [
98
+ _opened,
99
+ refs,
100
+ context,
101
+ floatingStyles,
102
+ getReferenceProps,
103
+ getFloatingProps,
104
+ withArrow,
105
+ arrowSize,
106
+ arrowRadius,
107
+ withinPortal,
108
+ trapFocus,
109
+ returnFocus,
110
+ keepMounted,
111
+ zIndex,
112
+ dropdownId,
113
+ transitionProps,
114
+ ]);
115
+ const body = _jsx(PopoverContext.Provider, { value: contextValue, children: children });
116
+ if (!withDelayGroup) {
117
+ return body;
118
+ }
119
+ return (_jsx(FloatingDelayGroup, { delay: { open: openDelay, close: closeDelay }, timeoutMs: delayGroupTimeoutMs, children: body }));
120
+ };
121
+ export const Popover = Object.assign(PopoverRoot, {
122
+ Target: PopoverTarget,
123
+ Dropdown: PopoverDropdown,
124
+ });
@@ -0,0 +1,7 @@
1
+ export declare const StyledDropdown: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
2
+ export declare const ARROW_STYLES: Record<"top" | "right" | "bottom" | "left", {
3
+ clipPath: string;
4
+ borderTransparent: string[];
5
+ radiusCorner: string;
6
+ staticProp: string;
7
+ }>;
@@ -0,0 +1,40 @@
1
+ import styled from "styled-components";
2
+ export const StyledDropdown = styled.div `
3
+ position: relative;
4
+ min-width: 180px;
5
+ border-radius: 8px;
6
+ border: 1px solid ${({ theme }) => theme.palette.divider};
7
+ background-color: ${({ theme }) => theme.palette.background.default};
8
+ color: ${({ theme }) => theme.palette.text.primary};
9
+ box-shadow:
10
+ rgba(15, 23, 42, 0.1) 0px 10px 15px -3px,
11
+ rgba(15, 23, 42, 0.05) 0px 4px 6px -2px;
12
+ padding: 10px 12px;
13
+ outline: none;
14
+ `;
15
+ export const ARROW_STYLES = {
16
+ bottom: {
17
+ clipPath: "polygon(0 100%, 0 0, 100% 0)",
18
+ borderTransparent: ["borderBottomColor", "borderRightColor"],
19
+ radiusCorner: "borderTopLeftRadius",
20
+ staticProp: "top",
21
+ },
22
+ top: {
23
+ clipPath: "polygon(0 100%, 100% 100%, 100% 0)",
24
+ borderTransparent: ["borderTopColor", "borderLeftColor"],
25
+ radiusCorner: "borderBottomRightRadius",
26
+ staticProp: "bottom",
27
+ },
28
+ left: {
29
+ clipPath: "polygon(100% 0, 0 0, 100% 100%)",
30
+ borderTransparent: ["borderLeftColor", "borderBottomColor"],
31
+ radiusCorner: "borderTopRightRadius",
32
+ staticProp: "right",
33
+ },
34
+ right: {
35
+ clipPath: "polygon(0 100%, 0 0, 100% 100%)",
36
+ borderTransparent: ["borderRightColor", "borderTopColor"],
37
+ radiusCorner: "borderBottomLeftRadius",
38
+ staticProp: "left",
39
+ },
40
+ };
@@ -0,0 +1,5 @@
1
+ import { PopoverTransitionProps } from "./Popover.types";
2
+ export declare function usePopoverTransition(opened: boolean, { transition, duration, timingFunction }: PopoverTransitionProps): {
3
+ mounted: boolean;
4
+ styles: React.CSSProperties;
5
+ };
@@ -0,0 +1,63 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+ const TRANSITION_PRESETS = {
3
+ fade: {
4
+ from: { opacity: 0 },
5
+ to: { opacity: 1 },
6
+ },
7
+ scale: {
8
+ from: { opacity: 0, scale: "0.85" },
9
+ to: { opacity: 1, scale: "1" },
10
+ },
11
+ "scale-y": {
12
+ from: { opacity: 0, scale: "1 0.7" },
13
+ to: { opacity: 1, scale: "1 1" },
14
+ },
15
+ pop: {
16
+ from: { opacity: 0, scale: "0.6" },
17
+ to: { opacity: 1, scale: "1" },
18
+ },
19
+ };
20
+ export function usePopoverTransition(opened, { transition = "fade", duration = 150, timingFunction = "ease" }) {
21
+ const [mounted, setMounted] = useState(opened);
22
+ const [transitionEnabled, setTransitionEnabled] = useState(false);
23
+ const [phase, setPhase] = useState(opened ? "enter" : "exit");
24
+ const frameRef = useRef(0);
25
+ useEffect(() => {
26
+ cancelAnimationFrame(frameRef.current);
27
+ if (opened) {
28
+ setMounted(true);
29
+ setTransitionEnabled(false);
30
+ setPhase("exit");
31
+ frameRef.current = requestAnimationFrame(() => {
32
+ frameRef.current = requestAnimationFrame(() => {
33
+ setTransitionEnabled(true);
34
+ setPhase("enter");
35
+ });
36
+ });
37
+ }
38
+ else {
39
+ setTransitionEnabled(true);
40
+ setPhase("exit");
41
+ const timer = setTimeout(() => {
42
+ setMounted(false);
43
+ setTransitionEnabled(false);
44
+ }, duration);
45
+ return () => clearTimeout(timer);
46
+ }
47
+ }, [opened, duration]);
48
+ useEffect(() => {
49
+ return () => cancelAnimationFrame(frameRef.current);
50
+ }, []);
51
+ const preset = TRANSITION_PRESETS[transition];
52
+ const transitionStyles = phase === "enter" ? preset.to : preset.from;
53
+ const properties = [
54
+ ...new Set([...Object.keys(preset.from), ...Object.keys(preset.to)]),
55
+ ];
56
+ const transitionValue = properties
57
+ .map((prop) => `${prop} ${duration}ms ${timingFunction}`)
58
+ .join(", ");
59
+ return {
60
+ mounted: mounted || opened,
61
+ styles: Object.assign(Object.assign({}, transitionStyles), (transitionEnabled ? { transition: transitionValue } : {})),
62
+ };
63
+ }
@@ -0,0 +1,45 @@
1
+ import { Placement } from "@floating-ui/react";
2
+ import { ReactElement, ReactNode } from "react";
3
+ export type PopoverTransition = "fade" | "scale" | "scale-y" | "pop";
4
+ export type PopoverTrigger = "click" | "hover";
5
+ export interface PopoverTransitionProps {
6
+ transition?: PopoverTransition;
7
+ duration?: number;
8
+ timingFunction?: string;
9
+ }
10
+ export interface PopoverProps {
11
+ children: ReactNode;
12
+ opened?: boolean;
13
+ defaultOpened?: boolean;
14
+ onChange?: (opened: boolean) => void;
15
+ trigger?: PopoverTrigger;
16
+ disabled?: boolean;
17
+ position?: Placement;
18
+ offset?: number;
19
+ openDelay?: number;
20
+ closeDelay?: number;
21
+ closeOnClickOutside?: boolean;
22
+ closeOnEscape?: boolean;
23
+ withinPortal?: boolean;
24
+ trapFocus?: boolean;
25
+ returnFocus?: boolean;
26
+ keepMounted?: boolean;
27
+ withArrow?: boolean;
28
+ arrowSize?: number;
29
+ arrowRadius?: number;
30
+ zIndex?: number;
31
+ role?: "dialog" | "menu" | "tooltip";
32
+ width?: number | string;
33
+ matchTargetWidth?: boolean;
34
+ shiftPadding?: number;
35
+ flipPadding?: number;
36
+ withDelayGroup?: boolean;
37
+ delayGroupTimeoutMs?: number;
38
+ transitionProps?: PopoverTransitionProps;
39
+ }
40
+ export interface PopoverTargetProps {
41
+ children: ReactElement;
42
+ }
43
+ export interface PopoverDropdownProps extends React.HTMLAttributes<HTMLDivElement> {
44
+ children: ReactNode;
45
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import { PopoverDropdownProps } from "./Popover.types";
2
+ export declare const PopoverDropdown: React.FC<PopoverDropdownProps>;
@@ -0,0 +1,52 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import { FloatingFocusManager, FloatingPortal } from "@floating-ui/react";
14
+ import { usePopoverContext } from "./Popover.context";
15
+ import { ARROW_STYLES, StyledDropdown } from "./Popover.styles";
16
+ import { usePopoverTransition } from "./Popover.transitions";
17
+ export const PopoverDropdown = (_a) => {
18
+ var _b, _c;
19
+ var { children, className, style } = _a, props = __rest(_a, ["children", "className", "style"]);
20
+ const { opened, refs, context, floatingStyles, getFloatingProps, withArrow, arrowSize, arrowRadius, arrowRef, withinPortal, trapFocus, returnFocus, keepMounted, zIndex, dropdownId, transitionProps: ctxTransitionProps, } = usePopoverContext();
21
+ const { mounted, styles: transitionStyles } = usePopoverTransition(opened, ctxTransitionProps);
22
+ const arrowX = (_b = context.middlewareData.arrow) === null || _b === void 0 ? void 0 : _b.x;
23
+ const arrowY = (_c = context.middlewareData.arrow) === null || _c === void 0 ? void 0 : _c.y;
24
+ const [placementSide, placementAlignment] = context.placement.split("-");
25
+ const arrowConfig = ARROW_STYLES[placementSide];
26
+ const originSide = {
27
+ top: "bottom",
28
+ bottom: "top",
29
+ left: "right",
30
+ right: "left",
31
+ }[placementSide];
32
+ const originAlignment = placementAlignment === "start"
33
+ ? placementSide === "top" || placementSide === "bottom"
34
+ ? "left"
35
+ : "top"
36
+ : placementAlignment === "end"
37
+ ? placementSide === "top" || placementSide === "bottom"
38
+ ? "right"
39
+ : "bottom"
40
+ : "center";
41
+ const transformOrigin = `${originSide} ${originAlignment}`;
42
+ if (!mounted && !keepMounted) {
43
+ return null;
44
+ }
45
+ const dropdown = (_jsx(FloatingFocusManager, { context: context, modal: trapFocus, returnFocus: returnFocus, children: _jsxs(StyledDropdown, Object.assign({}, getFloatingProps(props), { id: dropdownId, ref: refs.setFloating, className: className, style: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, floatingStyles), transitionStyles), { transformOrigin }), style), { zIndex }), (keepMounted && !mounted
46
+ ? { visibility: "hidden", pointerEvents: "none" }
47
+ : {})), children: [children, withArrow && (_jsx("div", { ref: arrowRef, style: Object.assign(Object.assign(Object.assign({ position: "absolute", width: Math.max(arrowSize, 6), height: Math.max(arrowSize, 6), transform: "rotate(45deg)", background: "inherit", border: "1px solid", borderColor: "inherit", pointerEvents: "none", zIndex: 1 }, (arrowX != null ? { left: arrowX } : {})), (arrowY != null ? { top: arrowY } : {})), { [arrowConfig.staticProp]: -Math.max(arrowSize, 6) / 2, [arrowConfig.radiusCorner]: arrowRadius, [arrowConfig.borderTransparent[0]]: "transparent", [arrowConfig.borderTransparent[1]]: "transparent", clipPath: arrowConfig.clipPath }) }))] })) }));
48
+ if (!withinPortal) {
49
+ return dropdown;
50
+ }
51
+ return _jsx(FloatingPortal, { children: dropdown });
52
+ };
@@ -0,0 +1,2 @@
1
+ import { PopoverTargetProps } from "./Popover.types";
2
+ export declare const PopoverTarget: React.FC<PopoverTargetProps>;
@@ -0,0 +1,11 @@
1
+ import { useMergeRefs } from "@floating-ui/react";
2
+ import { cloneElement, isValidElement } from "react";
3
+ import { usePopoverContext } from "./Popover.context";
4
+ export const PopoverTarget = ({ children }) => {
5
+ const { refs, getReferenceProps, opened, dropdownId } = usePopoverContext();
6
+ if (!isValidElement(children)) {
7
+ return null;
8
+ }
9
+ const mergedRef = useMergeRefs([refs.setReference, children.ref]);
10
+ return cloneElement(children, getReferenceProps(Object.assign({ ref: mergedRef, "aria-expanded": opened, "aria-controls": dropdownId, "aria-haspopup": "dialog" }, children.props)));
11
+ };
@@ -0,0 +1,2 @@
1
+ export { Popover } from "./Popover";
2
+ export type { PopoverProps, PopoverTargetProps, PopoverDropdownProps, PopoverTransition, PopoverTrigger, PopoverTransitionProps, } from "./Popover.types";
@@ -0,0 +1 @@
1
+ export { Popover } from "./Popover";
package/dist/index.d.ts CHANGED
@@ -42,3 +42,4 @@ export type { ColumnProps, TableProps } from "./Table";
42
42
  export * from "./Tabs";
43
43
  export * from "./Divider";
44
44
  export * from "./SegmentedControl";
45
+ export * from "./Popover";
package/dist/index.js CHANGED
@@ -34,3 +34,4 @@ export * from "./Table";
34
34
  export * from "./Tabs";
35
35
  export * from "./Divider";
36
36
  export * from "./SegmentedControl";
37
+ export * from "./Popover";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monolith-forensics/monolith-ui",
3
- "version": "1.3.112-dev.2",
3
+ "version": "1.3.113",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "author": "Matt Danner (Monolith Forensics LLC)",