@monolith-forensics/monolith-ui 1.3.112 → 1.4.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/dist/Popover/Popover.context.d.ts +23 -0
- package/dist/Popover/Popover.context.js +9 -0
- package/dist/Popover/Popover.d.ts +7 -0
- package/dist/Popover/Popover.js +124 -0
- package/dist/Popover/Popover.styles.d.ts +7 -0
- package/dist/Popover/Popover.styles.js +40 -0
- package/dist/Popover/Popover.transitions.d.ts +5 -0
- package/dist/Popover/Popover.transitions.js +63 -0
- package/dist/Popover/Popover.types.d.ts +45 -0
- package/dist/Popover/Popover.types.js +1 -0
- package/dist/Popover/PopoverDropdown.d.ts +2 -0
- package/dist/Popover/PopoverDropdown.js +52 -0
- package/dist/Popover/PopoverTarget.d.ts +2 -0
- package/dist/Popover/PopoverTarget.js +11 -0
- package/dist/Popover/index.d.ts +2 -0
- package/dist/Popover/index.js +1 -0
- package/dist/TextAreaInput/TextAreaInput.d.ts +17 -0
- package/dist/TextAreaInput/TextAreaInput.js +46 -27
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
|
@@ -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,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,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,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 @@
|
|
|
1
|
+
export { Popover } from "./Popover";
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Size } from "../core";
|
|
3
3
|
import { DropDownItem } from "..";
|
|
4
|
+
import { DropDownMenuProps } from "../DropDownMenu/types";
|
|
4
5
|
export type InsertableItem = {
|
|
5
6
|
label: string;
|
|
6
7
|
value: string;
|
|
8
|
+
group?: string;
|
|
7
9
|
};
|
|
8
10
|
export interface TextAreaInputProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
9
11
|
variant?: "contained" | "filled" | "outlined" | "text";
|
|
@@ -20,13 +22,28 @@ export interface TextAreaInputProps extends React.TextareaHTMLAttributes<HTMLTex
|
|
|
20
22
|
rowHeight: number;
|
|
21
23
|
}) => void;
|
|
22
24
|
showActionMenu?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Visual style of the action menu trigger.
|
|
27
|
+
* - `"ellipsis"` renders a minimal `...` icon button (default).
|
|
28
|
+
* - `"dropdown"` renders an outlined button with a label and arrow, similar to the Table Filter menu.
|
|
29
|
+
*/
|
|
30
|
+
actionMenuVariant?: "ellipsis" | "dropdown";
|
|
23
31
|
actionMenuOptions?: Array<{
|
|
24
32
|
value: string;
|
|
25
33
|
label: string;
|
|
26
34
|
}>;
|
|
27
35
|
onActionMenuSelect?: (item: DropDownItem) => void;
|
|
36
|
+
/** Label displayed on the actions dropdown button. Only used when `actionMenuVariant` is `"dropdown"`. Defaults to "Actions". */
|
|
37
|
+
actionMenuLabel?: string;
|
|
38
|
+
/** Icon rendered in the left section of the actions dropdown button. Only used when `actionMenuVariant` is `"dropdown"`. Defaults to MoreHorizontal. */
|
|
39
|
+
actionMenuIcon?: React.ReactNode;
|
|
40
|
+
/** Whether the actions dropdown is searchable. Only used when `actionMenuVariant` is `"dropdown"`. Defaults to false. */
|
|
41
|
+
actionMenuSearchable?: boolean;
|
|
42
|
+
/** Additional props forwarded to the DropDownMenu component. Only used when `actionMenuVariant` is `"dropdown"`. */
|
|
43
|
+
actionMenuProps?: Partial<DropDownMenuProps>;
|
|
28
44
|
insertableItems?: InsertableItem[];
|
|
29
45
|
onInsertItem?: (item: InsertableItem) => void;
|
|
46
|
+
groupInsertableItems?: boolean;
|
|
30
47
|
}
|
|
31
48
|
declare const TextAreaInput: React.ForwardRefExoticComponent<TextAreaInputProps & React.RefAttributes<HTMLTextAreaElement>>;
|
|
32
49
|
export default TextAreaInput;
|
|
@@ -50,11 +50,11 @@ const TextAreaInput = forwardRef((props, ref) => {
|
|
|
50
50
|
// UI
|
|
51
51
|
label, error, required, colSpan = 1, size = "sm", description, maxRows = 6, minRows = 3, onHeightChange, cacheMeasurements,
|
|
52
52
|
// Action menu
|
|
53
|
-
showActionMenu = false, actionMenuOptions = DEFAULT_ACTIONS, onActionMenuSelect,
|
|
53
|
+
showActionMenu = false, actionMenuVariant = "ellipsis", actionMenuOptions = DEFAULT_ACTIONS, onActionMenuSelect, actionMenuLabel = "Actions", actionMenuIcon, actionMenuSearchable = false, actionMenuProps,
|
|
54
54
|
// Insertable items
|
|
55
|
-
insertableItems, onInsertItem } = props,
|
|
55
|
+
insertableItems, onInsertItem, groupInsertableItems } = props,
|
|
56
56
|
// Rest of props for TextArea
|
|
57
|
-
rest = __rest(props, ["label", "error", "required", "colSpan", "size", "description", "maxRows", "minRows", "onHeightChange", "cacheMeasurements", "showActionMenu", "actionMenuOptions", "onActionMenuSelect", "insertableItems", "onInsertItem"]);
|
|
57
|
+
rest = __rest(props, ["label", "error", "required", "colSpan", "size", "description", "maxRows", "minRows", "onHeightChange", "cacheMeasurements", "showActionMenu", "actionMenuVariant", "actionMenuOptions", "onActionMenuSelect", "actionMenuLabel", "actionMenuIcon", "actionMenuSearchable", "actionMenuProps", "insertableItems", "onInsertItem", "groupInsertableItems"]);
|
|
58
58
|
// State for insert menu visibility
|
|
59
59
|
const [showInsertMenu, setShowInsertMenu] = useState(false);
|
|
60
60
|
const [triggerSelectBoxOpen, setTriggerSelectBoxOpen] = useState(false);
|
|
@@ -75,10 +75,16 @@ const TextAreaInput = forwardRef((props, ref) => {
|
|
|
75
75
|
if (!showInsertMenu)
|
|
76
76
|
return;
|
|
77
77
|
const handleClickOutside = (event) => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
var _a, _b, _c;
|
|
79
|
+
const target = event.target;
|
|
80
|
+
// Ignore clicks inside the insert menu container
|
|
81
|
+
if ((_a = insertMenuRef.current) === null || _a === void 0 ? void 0 : _a.contains(target))
|
|
82
|
+
return;
|
|
83
|
+
// Ignore clicks inside the SelectBox floating portal dropdown
|
|
84
|
+
const floatingEl = (_c = (_b = target).closest) === null || _c === void 0 ? void 0 : _c.call(_b, ".mfFloating");
|
|
85
|
+
if (floatingEl)
|
|
86
|
+
return;
|
|
87
|
+
setShowInsertMenu(false);
|
|
82
88
|
};
|
|
83
89
|
document.addEventListener("mousedown", handleClickOutside);
|
|
84
90
|
return () => {
|
|
@@ -86,6 +92,7 @@ const TextAreaInput = forwardRef((props, ref) => {
|
|
|
86
92
|
};
|
|
87
93
|
}, [showInsertMenu]);
|
|
88
94
|
const handleActionSelect = (item) => {
|
|
95
|
+
var _a;
|
|
89
96
|
if (item.value === "insert" && (insertableItems === null || insertableItems === void 0 ? void 0 : insertableItems.length)) {
|
|
90
97
|
setShowInsertMenu(true);
|
|
91
98
|
// Trigger SelectBox to open using the new enhanced props
|
|
@@ -95,11 +102,10 @@ const TextAreaInput = forwardRef((props, ref) => {
|
|
|
95
102
|
// Built-in clear functionality
|
|
96
103
|
const textarea = textareaRef.current;
|
|
97
104
|
if (textarea) {
|
|
98
|
-
|
|
105
|
+
const nativeSet = (_a = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value")) === null || _a === void 0 ? void 0 : _a.set;
|
|
106
|
+
nativeSet === null || nativeSet === void 0 ? void 0 : nativeSet.call(textarea, "");
|
|
107
|
+
textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
99
108
|
textarea.focus();
|
|
100
|
-
// Trigger change event so controlled components update
|
|
101
|
-
const event = new Event("input", { bubbles: true });
|
|
102
|
-
textarea.dispatchEvent(event);
|
|
103
109
|
}
|
|
104
110
|
onActionMenuSelect === null || onActionMenuSelect === void 0 ? void 0 : onActionMenuSelect(item);
|
|
105
111
|
}
|
|
@@ -112,6 +118,7 @@ const TextAreaInput = forwardRef((props, ref) => {
|
|
|
112
118
|
setTriggerSelectBoxOpen(false);
|
|
113
119
|
};
|
|
114
120
|
const handleInsertSelect = (value, option) => {
|
|
121
|
+
var _a;
|
|
115
122
|
console.log("Selected value:", value, "Selected option:", option); // Debug log
|
|
116
123
|
// SelectBox passes (value, option) - we want the full option object
|
|
117
124
|
const item = option;
|
|
@@ -131,28 +138,40 @@ const TextAreaInput = forwardRef((props, ref) => {
|
|
|
131
138
|
const end = textarea.selectionEnd;
|
|
132
139
|
const currentValue = textarea.value;
|
|
133
140
|
const newValue = currentValue.slice(0, start) + item.value + currentValue.slice(end);
|
|
134
|
-
|
|
141
|
+
// Use the native setter so React's synthetic event system
|
|
142
|
+
// recognises the change on controlled inputs
|
|
143
|
+
const nativeSet = (_a = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value")) === null || _a === void 0 ? void 0 : _a.set;
|
|
144
|
+
nativeSet === null || nativeSet === void 0 ? void 0 : nativeSet.call(textarea, newValue);
|
|
145
|
+
// Dispatch as a bubbling event so React's onChange fires
|
|
146
|
+
textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
135
147
|
textarea.focus();
|
|
136
148
|
textarea.setSelectionRange(start + item.value.length, start + item.value.length);
|
|
137
|
-
// Trigger change event
|
|
138
|
-
const event = new Event("input", { bubbles: true });
|
|
139
|
-
textarea.dispatchEvent(event);
|
|
140
149
|
}
|
|
141
150
|
}
|
|
142
151
|
setShowInsertMenu(false);
|
|
143
152
|
};
|
|
144
|
-
return (_jsxs("div", { style: { gridColumn: `span ${colSpan}`, height: "fit-content" }, children: [label && (_jsx(FieldLabel, { asterisk: required, error: error, description: description, size: size, actionComponent: showActionMenu
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
return (_jsxs("div", { style: { gridColumn: `span ${colSpan}`, height: "fit-content" }, children: [label && (_jsx(FieldLabel, { asterisk: required, error: error, description: description, size: size, actionComponent: showActionMenu
|
|
154
|
+
? actionMenuVariant === "dropdown"
|
|
155
|
+
? (_jsx(DropDownMenu, Object.assign({ data: actionMenuOptions, variant: "outlined", size: "xs", arrow: true, searchable: actionMenuSearchable, onItemSelect: handleActionSelect, buttonProps: {
|
|
156
|
+
title: actionMenuLabel,
|
|
157
|
+
size: "xxs",
|
|
158
|
+
leftSection: actionMenuIcon,
|
|
159
|
+
}, dropDownProps: {
|
|
160
|
+
style: { width: 175, maxWidth: 400 },
|
|
161
|
+
} }, actionMenuProps, { children: actionMenuLabel })))
|
|
162
|
+
: (_jsx(DropDownMenu, { data: actionMenuOptions, variant: "text", size: "xs", arrow: false, onItemSelect: handleActionSelect, buttonProps: {
|
|
163
|
+
"aria-label": "Open actions",
|
|
164
|
+
style: {
|
|
165
|
+
minWidth: "auto",
|
|
166
|
+
border: "none",
|
|
167
|
+
background: "transparent",
|
|
168
|
+
padding: 0,
|
|
169
|
+
margin: 0,
|
|
170
|
+
height: 16,
|
|
171
|
+
width: 16,
|
|
172
|
+
},
|
|
173
|
+
}, children: _jsx(StyledMoreHorizontal, { size: 16 }) }))
|
|
174
|
+
: null, children: label })), _jsxs(TextAreaWrapper, { children: [_jsx(TextArea, Object.assign({ ref: mergedRef, size: size, maxRows: maxRows, minRows: minRows, onHeightChange: onHeightChange, cacheMeasurements: cacheMeasurements }, rest)), showInsertMenu && (insertableItems === null || insertableItems === void 0 ? void 0 : insertableItems.length) && (_jsx(InsertMenuOverlay, { ref: insertMenuRef, "$visible": showInsertMenu, children: _jsx(StyledInsertSelectBox, { data: insertableItems, grouped: groupInsertableItems, searchable: true, clearable: false, arrow: false, focused: showInsertMenu, openOnFocus: true, triggerOpen: triggerSelectBoxOpen, onOpened: handleSelectBoxOpened, onChange: handleInsertSelect, size: size }) }))] })] }));
|
|
156
175
|
});
|
|
157
176
|
TextAreaInput.displayName = "TextAreaInput";
|
|
158
177
|
export default TextAreaInput;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED