@paroicms/react-ui 0.5.0 → 0.5.2
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/Button.js +7 -1
- package/dist/Checkbox.d.ts +4 -3
- package/dist/Checkbox.js +5 -7
- package/dist/DateInput.d.ts +5 -3
- package/dist/DateInput.js +7 -4
- package/dist/Dialog.d.ts +4 -2
- package/dist/Dialog.js +30 -27
- package/dist/InputNumber.d.ts +2 -2
- package/dist/InputNumber.js +5 -5
- package/dist/InputText.d.ts +3 -4
- package/dist/InputText.js +7 -6
- package/dist/MultiSelect.d.ts +3 -2
- package/dist/MultiSelect.js +27 -24
- package/dist/PasswordInput.d.ts +5 -3
- package/dist/PasswordInput.js +7 -4
- package/dist/PopupMenu.d.ts +3 -4
- package/dist/PopupMenu.js +13 -51
- package/dist/RadioButton.d.ts +4 -4
- package/dist/RadioButton.js +5 -5
- package/dist/Select.d.ts +3 -4
- package/dist/Select.js +5 -5
- package/dist/SplitButton.d.ts +1 -0
- package/dist/SplitButton.js +12 -15
- package/dist/Switch.d.ts +2 -2
- package/dist/Switch.js +1 -1
- package/dist/Textarea.d.ts +5 -3
- package/dist/Textarea.js +7 -4
- package/dist/Tooltip.d.ts +1 -1
- package/dist/Tooltip.js +11 -32
- package/dist/alert-stack.d.ts +3 -1
- package/dist/alert-stack.js +2 -2
- package/dist/popup-positioning.d.ts +10 -0
- package/dist/popup-positioning.js +160 -0
- package/package.json +6 -6
- package/styles/Alert.css +1 -0
- package/styles/Checkbox.css +7 -6
- package/styles/DateInput.css +2 -25
- package/styles/Dialog.css +35 -22
- package/styles/InputNumber.css +2 -25
- package/styles/InputText.css +16 -31
- package/styles/MultiSelect.css +8 -23
- package/styles/PasswordInput.css +7 -18
- package/styles/RadioButton.css +6 -5
- package/styles/Select.css +12 -27
- package/styles/SplitButton.css +2 -8
- package/styles/Textarea.css +1 -24
- package/styles/Tooltip.css +4 -18
- package/styles/Tree.css +4 -3
- package/styles/theme/field.css +29 -0
- package/styles/theme/index.css +1 -0
package/dist/SplitButton.js
CHANGED
|
@@ -2,26 +2,23 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import "../styles/SplitButton.css";
|
|
3
3
|
import { clsx } from "clsx";
|
|
4
4
|
import { ChevronDown } from "lucide-react";
|
|
5
|
-
import { useEffect, useRef
|
|
5
|
+
import { useEffect, useRef } from "react";
|
|
6
6
|
import { Button, } from "./Button.js";
|
|
7
|
+
import { computePopupPosition, setupPopoverPositioning } from "./popup-positioning.js";
|
|
7
8
|
export function SplitButton(props) {
|
|
8
|
-
const { items, className, ...buttonProps } = props;
|
|
9
|
-
const [open, setOpen] = useState(false);
|
|
9
|
+
const { items, className, position, ...buttonProps } = props;
|
|
10
10
|
const containerRef = useRef(null);
|
|
11
|
+
const menuRef = useRef(null);
|
|
12
|
+
const menuId = useRef(`pa-splitbtn-menu-${Math.random().toString(36).substring(2, 9)}`);
|
|
11
13
|
const severity = props.severity ?? "primary";
|
|
12
14
|
const disabled = props.disabled;
|
|
13
|
-
// Close dropdown when clicking outside
|
|
14
15
|
useEffect(() => {
|
|
15
|
-
|
|
16
|
+
const menu = menuRef.current;
|
|
17
|
+
const container = containerRef.current;
|
|
18
|
+
if (!menu || !container)
|
|
16
19
|
return;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
setOpen(false);
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
23
|
-
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
24
|
-
}, [open]);
|
|
20
|
+
return setupPopoverPositioning(menu, () => computePopupPosition(container, menu, position ?? "auto", "corner"));
|
|
21
|
+
}, [position]);
|
|
25
22
|
const handleItemClick = async (item) => {
|
|
26
23
|
try {
|
|
27
24
|
await item.command();
|
|
@@ -35,8 +32,8 @@ export function SplitButton(props) {
|
|
|
35
32
|
}
|
|
36
33
|
}
|
|
37
34
|
finally {
|
|
38
|
-
|
|
35
|
+
menuRef.current?.hidePopover();
|
|
39
36
|
}
|
|
40
37
|
};
|
|
41
|
-
return (_jsxs("div", { ref: containerRef, className: clsx("PaSplitBtn", severity,
|
|
38
|
+
return (_jsxs("div", { ref: containerRef, className: clsx("PaSplitBtn", severity, disabled && "disabled", className), children: [_jsx(Button, { ...buttonProps, className: "PaSplitBtn-main" }), _jsx("button", { type: "button", className: "PaSplitBtn-toggle", popoverTarget: menuId.current, popoverTargetAction: "toggle", "aria-haspopup": "menu", children: _jsx(ChevronDown, { className: "PaSplitBtn-toggleIcon" }) }), _jsx("div", { ref: menuRef, id: menuId.current, className: "PaSplitBtn-menu", role: "menu", popover: "auto", children: items.map((item) => (_jsxs("button", { type: "button", className: clsx("PaSplitBtn-menuItem", item.danger && "danger", item.disabled && "disabled"), onClick: () => void handleItemClick(item), role: "menuitem", disabled: item.disabled, children: [item.icon && _jsx("span", { className: "PaSplitBtn-menuIcon", children: item.icon }), item.label] }, item.label))) })] }));
|
|
42
39
|
}
|
package/dist/Switch.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { InputHTMLAttributes } from "react";
|
|
1
|
+
import type { ChangeEvent, InputHTMLAttributes } from "react";
|
|
2
2
|
import "../styles/Switch.css";
|
|
3
3
|
export interface SwitchProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "onChange"> {
|
|
4
4
|
checked: boolean;
|
|
5
|
-
onChange
|
|
5
|
+
onChange?: (checked: boolean, ev: ChangeEvent<HTMLInputElement>) => void;
|
|
6
6
|
label?: string;
|
|
7
7
|
className?: string;
|
|
8
8
|
}
|
package/dist/Switch.js
CHANGED
|
@@ -3,7 +3,7 @@ import { clsx } from "clsx";
|
|
|
3
3
|
import "../styles/Switch.css";
|
|
4
4
|
export function Switch({ checked, onChange, label, className, ...rest }) {
|
|
5
5
|
const handleChange = (e) => {
|
|
6
|
-
onChange(e.target.checked);
|
|
6
|
+
onChange?.(e.target.checked, e);
|
|
7
7
|
};
|
|
8
8
|
if (label) {
|
|
9
9
|
return (_jsxs("label", { className: clsx("PaSwitch", className), children: [_jsx("input", { className: "PaSwitch-input", type: "checkbox", checked: checked, onChange: handleChange, ...rest }), _jsx("span", { className: "PaSwitch-track", children: _jsx("span", { className: "PaSwitch-thumb" }) }), _jsx("span", { className: "PaSwitch-label", children: label })] }));
|
package/dist/Textarea.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import "../styles/Textarea.css";
|
|
2
|
-
import type { Ref, TextareaHTMLAttributes } from "react";
|
|
3
|
-
export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
2
|
+
import type { ChangeEvent, Ref, TextareaHTMLAttributes } from "react";
|
|
3
|
+
export interface TextareaProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, "onChange"> {
|
|
4
|
+
value?: string;
|
|
5
|
+
onChange?: (value: string, ev: ChangeEvent<HTMLTextAreaElement>) => void;
|
|
4
6
|
label?: string;
|
|
5
7
|
error?: string;
|
|
6
8
|
ref?: Ref<HTMLTextAreaElement>;
|
|
7
9
|
}
|
|
8
|
-
export declare function Textarea({ className, label, error, ref, ...props }: TextareaProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function Textarea({ className, label, error, value, onChange, ref, ...props }: TextareaProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/Textarea.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import "../styles/Textarea.css";
|
|
3
3
|
import { clsx } from "clsx";
|
|
4
|
-
export function Textarea({ className, label, error, ref, ...props }) {
|
|
5
|
-
const
|
|
6
|
-
|
|
4
|
+
export function Textarea({ className, label, error, value, onChange, ref, ...props }) {
|
|
5
|
+
const handleChange = (e) => {
|
|
6
|
+
onChange?.(e.target.value, e);
|
|
7
|
+
};
|
|
8
|
+
const textareaElement = (_jsx("textarea", { ref: ref, className: clsx("PaTextarea", error && "error", !label && className), value: value, onChange: handleChange, ...props }));
|
|
9
|
+
return (_jsxs(_Fragment, { children: [label ? (_jsxs("label", { className: clsx("PaField", error && "error", className), children: [_jsx("span", { className: "PaField-label", children: label }), textareaElement] })) : (textareaElement), error && _jsx("span", { className: "PaFieldError", children: error })] }));
|
|
7
10
|
}
|
package/dist/Tooltip.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import "../styles/Tooltip.css";
|
|
|
2
2
|
import { type ReactNode } from "react";
|
|
3
3
|
export interface TooltipProps {
|
|
4
4
|
content: string;
|
|
5
|
-
position?: "top" | "bottom" | "left" | "right";
|
|
5
|
+
position?: "auto" | "top" | "bottom" | "left" | "right";
|
|
6
6
|
children: ReactNode;
|
|
7
7
|
className?: string;
|
|
8
8
|
delay?: number;
|
package/dist/Tooltip.js
CHANGED
|
@@ -1,50 +1,29 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import "../styles/Tooltip.css";
|
|
3
3
|
import { clsx } from "clsx";
|
|
4
|
-
import { useEffect, useRef
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const [coords, setCoords] = useState({ top: 0, left: 0 });
|
|
4
|
+
import { useEffect, useRef } from "react";
|
|
5
|
+
import { computePopupPosition, setupPopoverPositioning } from "./popup-positioning.js";
|
|
6
|
+
export function Tooltip({ content, position = "auto", children, className, delay = 200, }) {
|
|
8
7
|
const triggerRef = useRef(null);
|
|
9
8
|
const tooltipRef = useRef(null);
|
|
10
9
|
const timeoutRef = useRef(undefined);
|
|
11
10
|
const showTooltip = () => {
|
|
12
11
|
timeoutRef.current = window.setTimeout(() => {
|
|
13
|
-
|
|
12
|
+
tooltipRef.current?.showPopover();
|
|
14
13
|
}, delay);
|
|
15
14
|
};
|
|
16
15
|
const hideTooltip = () => {
|
|
17
16
|
if (timeoutRef.current) {
|
|
18
17
|
clearTimeout(timeoutRef.current);
|
|
19
18
|
}
|
|
20
|
-
|
|
19
|
+
tooltipRef.current?.hidePopover();
|
|
21
20
|
};
|
|
22
21
|
useEffect(() => {
|
|
23
|
-
if (!
|
|
22
|
+
if (!tooltipRef.current || !triggerRef.current)
|
|
24
23
|
return;
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
case "top":
|
|
31
|
-
top = rect.top - 8;
|
|
32
|
-
left = rect.left + rect.width / 2;
|
|
33
|
-
break;
|
|
34
|
-
case "bottom":
|
|
35
|
-
top = rect.bottom + 8;
|
|
36
|
-
left = rect.left + rect.width / 2;
|
|
37
|
-
break;
|
|
38
|
-
case "left":
|
|
39
|
-
top = rect.top + rect.height / 2;
|
|
40
|
-
left = rect.left - 8;
|
|
41
|
-
break;
|
|
42
|
-
case "right":
|
|
43
|
-
top = rect.top + rect.height / 2;
|
|
44
|
-
left = rect.right + 8;
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
setCoords({ top, left });
|
|
48
|
-
}, [visible, position]);
|
|
49
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { ref: triggerRef, className: "PaTooltip-trigger", onMouseEnter: showTooltip, onMouseLeave: hideTooltip, onFocus: showTooltip, onBlur: hideTooltip, children: children }), visible && (_jsx("div", { ref: tooltipRef, className: clsx("PaTooltip", position, className), style: { top: coords.top, left: coords.left }, role: "tooltip", children: content }))] }));
|
|
24
|
+
const triggerEl = triggerRef.current;
|
|
25
|
+
const popupEl = tooltipRef.current;
|
|
26
|
+
return setupPopoverPositioning(popupEl, () => computePopupPosition(triggerEl, popupEl, position, "cardinal"));
|
|
27
|
+
}, [position]);
|
|
28
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { ref: triggerRef, className: "PaTooltip-trigger", onMouseEnter: showTooltip, onMouseLeave: hideTooltip, onFocus: showTooltip, onBlur: hideTooltip, children: children }), _jsx("div", { ref: tooltipRef, className: clsx("PaTooltip", className), role: "tooltip", popover: "hint", children: content })] }));
|
|
50
29
|
}
|
package/dist/alert-stack.d.ts
CHANGED
|
@@ -14,5 +14,7 @@ interface AlertStackProviderProps {
|
|
|
14
14
|
}
|
|
15
15
|
export declare function AlertStackProvider({ children, ref }: AlertStackProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
16
16
|
export declare function useAlertStack(): AlertStackHandle;
|
|
17
|
-
export declare function AlertStack(
|
|
17
|
+
export declare function AlertStack(props?: {
|
|
18
|
+
className?: string;
|
|
19
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
18
20
|
export {};
|
package/dist/alert-stack.js
CHANGED
|
@@ -47,7 +47,7 @@ export function useAlertStack() {
|
|
|
47
47
|
}, [context.showAlert]);
|
|
48
48
|
return { showAlert: context.showAlert, showError };
|
|
49
49
|
}
|
|
50
|
-
export function AlertStack() {
|
|
50
|
+
export function AlertStack(props) {
|
|
51
51
|
const context = useContext(AlertStackContext);
|
|
52
52
|
const config = useReactUIConfig();
|
|
53
53
|
if (!context) {
|
|
@@ -68,5 +68,5 @@ export function AlertStack() {
|
|
|
68
68
|
]);
|
|
69
69
|
if (!currentAlert)
|
|
70
70
|
return null;
|
|
71
|
-
return (_jsx(Alert, { severity: currentAlert.severity, onClose: dismissCurrent, children: currentAlert.message }));
|
|
71
|
+
return (_jsx(Alert, { className: props?.className, severity: currentAlert.severity, onClose: dismissCurrent, children: currentAlert.message }));
|
|
72
72
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type CornerPosition = "topLeft" | "topRight" | "bottomLeft" | "bottomRight";
|
|
2
|
+
export type VerticalPosition = "top" | "bottom";
|
|
3
|
+
export type CardinalPosition = "top" | "bottom" | "left" | "right";
|
|
4
|
+
export interface PositionResult {
|
|
5
|
+
top: number;
|
|
6
|
+
left: number;
|
|
7
|
+
position: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function setupPopoverPositioning(popupEl: HTMLElement, getPosition: () => PositionResult): () => void;
|
|
10
|
+
export declare function computePopupPosition(triggerEl: HTMLElement, popupEl: HTMLElement, preferredPosition: string, mode: "corner" | "vertical" | "cardinal"): PositionResult;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
export function setupPopoverPositioning(popupEl, getPosition) {
|
|
2
|
+
const handleToggle = (e) => {
|
|
3
|
+
const newState = e.newState;
|
|
4
|
+
if (newState === "open") {
|
|
5
|
+
const position = getPosition();
|
|
6
|
+
popupEl.style.position = "absolute";
|
|
7
|
+
popupEl.style.top = `${position.top}px`;
|
|
8
|
+
popupEl.style.left = `${position.left}px`;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
popupEl.addEventListener("toggle", handleToggle);
|
|
12
|
+
return () => popupEl.removeEventListener("toggle", handleToggle);
|
|
13
|
+
}
|
|
14
|
+
export function computePopupPosition(triggerEl, popupEl, preferredPosition, mode) {
|
|
15
|
+
const triggerRect = triggerEl.getBoundingClientRect();
|
|
16
|
+
const popupWidth = popupEl.offsetWidth;
|
|
17
|
+
const popupHeight = popupEl.offsetHeight;
|
|
18
|
+
const bounds = getConstrainingBounds(triggerEl);
|
|
19
|
+
let result;
|
|
20
|
+
switch (mode) {
|
|
21
|
+
case "corner":
|
|
22
|
+
result = computeCornerPosition(triggerRect, popupWidth, popupHeight, bounds, preferredPosition);
|
|
23
|
+
break;
|
|
24
|
+
case "vertical":
|
|
25
|
+
result = computeVerticalPosition(triggerRect, popupWidth, popupHeight, bounds, preferredPosition);
|
|
26
|
+
break;
|
|
27
|
+
case "cardinal":
|
|
28
|
+
result = computeCardinalPosition(triggerRect, popupWidth, popupHeight, bounds, preferredPosition);
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
position: result.position,
|
|
33
|
+
top: result.top + window.scrollY,
|
|
34
|
+
left: result.left + window.scrollX,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function getConstrainingBounds(triggerEl) {
|
|
38
|
+
const dialog = triggerEl.closest("dialog");
|
|
39
|
+
if (dialog) {
|
|
40
|
+
const rect = dialog.getBoundingClientRect();
|
|
41
|
+
return {
|
|
42
|
+
top: rect.top,
|
|
43
|
+
left: rect.left,
|
|
44
|
+
right: rect.right,
|
|
45
|
+
bottom: rect.bottom,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
top: 0,
|
|
50
|
+
left: 0,
|
|
51
|
+
right: window.innerWidth,
|
|
52
|
+
bottom: window.innerHeight,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function computeCornerPosition(triggerRect, popupWidth, popupHeight, bounds, preferredPosition) {
|
|
56
|
+
const spaceTop = triggerRect.top - bounds.top;
|
|
57
|
+
const spaceBottom = bounds.bottom - triggerRect.bottom;
|
|
58
|
+
const spaceLeft = triggerRect.left - bounds.left;
|
|
59
|
+
const spaceRight = bounds.right - triggerRect.right;
|
|
60
|
+
let position;
|
|
61
|
+
if (preferredPosition !== "auto") {
|
|
62
|
+
position = preferredPosition;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// Pick corner with most space, prefer bottom-right > bottom-left > top-right > top-left
|
|
66
|
+
const canBottom = spaceBottom >= popupHeight;
|
|
67
|
+
const canTop = spaceTop >= popupHeight;
|
|
68
|
+
const canRight = spaceRight + triggerRect.width >= popupWidth;
|
|
69
|
+
const canLeft = spaceLeft + triggerRect.width >= popupWidth;
|
|
70
|
+
if (canBottom && canRight) {
|
|
71
|
+
position = "bottomRight";
|
|
72
|
+
}
|
|
73
|
+
else if (canBottom && canLeft) {
|
|
74
|
+
position = "bottomLeft";
|
|
75
|
+
}
|
|
76
|
+
else if (canTop && canRight) {
|
|
77
|
+
position = "topRight";
|
|
78
|
+
}
|
|
79
|
+
else if (canTop && canLeft) {
|
|
80
|
+
position = "topLeft";
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Fallback: choose based on available space
|
|
84
|
+
const vertical = spaceBottom >= spaceTop ? "bottom" : "top";
|
|
85
|
+
const horizontal = spaceRight >= spaceLeft ? "Right" : "Left";
|
|
86
|
+
position = `${vertical}${horizontal}`;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
let top;
|
|
90
|
+
let left;
|
|
91
|
+
if (position.startsWith("bottom")) {
|
|
92
|
+
top = triggerRect.bottom;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
top = triggerRect.top - popupHeight;
|
|
96
|
+
}
|
|
97
|
+
if (position.endsWith("Right")) {
|
|
98
|
+
left = triggerRect.left;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
left = triggerRect.right - popupWidth;
|
|
102
|
+
}
|
|
103
|
+
return { position, top, left };
|
|
104
|
+
}
|
|
105
|
+
function computeVerticalPosition(triggerRect, _popupWidth, popupHeight, bounds, preferredPosition) {
|
|
106
|
+
const spaceTop = triggerRect.top - bounds.top;
|
|
107
|
+
const spaceBottom = bounds.bottom - triggerRect.bottom;
|
|
108
|
+
let position;
|
|
109
|
+
if (preferredPosition !== "auto") {
|
|
110
|
+
position = preferredPosition;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
position = spaceBottom >= popupHeight || spaceBottom >= spaceTop ? "bottom" : "top";
|
|
114
|
+
}
|
|
115
|
+
const top = position === "bottom" ? triggerRect.bottom : triggerRect.top - popupHeight;
|
|
116
|
+
const left = triggerRect.left;
|
|
117
|
+
return { position, top, left };
|
|
118
|
+
}
|
|
119
|
+
function computeCardinalPosition(triggerRect, popupWidth, popupHeight, bounds, preferredPosition) {
|
|
120
|
+
const spaceTop = triggerRect.top - bounds.top;
|
|
121
|
+
const spaceBottom = bounds.bottom - triggerRect.bottom;
|
|
122
|
+
const spaceLeft = triggerRect.left - bounds.left;
|
|
123
|
+
const spaceRight = bounds.right - triggerRect.right;
|
|
124
|
+
let position;
|
|
125
|
+
if (preferredPosition !== "auto") {
|
|
126
|
+
position = preferredPosition;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// Pick direction with most space
|
|
130
|
+
const spaces = [
|
|
131
|
+
{ dir: "bottom", space: spaceBottom },
|
|
132
|
+
{ dir: "right", space: spaceRight },
|
|
133
|
+
{ dir: "top", space: spaceTop },
|
|
134
|
+
{ dir: "left", space: spaceLeft },
|
|
135
|
+
];
|
|
136
|
+
spaces.sort((a, b) => b.space - a.space);
|
|
137
|
+
position = spaces[0].dir;
|
|
138
|
+
}
|
|
139
|
+
let top;
|
|
140
|
+
let left;
|
|
141
|
+
switch (position) {
|
|
142
|
+
case "top":
|
|
143
|
+
top = triggerRect.top - popupHeight;
|
|
144
|
+
left = triggerRect.left + (triggerRect.width - popupWidth) / 2;
|
|
145
|
+
break;
|
|
146
|
+
case "bottom":
|
|
147
|
+
top = triggerRect.bottom;
|
|
148
|
+
left = triggerRect.left + (triggerRect.width - popupWidth) / 2;
|
|
149
|
+
break;
|
|
150
|
+
case "left":
|
|
151
|
+
top = triggerRect.top + (triggerRect.height - popupHeight) / 2;
|
|
152
|
+
left = triggerRect.left - popupWidth;
|
|
153
|
+
break;
|
|
154
|
+
case "right":
|
|
155
|
+
top = triggerRect.top + (triggerRect.height - popupHeight) / 2;
|
|
156
|
+
left = triggerRect.right;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
return { position, top, left };
|
|
160
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paroicms/react-ui",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "React UI toolkit for ParoiCMS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"paroicms",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"dev": "tsc --watch --preserveWatchOutput"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@paroicms/public-anywhere-lib": "0.41.
|
|
28
|
+
"@paroicms/public-anywhere-lib": "0.41.1",
|
|
29
29
|
"clsx": "~2.1.1",
|
|
30
30
|
"lucide-react": "~0.562.0",
|
|
31
31
|
"react-sortablejs": "~6.1.4",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"react-dom": ">=18.0.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@types/react": "~19.2.
|
|
39
|
+
"@types/react": "~19.2.8",
|
|
40
40
|
"@types/react-dom": "~19.2.3",
|
|
41
|
-
"@types/sortablejs": "^1.15.
|
|
42
|
-
"react": "~19.2.
|
|
43
|
-
"react-dom": "~19.2.
|
|
41
|
+
"@types/sortablejs": "^1.15.9",
|
|
42
|
+
"react": "~19.2.3",
|
|
43
|
+
"react-dom": "~19.2.3",
|
|
44
44
|
"rimraf": "~6.1.2",
|
|
45
45
|
"typescript": "~5.9.3"
|
|
46
46
|
},
|
package/styles/Alert.css
CHANGED
package/styles/Checkbox.css
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* ========================================
|
|
2
2
|
Checkbox Component
|
|
3
3
|
======================================== */
|
|
4
|
-
.
|
|
4
|
+
.PaCheckboxField {
|
|
5
5
|
display: inline-flex;
|
|
6
6
|
gap: var(--space-2);
|
|
7
7
|
align-items: center;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
user-select: none;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
.
|
|
12
|
+
.PaCheckboxInput {
|
|
13
13
|
display: flex;
|
|
14
14
|
flex-shrink: 0;
|
|
15
15
|
align-items: center;
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
border-radius: var(--radius-sm);
|
|
25
25
|
transition: all var(--transition);
|
|
26
26
|
|
|
27
|
-
&:hover {
|
|
27
|
+
&:hover:not(:disabled) {
|
|
28
28
|
border-color: var(--color-primary);
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -55,7 +55,8 @@
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
.
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
.PaCheckboxGroup {
|
|
59
|
+
display: flex;
|
|
60
|
+
flex-wrap: wrap;
|
|
61
|
+
gap: var(--space-3);
|
|
61
62
|
}
|
package/styles/DateInput.css
CHANGED
|
@@ -1,25 +1,7 @@
|
|
|
1
1
|
/* ========================================
|
|
2
2
|
DateInput Component
|
|
3
3
|
======================================== */
|
|
4
|
-
.
|
|
5
|
-
display: flex;
|
|
6
|
-
flex-direction: column;
|
|
7
|
-
gap: var(--space-2);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.PaDateInput-wrapper {
|
|
11
|
-
display: flex;
|
|
12
|
-
flex-direction: column;
|
|
13
|
-
gap: var(--space-2);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.PaDateInput-label {
|
|
17
|
-
font-size: var(--text-sm);
|
|
18
|
-
font-weight: var(--font-medium);
|
|
19
|
-
color: var(--color-text);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.PaDateInput-field {
|
|
4
|
+
.PaDateTimeInput {
|
|
23
5
|
padding: var(--space-2) var(--space-3);
|
|
24
6
|
font-family: inherit;
|
|
25
7
|
font-size: var(--text-base);
|
|
@@ -32,7 +14,7 @@
|
|
|
32
14
|
border-color var(--transition),
|
|
33
15
|
box-shadow var(--transition);
|
|
34
16
|
|
|
35
|
-
&:hover {
|
|
17
|
+
&:hover:not(:disabled) {
|
|
36
18
|
border-color: var(--color-primary);
|
|
37
19
|
}
|
|
38
20
|
|
|
@@ -52,8 +34,3 @@
|
|
|
52
34
|
border-color: var(--color-danger);
|
|
53
35
|
}
|
|
54
36
|
}
|
|
55
|
-
|
|
56
|
-
.PaDateInput-error {
|
|
57
|
-
font-size: var(--text-xs);
|
|
58
|
-
color: var(--color-danger);
|
|
59
|
-
}
|
package/styles/Dialog.css
CHANGED
|
@@ -1,32 +1,43 @@
|
|
|
1
1
|
/* ========================================
|
|
2
2
|
Dialog Component
|
|
3
3
|
======================================== */
|
|
4
|
-
.PaDialog-overlay {
|
|
5
|
-
position: fixed;
|
|
6
|
-
inset: 0;
|
|
7
|
-
z-index: var(--z-modal);
|
|
8
|
-
display: flex;
|
|
9
|
-
align-items: center;
|
|
10
|
-
justify-content: center;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.PaDialog-backdrop {
|
|
14
|
-
position: absolute;
|
|
15
|
-
inset: 0;
|
|
16
|
-
background: rgba(0, 0, 0, 0.5);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
4
|
.PaDialog {
|
|
20
|
-
position: relative;
|
|
21
|
-
z-index: 1;
|
|
22
|
-
display: flex;
|
|
23
|
-
flex-direction: column;
|
|
24
|
-
min-width: 320px;
|
|
25
5
|
max-width: 90vw;
|
|
26
|
-
|
|
6
|
+
padding: 0;
|
|
27
7
|
background: var(--color-bg-elevated);
|
|
8
|
+
border: none;
|
|
28
9
|
border-radius: var(--radius-lg);
|
|
29
10
|
box-shadow: var(--shadow-lg);
|
|
11
|
+
|
|
12
|
+
&[open] {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
&:modal {
|
|
18
|
+
max-height: 90vh;
|
|
19
|
+
margin: auto;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
&::backdrop {
|
|
23
|
+
background: rgba(0, 0, 0, 0.5);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Size variants */
|
|
27
|
+
&.sizeSm {
|
|
28
|
+
width: 480px;
|
|
29
|
+
max-width: 100%;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&.sizeMd {
|
|
33
|
+
width: 640px;
|
|
34
|
+
max-width: 100%;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&.sizeLg {
|
|
38
|
+
width: 800px;
|
|
39
|
+
max-width: 100%;
|
|
40
|
+
}
|
|
30
41
|
}
|
|
31
42
|
|
|
32
43
|
.PaDialog-header {
|
|
@@ -34,7 +45,7 @@
|
|
|
34
45
|
gap: var(--space-4);
|
|
35
46
|
align-items: center;
|
|
36
47
|
justify-content: space-between;
|
|
37
|
-
padding: var(--space-
|
|
48
|
+
padding: var(--space-3) var(--space-5);
|
|
38
49
|
border-bottom: 1px solid var(--color-border-light);
|
|
39
50
|
}
|
|
40
51
|
|
|
@@ -48,6 +59,8 @@
|
|
|
48
59
|
display: flex;
|
|
49
60
|
align-items: center;
|
|
50
61
|
justify-content: center;
|
|
62
|
+
width: 40px;
|
|
63
|
+
height: 40px;
|
|
51
64
|
padding: var(--space-1);
|
|
52
65
|
color: var(--color-text-muted);
|
|
53
66
|
cursor: pointer;
|
package/styles/InputNumber.css
CHANGED
|
@@ -1,25 +1,7 @@
|
|
|
1
1
|
/* ========================================
|
|
2
2
|
InputNumber Component
|
|
3
3
|
======================================== */
|
|
4
|
-
.
|
|
5
|
-
display: flex;
|
|
6
|
-
flex-direction: column;
|
|
7
|
-
gap: var(--space-2);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.PaInputNumber-wrapper {
|
|
11
|
-
display: flex;
|
|
12
|
-
flex-direction: column;
|
|
13
|
-
gap: var(--space-2);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.PaInputNumber-label {
|
|
17
|
-
font-size: var(--text-sm);
|
|
18
|
-
font-weight: var(--font-medium);
|
|
19
|
-
color: var(--color-text);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.PaInputNumber-field {
|
|
4
|
+
.PaNumberInput {
|
|
23
5
|
width: 100%;
|
|
24
6
|
padding: var(--space-2) var(--space-3);
|
|
25
7
|
font-family: inherit;
|
|
@@ -33,7 +15,7 @@
|
|
|
33
15
|
border-color var(--transition),
|
|
34
16
|
box-shadow var(--transition);
|
|
35
17
|
|
|
36
|
-
&:hover {
|
|
18
|
+
&:hover:not(:disabled) {
|
|
37
19
|
border-color: var(--color-primary);
|
|
38
20
|
}
|
|
39
21
|
|
|
@@ -53,8 +35,3 @@
|
|
|
53
35
|
border-color: var(--color-danger);
|
|
54
36
|
}
|
|
55
37
|
}
|
|
56
|
-
|
|
57
|
-
.PaInputNumber-error {
|
|
58
|
-
font-size: var(--text-xs);
|
|
59
|
-
color: var(--color-danger);
|
|
60
|
-
}
|