@paroicms/react-ui 0.4.4 → 0.5.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/Accordion.d.ts +10 -0
- package/dist/{PuAccordion.jsx → Accordion.js} +5 -8
- package/dist/Alert.d.ts +10 -0
- package/dist/Alert.js +7 -0
- package/dist/Badge.d.ts +8 -0
- package/dist/Badge.js +6 -0
- package/dist/Breadcrumb.d.ts +14 -0
- package/dist/Breadcrumb.js +10 -0
- package/dist/Button.d.ts +36 -0
- package/dist/Button.js +74 -0
- package/dist/Card.d.ts +10 -0
- package/dist/Card.js +7 -0
- package/dist/Checkbox.d.ts +9 -0
- package/dist/Checkbox.js +12 -0
- package/dist/Chip.d.ts +8 -0
- package/dist/Chip.js +7 -0
- package/dist/Column.d.ts +14 -0
- package/dist/Column.js +7 -0
- package/dist/DataTable.d.ts +30 -0
- package/dist/DataTable.js +26 -0
- package/dist/DateInput.d.ts +9 -0
- package/dist/DateInput.js +7 -0
- package/dist/Dialog.d.ts +13 -0
- package/dist/Dialog.js +55 -0
- package/dist/Inplace.d.ts +12 -0
- package/dist/Inplace.js +16 -0
- package/dist/InputNumber.d.ts +10 -0
- package/dist/InputNumber.js +19 -0
- package/dist/InputText.d.ts +14 -0
- package/dist/InputText.js +11 -0
- package/dist/MenuItem.d.ts +8 -0
- package/dist/MenuItem.js +18 -0
- package/dist/MultiSelect.d.ts +17 -0
- package/dist/MultiSelect.js +50 -0
- package/dist/Panel.d.ts +11 -0
- package/dist/Panel.js +9 -0
- package/dist/PasswordInput.d.ts +8 -0
- package/dist/PasswordInput.js +10 -0
- package/dist/PopupMenu.d.ts +20 -0
- package/dist/{PuPopupMenu.jsx → PopupMenu.js} +45 -36
- package/dist/RadioButton.d.ts +9 -0
- package/dist/RadioButton.js +12 -0
- package/dist/Select.d.ts +18 -0
- package/dist/Select.js +11 -0
- package/dist/SideMenu.d.ts +5 -0
- package/dist/SideMenu.js +13 -0
- package/dist/SortableList.d.ts +19 -0
- package/dist/SortableList.js +27 -0
- package/dist/Spinner.d.ts +2 -0
- package/dist/Spinner.js +5 -0
- package/dist/SplitButton.d.ts +24 -0
- package/dist/SplitButton.js +42 -0
- package/dist/Switch.d.ts +9 -0
- package/dist/Switch.js +12 -0
- package/dist/Tabs.d.ts +22 -0
- package/dist/Tabs.js +21 -0
- package/dist/Textarea.d.ts +8 -0
- package/dist/Textarea.js +7 -0
- package/dist/ToggleButton.d.ts +11 -0
- package/dist/ToggleButton.js +6 -0
- package/dist/ToggleGroup.d.ts +15 -0
- package/dist/ToggleGroup.js +6 -0
- package/dist/Tooltip.d.ts +10 -0
- package/dist/Tooltip.js +50 -0
- package/dist/Tree.d.ts +22 -0
- package/dist/Tree.js +43 -0
- package/dist/alert-stack.d.ts +18 -0
- package/dist/alert-stack.js +72 -0
- package/dist/index.d.ts +36 -10
- package/dist/index.js +45 -10
- package/dist/paroi-ui-lib-types.d.ts +4 -4
- package/dist/react-ui-provider.d.ts +15 -0
- package/dist/react-ui-provider.js +22 -0
- package/package.json +16 -2
- package/styles/Accordion.css +46 -0
- package/styles/Alert.css +76 -0
- package/styles/Badge.css +59 -0
- package/styles/Breadcrumb.css +57 -0
- package/styles/Button.css +167 -0
- package/styles/Card.css +28 -0
- package/styles/Checkbox.css +61 -0
- package/styles/Chip.css +35 -0
- package/styles/DataTable.css +176 -0
- package/styles/DateInput.css +59 -0
- package/styles/Dialog.css +77 -0
- package/styles/Inplace.css +44 -0
- package/styles/InputNumber.css +60 -0
- package/styles/InputText.css +99 -0
- package/styles/MenuItem.css +169 -0
- package/styles/MultiSelect.css +158 -0
- package/styles/Panel.css +40 -0
- package/styles/PasswordInput.css +80 -0
- package/styles/PopupMenu.css +37 -0
- package/styles/RadioButton.css +60 -0
- package/styles/Select.css +72 -0
- package/styles/SideMenu.css +7 -0
- package/styles/SortableList.css +32 -0
- package/styles/Spinner.css +30 -0
- package/styles/SplitButton.css +143 -0
- package/styles/Switch.css +60 -0
- package/styles/Tabs.css +94 -0
- package/styles/Textarea.css +66 -0
- package/styles/ToggleButton.css +36 -0
- package/styles/ToggleGroup.css +55 -0
- package/styles/Tooltip.css +34 -0
- package/styles/Tree.css +161 -0
- package/styles/theme/base.css +40 -0
- package/styles/theme/common.css +410 -0
- package/styles/theme/index.css +15 -0
- package/styles/theme/margins.css +119 -0
- package/styles/theme/reset.css +119 -0
- package/styles/theme/tokens.css +226 -0
- package/dist/PuAccordion.d.ts +0 -9
- package/dist/PuButton.d.ts +0 -14
- package/dist/PuButton.jsx +0 -15
- package/dist/PuCheckbox.d.ts +0 -8
- package/dist/PuCheckbox.jsx +0 -13
- package/dist/PuInput.d.ts +0 -10
- package/dist/PuInput.jsx +0 -13
- package/dist/PuMenuItem.d.ts +0 -7
- package/dist/PuMenuItem.jsx +0 -33
- package/dist/PuPopupMenu.d.ts +0 -14
- package/dist/PuSelect.d.ts +0 -17
- package/dist/PuSelect.jsx +0 -24
- package/dist/PuSideMenu.d.ts +0 -4
- package/dist/PuSideMenu.jsx +0 -15
- package/dist/PuSpinner.d.ts +0 -1
- package/dist/PuSpinner.jsx +0 -3
- package/dist/svg-icons.d.ts +0 -5
- package/dist/svg-icons.jsx +0 -30
package/dist/Tooltip.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import "../styles/Tooltip.css";
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
export function Tooltip({ content, position = "top", children, className, delay = 200, }) {
|
|
6
|
+
const [visible, setVisible] = useState(false);
|
|
7
|
+
const [coords, setCoords] = useState({ top: 0, left: 0 });
|
|
8
|
+
const triggerRef = useRef(null);
|
|
9
|
+
const tooltipRef = useRef(null);
|
|
10
|
+
const timeoutRef = useRef(undefined);
|
|
11
|
+
const showTooltip = () => {
|
|
12
|
+
timeoutRef.current = window.setTimeout(() => {
|
|
13
|
+
setVisible(true);
|
|
14
|
+
}, delay);
|
|
15
|
+
};
|
|
16
|
+
const hideTooltip = () => {
|
|
17
|
+
if (timeoutRef.current) {
|
|
18
|
+
clearTimeout(timeoutRef.current);
|
|
19
|
+
}
|
|
20
|
+
setVisible(false);
|
|
21
|
+
};
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (!visible || !triggerRef.current)
|
|
24
|
+
return;
|
|
25
|
+
const trigger = triggerRef.current;
|
|
26
|
+
const rect = trigger.getBoundingClientRect();
|
|
27
|
+
let top = 0;
|
|
28
|
+
let left = 0;
|
|
29
|
+
switch (position) {
|
|
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 }))] }));
|
|
50
|
+
}
|
package/dist/Tree.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import "../styles/Tree.css";
|
|
3
|
+
export interface TreeNode {
|
|
4
|
+
key: string;
|
|
5
|
+
label: ReactNode;
|
|
6
|
+
children?: TreeNode[];
|
|
7
|
+
data?: unknown;
|
|
8
|
+
selectable?: boolean;
|
|
9
|
+
icon?: ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface TreeProps {
|
|
13
|
+
value: TreeNode[];
|
|
14
|
+
selectionMode?: "single" | "checkbox";
|
|
15
|
+
selection?: Record<string, boolean>;
|
|
16
|
+
onSelectionChange?: (selection: Record<string, boolean>) => void;
|
|
17
|
+
expandedKeys?: Record<string, boolean>;
|
|
18
|
+
onExpandedKeysChange?: (keys: Record<string, boolean>) => void;
|
|
19
|
+
nodeTemplate?: (node: TreeNode) => ReactNode;
|
|
20
|
+
className?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function Tree({ value, selectionMode, selection, onSelectionChange, expandedKeys, onExpandedKeysChange, nodeTemplate, className, }: TreeProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/Tree.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { ChevronDown, ChevronRight } from "lucide-react";
|
|
4
|
+
import { useCallback } from "react";
|
|
5
|
+
import "../styles/Tree.css";
|
|
6
|
+
export function Tree({ value, selectionMode, selection = {}, onSelectionChange, expandedKeys = {}, onExpandedKeysChange, nodeTemplate, className, }) {
|
|
7
|
+
const toggleExpand = useCallback((key) => {
|
|
8
|
+
if (onExpandedKeysChange) {
|
|
9
|
+
const newKeys = { ...expandedKeys };
|
|
10
|
+
if (newKeys[key]) {
|
|
11
|
+
delete newKeys[key];
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
newKeys[key] = true;
|
|
15
|
+
}
|
|
16
|
+
onExpandedKeysChange(newKeys);
|
|
17
|
+
}
|
|
18
|
+
}, [expandedKeys, onExpandedKeysChange]);
|
|
19
|
+
const toggleSelect = useCallback((key, node) => {
|
|
20
|
+
if (!onSelectionChange || node.selectable === false)
|
|
21
|
+
return;
|
|
22
|
+
if (selectionMode === "single") {
|
|
23
|
+
onSelectionChange({ [key]: true });
|
|
24
|
+
}
|
|
25
|
+
else if (selectionMode === "checkbox") {
|
|
26
|
+
const newSelection = { ...selection };
|
|
27
|
+
if (newSelection[key]) {
|
|
28
|
+
delete newSelection[key];
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
newSelection[key] = true;
|
|
32
|
+
}
|
|
33
|
+
onSelectionChange(newSelection);
|
|
34
|
+
}
|
|
35
|
+
}, [selection, selectionMode, onSelectionChange]);
|
|
36
|
+
return (_jsx("div", { className: clsx("PaTree", className), children: _jsx("ul", { className: "PaTree-root", children: value.map((node) => (_jsx(TreeNodeItem, { node: node, expandedKeys: expandedKeys, selection: selection, selectionMode: selectionMode, onToggleExpand: toggleExpand, onToggleSelect: toggleSelect, nodeTemplate: nodeTemplate }, node.key))) }) }));
|
|
37
|
+
}
|
|
38
|
+
function TreeNodeItem({ node, expandedKeys, selection, selectionMode, onToggleExpand, onToggleSelect, nodeTemplate, }) {
|
|
39
|
+
const hasChildren = node.children && node.children.length > 0;
|
|
40
|
+
const isExpanded = expandedKeys[node.key];
|
|
41
|
+
const isSelected = selection[node.key];
|
|
42
|
+
return (_jsxs("li", { className: clsx("PaTree-node", node.className), children: [_jsxs("div", { className: clsx("PaTree-nodeContent", isSelected && "selected"), children: [hasChildren ? (_jsx("button", { type: "button", className: "PaTree-toggle", onClick: () => onToggleExpand(node.key), "aria-label": isExpanded ? "Collapse" : "Expand", children: isExpanded ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 }) })) : (_jsx("span", { className: "PaTree-togglePlaceholder" })), selectionMode === "checkbox" && (_jsx("input", { type: "checkbox", className: "PaTree-checkbox", checked: isSelected, onChange: () => onToggleSelect(node.key, node), disabled: node.selectable === false })), selectionMode === "single" && node.selectable !== false ? (_jsxs("button", { type: "button", className: clsx("PaTree-labelWrapper", "selectable"), onClick: () => onToggleSelect(node.key, node), children: [node.icon && _jsx("span", { className: "PaTree-icon", children: node.icon }), nodeTemplate ? nodeTemplate(node) : _jsx("span", { className: "PaTree-label", children: node.label })] })) : (_jsxs("div", { className: "PaTree-labelWrapper", children: [node.icon && _jsx("span", { className: "PaTree-icon", children: node.icon }), nodeTemplate ? nodeTemplate(node) : _jsx("span", { className: "PaTree-label", children: node.label })] }))] }), hasChildren && isExpanded && (_jsx("ul", { className: "PaTree-children", children: node.children?.map((child) => (_jsx(TreeNodeItem, { node: child, expandedKeys: expandedKeys, selection: selection, selectionMode: selectionMode, onToggleExpand: onToggleExpand, onToggleSelect: onToggleSelect, nodeTemplate: nodeTemplate }, child.key))) }))] }));
|
|
43
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactNode, Ref } from "react";
|
|
2
|
+
export type AlertSeverity = "info" | "success" | "warning" | "error";
|
|
3
|
+
export interface ShowAlertOptions {
|
|
4
|
+
severity?: AlertSeverity;
|
|
5
|
+
autoDismiss?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface AlertStackHandle {
|
|
8
|
+
showAlert: (message: string, options?: ShowAlertOptions) => void;
|
|
9
|
+
showError: (error: unknown) => void;
|
|
10
|
+
}
|
|
11
|
+
interface AlertStackProviderProps {
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
ref?: Ref<AlertStackHandle>;
|
|
14
|
+
}
|
|
15
|
+
export declare function AlertStackProvider({ children, ref }: AlertStackProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export declare function useAlertStack(): AlertStackHandle;
|
|
17
|
+
export declare function AlertStack(): import("react/jsx-runtime").JSX.Element | null;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { messageOf } from "@paroicms/public-anywhere-lib";
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useImperativeHandle, useReducer, useRef, } from "react";
|
|
4
|
+
import { Alert } from "./Alert.js";
|
|
5
|
+
import { useReactUIConfig } from "./react-ui-provider.js";
|
|
6
|
+
const AlertStackContext = createContext(undefined);
|
|
7
|
+
export function AlertStackProvider({ children, ref }) {
|
|
8
|
+
const { logger } = useReactUIConfig();
|
|
9
|
+
const queue = useRef([]);
|
|
10
|
+
const idSeq = useRef(0);
|
|
11
|
+
const [renderCount, forceRender] = useReducer((x) => x + 1, 0);
|
|
12
|
+
const showAlert = useCallback((message, options) => {
|
|
13
|
+
const alert = {
|
|
14
|
+
id: ++idSeq.current,
|
|
15
|
+
message,
|
|
16
|
+
severity: options?.severity ?? "info",
|
|
17
|
+
autoDismiss: options?.autoDismiss ?? false,
|
|
18
|
+
};
|
|
19
|
+
queue.current.push(alert);
|
|
20
|
+
forceRender();
|
|
21
|
+
}, []);
|
|
22
|
+
const dismissCurrent = useCallback(() => {
|
|
23
|
+
queue.current.shift();
|
|
24
|
+
forceRender();
|
|
25
|
+
}, []);
|
|
26
|
+
const showError = useCallback((error) => {
|
|
27
|
+
logger.error("AlertStack caught error:", error);
|
|
28
|
+
showAlert(messageOf(error), { severity: "error" });
|
|
29
|
+
}, [showAlert]);
|
|
30
|
+
useImperativeHandle(ref, () => ({ showAlert, showError }), [showAlert, showError]);
|
|
31
|
+
const contextValue = {
|
|
32
|
+
showAlert,
|
|
33
|
+
queue: queue.current,
|
|
34
|
+
dismissCurrent,
|
|
35
|
+
};
|
|
36
|
+
// renderCount is used to ensure context value updates trigger re-renders
|
|
37
|
+
void renderCount;
|
|
38
|
+
return _jsx(AlertStackContext.Provider, { value: contextValue, children: children });
|
|
39
|
+
}
|
|
40
|
+
export function useAlertStack() {
|
|
41
|
+
const context = useContext(AlertStackContext);
|
|
42
|
+
if (!context) {
|
|
43
|
+
throw new Error("useAlertStack must be used within an AlertStackProvider");
|
|
44
|
+
}
|
|
45
|
+
const showError = useCallback((error) => {
|
|
46
|
+
context.showAlert(messageOf(error), { severity: "error" });
|
|
47
|
+
}, [context.showAlert]);
|
|
48
|
+
return { showAlert: context.showAlert, showError };
|
|
49
|
+
}
|
|
50
|
+
export function AlertStack() {
|
|
51
|
+
const context = useContext(AlertStackContext);
|
|
52
|
+
const config = useReactUIConfig();
|
|
53
|
+
if (!context) {
|
|
54
|
+
throw new Error("AlertStack must be used within an AlertStackProvider");
|
|
55
|
+
}
|
|
56
|
+
const { queue, dismissCurrent } = context;
|
|
57
|
+
const currentAlert = queue[0];
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (!currentAlert?.autoDismiss)
|
|
60
|
+
return;
|
|
61
|
+
const timer = setTimeout(dismissCurrent, config.autoDismissAlertDurationMs);
|
|
62
|
+
return () => clearTimeout(timer);
|
|
63
|
+
}, [
|
|
64
|
+
currentAlert?.id,
|
|
65
|
+
currentAlert?.autoDismiss,
|
|
66
|
+
config.autoDismissAlertDurationMs,
|
|
67
|
+
dismissCurrent,
|
|
68
|
+
]);
|
|
69
|
+
if (!currentAlert)
|
|
70
|
+
return null;
|
|
71
|
+
return (_jsx(Alert, { severity: currentAlert.severity, onClose: dismissCurrent, children: currentAlert.message }));
|
|
72
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,37 @@
|
|
|
1
|
-
import "../styles/index.
|
|
2
|
-
export * from "./
|
|
3
|
-
export * from "./
|
|
4
|
-
export * from "./
|
|
5
|
-
export * from "./
|
|
6
|
-
export * from "./
|
|
7
|
-
export * from "./
|
|
8
|
-
export * from "./
|
|
9
|
-
export * from "./
|
|
10
|
-
export * from "./
|
|
1
|
+
import "../styles/theme/index.css";
|
|
2
|
+
export * from "./Checkbox.js";
|
|
3
|
+
export * from "./DateInput.js";
|
|
4
|
+
export * from "./InputNumber.js";
|
|
5
|
+
export * from "./InputText.js";
|
|
6
|
+
export * from "./MultiSelect.js";
|
|
7
|
+
export * from "./PasswordInput.js";
|
|
8
|
+
export * from "./RadioButton.js";
|
|
9
|
+
export * from "./Select.js";
|
|
10
|
+
export * from "./Switch.js";
|
|
11
|
+
export * from "./Textarea.js";
|
|
12
|
+
export * from "./ToggleGroup.js";
|
|
13
|
+
export * from "./Button.js";
|
|
14
|
+
export * from "./SplitButton.js";
|
|
15
|
+
export * from "./ToggleButton.js";
|
|
16
|
+
export * from "./Alert.js";
|
|
17
|
+
export * from "./Badge.js";
|
|
18
|
+
export * from "./Card.js";
|
|
19
|
+
export * from "./Chip.js";
|
|
20
|
+
export * from "./Column.js";
|
|
21
|
+
export * from "./DataTable.js";
|
|
22
|
+
export * from "./Breadcrumb.js";
|
|
23
|
+
export * from "./MenuItem.js";
|
|
24
|
+
export * from "./PopupMenu.js";
|
|
25
|
+
export * from "./SideMenu.js";
|
|
26
|
+
export * from "./Tabs.js";
|
|
27
|
+
export * from "./Dialog.js";
|
|
28
|
+
export * from "./Spinner.js";
|
|
29
|
+
export * from "./Tooltip.js";
|
|
30
|
+
export * from "./Accordion.js";
|
|
31
|
+
export * from "./Inplace.js";
|
|
32
|
+
export * from "./Panel.js";
|
|
33
|
+
export * from "./Tree.js";
|
|
34
|
+
export * from "./SortableList.js";
|
|
35
|
+
export * from "./alert-stack.js";
|
|
36
|
+
export * from "./react-ui-provider.js";
|
|
11
37
|
export type * from "./paroi-ui-lib-types.js";
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,45 @@
|
|
|
1
|
-
import "../styles/index.
|
|
2
|
-
|
|
3
|
-
export * from "./
|
|
4
|
-
export * from "./
|
|
5
|
-
export * from "./
|
|
6
|
-
export * from "./
|
|
7
|
-
export * from "./
|
|
8
|
-
export * from "./
|
|
9
|
-
export * from "./
|
|
10
|
-
export * from "./
|
|
1
|
+
import "../styles/theme/index.css";
|
|
2
|
+
// Form Controls
|
|
3
|
+
export * from "./Checkbox.js";
|
|
4
|
+
export * from "./DateInput.js";
|
|
5
|
+
export * from "./InputNumber.js";
|
|
6
|
+
export * from "./InputText.js";
|
|
7
|
+
export * from "./MultiSelect.js";
|
|
8
|
+
export * from "./PasswordInput.js";
|
|
9
|
+
export * from "./RadioButton.js";
|
|
10
|
+
export * from "./Select.js";
|
|
11
|
+
export * from "./Switch.js";
|
|
12
|
+
export * from "./Textarea.js";
|
|
13
|
+
export * from "./ToggleGroup.js";
|
|
14
|
+
// Buttons
|
|
15
|
+
export * from "./Button.js";
|
|
16
|
+
export * from "./SplitButton.js";
|
|
17
|
+
export * from "./ToggleButton.js";
|
|
18
|
+
// Data Display
|
|
19
|
+
export * from "./Alert.js";
|
|
20
|
+
export * from "./Badge.js";
|
|
21
|
+
export * from "./Card.js";
|
|
22
|
+
export * from "./Chip.js";
|
|
23
|
+
export * from "./Column.js";
|
|
24
|
+
export * from "./DataTable.js";
|
|
25
|
+
// Navigation
|
|
26
|
+
export * from "./Breadcrumb.js";
|
|
27
|
+
export * from "./MenuItem.js";
|
|
28
|
+
export * from "./PopupMenu.js";
|
|
29
|
+
export * from "./SideMenu.js";
|
|
30
|
+
export * from "./Tabs.js";
|
|
31
|
+
// Overlays & Feedback
|
|
32
|
+
export * from "./Dialog.js";
|
|
33
|
+
export * from "./Spinner.js";
|
|
34
|
+
export * from "./Tooltip.js";
|
|
35
|
+
// Layout
|
|
36
|
+
export * from "./Accordion.js";
|
|
37
|
+
export * from "./Inplace.js";
|
|
38
|
+
export * from "./Panel.js";
|
|
39
|
+
// Tree
|
|
40
|
+
export * from "./Tree.js";
|
|
41
|
+
// Drag & Drop
|
|
42
|
+
export * from "./SortableList.js";
|
|
43
|
+
// Providers
|
|
44
|
+
export * from "./alert-stack.js";
|
|
45
|
+
export * from "./react-ui-provider.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CSSProperties, ReactNode } from "react";
|
|
2
|
-
export interface
|
|
2
|
+
export interface MenuOption {
|
|
3
3
|
/**
|
|
4
4
|
* Unique identifier of the menuitem.
|
|
5
5
|
*/
|
|
@@ -32,14 +32,14 @@ export interface PuMenuOption {
|
|
|
32
32
|
* Callback to execute when item is clicked.
|
|
33
33
|
*/
|
|
34
34
|
command?(): void;
|
|
35
|
-
popupMenu?:
|
|
35
|
+
popupMenu?: MenuNode[];
|
|
36
36
|
active?: boolean;
|
|
37
37
|
}
|
|
38
|
-
export interface
|
|
38
|
+
export interface MenuNode extends MenuOption {
|
|
39
39
|
/**
|
|
40
40
|
* An array of child menu items.
|
|
41
41
|
*/
|
|
42
|
-
subMenu?:
|
|
42
|
+
subMenu?: MenuNode[];
|
|
43
43
|
/**
|
|
44
44
|
* Initial visibility of submenu.
|
|
45
45
|
*/
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface ReactUIConfig {
|
|
3
|
+
autoDismissAlertDurationMs?: number;
|
|
4
|
+
autoDismissInsideFeedbackDurationMs?: number;
|
|
5
|
+
logger?: {
|
|
6
|
+
error: (...messages: unknown[]) => void;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
interface ReactUIProviderProps {
|
|
10
|
+
config?: ReactUIConfig;
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
export declare function ReactUIProvider({ config, children }: ReactUIProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare function useReactUIConfig(): Required<ReactUIConfig>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext } from "react";
|
|
3
|
+
const ReactUIContext = createContext(undefined);
|
|
4
|
+
const defaultConfig = {
|
|
5
|
+
autoDismissAlertDurationMs: 5000,
|
|
6
|
+
autoDismissInsideFeedbackDurationMs: 2000,
|
|
7
|
+
logger: {
|
|
8
|
+
error: console.error,
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
export function ReactUIProvider({ config, children }) {
|
|
12
|
+
return _jsx(ReactUIContext.Provider, { value: config, children: children });
|
|
13
|
+
}
|
|
14
|
+
export function useReactUIConfig() {
|
|
15
|
+
const config = useContext(ReactUIContext);
|
|
16
|
+
return {
|
|
17
|
+
autoDismissAlertDurationMs: config?.autoDismissAlertDurationMs ?? defaultConfig.autoDismissAlertDurationMs,
|
|
18
|
+
autoDismissInsideFeedbackDurationMs: config?.autoDismissInsideFeedbackDurationMs ??
|
|
19
|
+
defaultConfig.autoDismissInsideFeedbackDurationMs,
|
|
20
|
+
logger: config?.logger ?? defaultConfig.logger,
|
|
21
|
+
};
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paroicms/react-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "React UI toolkit for ParoiCMS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"paroicms",
|
|
@@ -19,19 +19,33 @@
|
|
|
19
19
|
"main": "dist/index.js",
|
|
20
20
|
"typings": "dist/index.d.ts",
|
|
21
21
|
"scripts": {
|
|
22
|
+
"tsc": "tsc",
|
|
22
23
|
"build": "tsc",
|
|
23
24
|
"clear": "rimraf dist/*",
|
|
24
25
|
"dev": "tsc --watch --preserveWatchOutput"
|
|
25
26
|
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@paroicms/public-anywhere-lib": "0.41.0",
|
|
29
|
+
"clsx": "~2.1.1",
|
|
30
|
+
"lucide-react": "~0.562.0",
|
|
31
|
+
"react-sortablejs": "~6.1.4",
|
|
32
|
+
"sortablejs": "~1.15.6"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": ">=18.0.0",
|
|
36
|
+
"react-dom": ">=18.0.0"
|
|
37
|
+
},
|
|
26
38
|
"devDependencies": {
|
|
27
39
|
"@types/react": "~19.2.7",
|
|
28
40
|
"@types/react-dom": "~19.2.3",
|
|
41
|
+
"@types/sortablejs": "^1.15.8",
|
|
29
42
|
"react": "~19.2.0",
|
|
30
43
|
"react-dom": "~19.2.0",
|
|
31
44
|
"rimraf": "~6.1.2",
|
|
32
45
|
"typescript": "~5.9.3"
|
|
33
46
|
},
|
|
34
47
|
"files": [
|
|
35
|
-
"dist"
|
|
48
|
+
"dist",
|
|
49
|
+
"styles"
|
|
36
50
|
]
|
|
37
51
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* ========================================
|
|
2
|
+
Accordion / Collapsible
|
|
3
|
+
======================================== */
|
|
4
|
+
.PaAccordion-content {
|
|
5
|
+
padding-left: 20px;
|
|
6
|
+
transition: max-height 200ms ease-out;
|
|
7
|
+
|
|
8
|
+
&.transition {
|
|
9
|
+
overflow: hidden;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
&.hide {
|
|
13
|
+
display: none;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.PaAccordion-header {
|
|
18
|
+
display: flex;
|
|
19
|
+
gap: var(--space-3);
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: space-between;
|
|
22
|
+
padding: var(--space-4) var(--space-5);
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
background: var(--color-bg-subtle);
|
|
25
|
+
transition: background-color var(--transition);
|
|
26
|
+
|
|
27
|
+
/* &:hover {
|
|
28
|
+
background: var(--color-bg-section);
|
|
29
|
+
} */
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.PaAccordion-title {
|
|
33
|
+
font-size: var(--text-base);
|
|
34
|
+
font-weight: var(--font-medium);
|
|
35
|
+
color: var(--color-text);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.PaAccordion-chevron {
|
|
39
|
+
flex-shrink: 0;
|
|
40
|
+
color: var(--color-text-light);
|
|
41
|
+
transition: transform var(--transition);
|
|
42
|
+
|
|
43
|
+
.PaAccordion.open & {
|
|
44
|
+
transform: rotate(180deg);
|
|
45
|
+
}
|
|
46
|
+
}
|
package/styles/Alert.css
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* ========================================
|
|
2
|
+
Alert / Notice Box
|
|
3
|
+
======================================== */
|
|
4
|
+
.PaAlert {
|
|
5
|
+
position: relative;
|
|
6
|
+
padding: var(--space-4) var(--space-5);
|
|
7
|
+
border-left: 4px solid;
|
|
8
|
+
border-radius: var(--radius);
|
|
9
|
+
|
|
10
|
+
&.dismissible {
|
|
11
|
+
padding-right: var(--space-10);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
&.info {
|
|
15
|
+
background: var(--color-info-light);
|
|
16
|
+
border-color: var(--color-info);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
&.primary {
|
|
20
|
+
background: var(--color-primary-light);
|
|
21
|
+
border-color: var(--color-primary);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&.success {
|
|
25
|
+
background: var(--color-success-light);
|
|
26
|
+
border-color: var(--color-success);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&.warning {
|
|
30
|
+
background: var(--color-yellow-light);
|
|
31
|
+
border-color: var(--color-yellow);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
&.error {
|
|
35
|
+
background: var(--color-danger-light);
|
|
36
|
+
border-color: var(--color-danger);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.PaAlert-closeBtn {
|
|
41
|
+
position: absolute;
|
|
42
|
+
top: var(--space-3);
|
|
43
|
+
right: var(--space-3);
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
justify-content: center;
|
|
47
|
+
padding: var(--space-1);
|
|
48
|
+
color: var(--color-text-muted);
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
background: transparent;
|
|
51
|
+
border: none;
|
|
52
|
+
border-radius: var(--radius-sm);
|
|
53
|
+
transition:
|
|
54
|
+
color 0.15s,
|
|
55
|
+
background-color 0.15s;
|
|
56
|
+
|
|
57
|
+
&:hover {
|
|
58
|
+
color: var(--color-text);
|
|
59
|
+
background: rgb(0 0 0 / 10%);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.PaAlert-title {
|
|
64
|
+
margin-bottom: var(--space-2);
|
|
65
|
+
font-size: var(--text-sm);
|
|
66
|
+
font-weight: var(--font-semibold);
|
|
67
|
+
color: var(--color-text);
|
|
68
|
+
text-transform: uppercase;
|
|
69
|
+
letter-spacing: 0.025em;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.PaAlert-content {
|
|
73
|
+
font-size: var(--text-sm);
|
|
74
|
+
line-height: 1.7;
|
|
75
|
+
color: var(--color-text);
|
|
76
|
+
}
|
package/styles/Badge.css
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* ========================================
|
|
2
|
+
Badges / Pills
|
|
3
|
+
======================================== */
|
|
4
|
+
.PaBadge {
|
|
5
|
+
display: inline-flex;
|
|
6
|
+
gap: var(--space-1);
|
|
7
|
+
align-items: center;
|
|
8
|
+
padding: var(--space-1) var(--space-2);
|
|
9
|
+
font-size: var(--text-xs);
|
|
10
|
+
font-weight: var(--font-medium);
|
|
11
|
+
border-radius: var(--radius-full);
|
|
12
|
+
|
|
13
|
+
&.default {
|
|
14
|
+
color: var(--color-text-muted);
|
|
15
|
+
background: var(--color-bg-subtle);
|
|
16
|
+
border: 1px solid var(--color-border);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
&.primary {
|
|
20
|
+
color: var(--color-primary-dark);
|
|
21
|
+
background: var(--color-primary-light);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&.accent {
|
|
25
|
+
color: var(--color-accent-dark);
|
|
26
|
+
background: var(--color-accent-light);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&.success {
|
|
30
|
+
color: var(--color-success-dark);
|
|
31
|
+
background: var(--color-success-light);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
&.warning {
|
|
35
|
+
color: var(--color-yellow-dark);
|
|
36
|
+
background: var(--color-yellow-light);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
&.danger {
|
|
40
|
+
color: var(--color-danger-dark);
|
|
41
|
+
background: var(--color-danger-light);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&.info {
|
|
45
|
+
color: var(--color-primary-dark);
|
|
46
|
+
background: var(--color-primary-subtle);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&.secondary {
|
|
50
|
+
color: var(--color-text-light);
|
|
51
|
+
background: var(--color-bg-muted);
|
|
52
|
+
border: 1px solid var(--color-border-light);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&.contrast {
|
|
56
|
+
color: var(--color-text-inverse);
|
|
57
|
+
background: var(--color-text);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/* ========================================
|
|
2
|
+
Breadcrumb
|
|
3
|
+
======================================== */
|
|
4
|
+
.PaBreadcrumb {
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-wrap: wrap;
|
|
7
|
+
gap: var(--space-1);
|
|
8
|
+
align-items: center;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.PaBreadcrumb-item {
|
|
12
|
+
display: flex;
|
|
13
|
+
gap: var(--space-1);
|
|
14
|
+
align-items: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.PaBreadcrumb-link {
|
|
18
|
+
max-width: 150px;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
text-overflow: ellipsis;
|
|
21
|
+
font-size: var(--text-sm);
|
|
22
|
+
color: var(--color-text-muted);
|
|
23
|
+
white-space: nowrap;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.PaBreadcrumb-link:is(a, button) {
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
transition: color var(--transition);
|
|
29
|
+
|
|
30
|
+
&:hover {
|
|
31
|
+
color: var(--color-primary);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.PaBreadcrumb-separator {
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
height: 100%;
|
|
39
|
+
padding: 0 var(--space-1);
|
|
40
|
+
font-size: var(--text-xs);
|
|
41
|
+
color: var(--color-text-light);
|
|
42
|
+
|
|
43
|
+
svg {
|
|
44
|
+
width: 16px;
|
|
45
|
+
height: 16px;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.PaBreadcrumb-current {
|
|
50
|
+
max-width: 200px;
|
|
51
|
+
overflow: hidden;
|
|
52
|
+
text-overflow: ellipsis;
|
|
53
|
+
font-size: var(--text-sm);
|
|
54
|
+
font-weight: var(--font-medium);
|
|
55
|
+
color: var(--color-text);
|
|
56
|
+
white-space: nowrap;
|
|
57
|
+
}
|