@hitachivantara/uikit-react-lab
Version:
Contributed React components to UI Kit by the community.
375 lines (374 loc) • 10.5 kB
JavaScript
import { useCallback, useMemo, useRef, useState } from "react";
import { HvButton, HvCheckBox, HvColorPicker, HvDialogContent, HvDialogTitle, HvIconButton, HvListItem, HvMultiButton, HvSelectionList, theme } from "@hitachivantara/uikit-react-core";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { NodeResizer, NodeToolbar, Position, useReactFlow } from "reactflow";
import { ActualSize, Bold, Delete, FontSize, Fullscreen, Italic, Palette } from "@hitachivantara/uikit-react-icons";
import { css, cx } from "@emotion/css";
import Popover from "@mui/material/Popover";
//#region src/Flow/nodes/StickyNode.tsx
var defaultData = {
title: "Sticky Note",
backgroundColor: theme.colors.warningSubtle,
borderColor: theme.colors.warningSubtle,
textColor: theme.colors.text,
hasShadow: true,
bold: false,
italic: false,
fontSize: 14,
expanded: true,
visible: true
};
var classes = {
root: css({
width: "100%",
height: "100%",
position: "relative",
display: "flex",
outline: "none"
}),
nodeToolbar: css({
backgroundColor: "transparent",
borderRadius: theme.radii.full,
top: 10
}),
buttonsContainer: css({ padding: theme.space.xs }),
textAreaRoot: css({
flex: 1,
width: "100%",
border: "none",
background: "transparent",
outline: "none"
}),
textAreaInput: css({
resize: "none",
height: "100%",
width: "100%",
padding: theme.space.xs,
"&:focus-visible": { outline: "none" },
paddingRight: 32
}),
textAreaInputFolded: css({
resize: "none",
width: "100%",
padding: 0,
border: "none",
overflow: "hidden",
minHeight: "1.5rem",
height: "auto"
}),
colorConfig: css({
display: "flex",
flexDirection: "column",
gap: theme.space.sm
}),
folded: css({
width: 34,
height: 34
}),
expandButton: css({
position: "absolute",
top: theme.space.xxs,
right: theme.space.xxs
}),
fontSizes: css({
maxHeight: 160,
overflowY: "auto",
padding: theme.space.xs
})
};
var colorsToConfig = [
"textColor",
"backgroundColor",
"borderColor"
];
var fontSizes = [
10,
11,
12,
14,
16,
20,
24,
32,
36,
40,
48,
64,
96,
128
];
var StickyNode = ({ id, selected, data = {} }) => {
const mergedData = useMemo(() => ({
...defaultData,
...data
}), [data]);
const [text, setText] = useState("");
const { setNodes } = useReactFlow();
const [editing, setEditing] = useState(false);
const [toolbarVisible, setToolbarVisible] = useState(false);
const [colorsConfigOpen, setColorsConfigOpen] = useState(false);
const [fontSizeConfigOpen, setFontSizeConfigOpen] = useState(false);
const [fontSize, setFontSize] = useState(mergedData.fontSize ?? 14);
const colorConfigBtnRef = useRef(null);
const fontSizeConfigBtnRef = useRef(null);
const handleToggleBold = useCallback(() => {
setNodes((nds) => nds.map((node) => {
if (node.id === id) node.data = {
...node.data,
bold: !node.data?.bold
};
return node;
}));
}, [setNodes, id]);
const handleToggleItalic = useCallback(() => {
setNodes((nds) => nds.map((node) => {
if (node.id === id) node.data = {
...node.data,
italic: !node.data?.italic
};
return node;
}));
}, [setNodes, id]);
const handleChangeFontSize = useCallback((size) => {
setFontSize(size);
setNodes((nds) => nds.map((node) => {
if (node.id === id) node.data = {
...node.data,
fontSize: size
};
return node;
}));
setFontSizeConfigOpen(false);
}, [setNodes, id]);
const handleToggleExpand = useCallback(() => {
setNodes((nds) => nds.map((node) => {
if (node.id === id) node.data = {
...node.data,
expanded: !node.data?.expanded
};
return node;
}));
}, [setNodes, id]);
const handleResetColors = useCallback(() => {
setNodes((nds) => nds.map((node) => {
if (node.id === id) node.data = {
...node.data,
backgroundColor: defaultData.backgroundColor,
borderColor: defaultData.borderColor,
textColor: defaultData.textColor,
hasShadow: defaultData.hasShadow
};
return node;
}));
}, [setNodes, id]);
const handleDeleteSticky = useCallback(() => {
setNodes((nds) => nds.filter((node) => node.id !== id));
mergedData.onDelete?.();
}, [
mergedData,
setNodes,
id
]);
if (!mergedData.visible) return null;
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsxs(Popover, {
open: colorsConfigOpen,
anchorEl: colorConfigBtnRef.current,
onClose: () => {
setColorsConfigOpen(false);
setEditing(false);
},
anchorOrigin: {
vertical: "bottom",
horizontal: "left"
},
transformOrigin: {
vertical: "top",
horizontal: "left"
},
children: [/* @__PURE__ */ jsx(HvDialogTitle, { children: "Customize Colors" }), /* @__PURE__ */ jsx(HvDialogContent, { children: /* @__PURE__ */ jsxs("div", {
className: classes.colorConfig,
children: [
colorsToConfig.map((c) => /* @__PURE__ */ jsx(HvColorPicker, {
label: `${c.charAt(0).toUpperCase() + c.slice(1).replace("Color", " Color")}`,
value: mergedData[c] ?? "",
onChange: (color) => {
setNodes((nds) => nds.map((node) => {
if (node.id === id) node.data = {
...node.data,
[c]: color
};
return node;
}));
}
}, c)),
/* @__PURE__ */ jsx(HvCheckBox, {
label: "Drop Shadow",
defaultChecked: mergedData.hasShadow,
onChange: (_, checked) => {
setNodes((nds) => nds.map((node) => {
if (node.id === id) node.data = {
...node.data,
hasShadow: checked
};
return node;
}));
}
}),
/* @__PURE__ */ jsx(HvButton, {
variant: "secondarySubtle",
onClick: handleResetColors,
children: "Reset to defaults"
})
]
}) })]
}),
/* @__PURE__ */ jsx(Popover, {
open: fontSizeConfigOpen,
anchorEl: fontSizeConfigBtnRef.current,
onClose: () => {
setFontSizeConfigOpen(false);
setEditing(false);
},
anchorOrigin: {
vertical: "bottom",
horizontal: "right"
},
transformOrigin: {
vertical: "top",
horizontal: "right"
},
children: /* @__PURE__ */ jsx(HvSelectionList, {
className: classes.fontSizes,
value: fontSize,
onChange: (evt, newValue) => {
handleChangeFontSize(newValue);
},
children: fontSizes.map((size) => /* @__PURE__ */ jsx(HvListItem, {
value: size,
children: size
}, size))
})
}),
/* @__PURE__ */ jsxs("div", {
className: cx(classes.root, "nowheel", !mergedData.expanded && classes.folded),
style: {
backgroundColor: mergedData.backgroundColor ?? theme.colors.bgContainer,
boxShadow: mergedData.hasShadow ? "0 8px 12px rgba(65,65,65,0.25)" : "none",
border: mergedData.borderColor ? `1px solid ${mergedData.borderColor}` : "none",
fontSize: `${mergedData.fontSize ?? 14}px`,
lineHeight: `${mergedData.fontSize ?? 14}px`
},
children: [mergedData.expanded && /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(NodeResizer, {
isVisible: selected,
minWidth: 100,
minHeight: 75,
lineStyle: {
color: theme.colors.primary,
borderStyle: "solid"
},
handleStyle: {
width: 6,
height: 6,
border: `1px solid ${theme.colors.primary}`,
backgroundColor: mergedData.backgroundColor ?? "transparent",
borderRadius: theme.radii.full
}
}),
/* @__PURE__ */ jsx(NodeToolbar, {
isVisible: editing || toolbarVisible || selected,
position: Position.Top,
className: classes.nodeToolbar,
onMouseEnter: () => setToolbarVisible(true),
onMouseLeave: () => setToolbarVisible(false),
children: /* @__PURE__ */ jsx("div", {
className: classes.buttonsContainer,
children: /* @__PURE__ */ jsxs(HvMultiButton, { children: [
/* @__PURE__ */ jsx(HvIconButton, {
"aria-label": "Font Size",
title: "Font Size",
ref: fontSizeConfigBtnRef,
onClick: () => {
setEditing(true);
setFontSizeConfigOpen(true);
},
children: /* @__PURE__ */ jsx(FontSize, {})
}),
/* @__PURE__ */ jsx(HvIconButton, {
"aria-label": "Bold",
title: "Bold",
selected: mergedData.bold,
onClick: handleToggleBold,
children: /* @__PURE__ */ jsx(Bold, {})
}),
/* @__PURE__ */ jsx(HvIconButton, {
"aria-label": "Italic",
title: "Italic",
selected: mergedData.italic,
onClick: handleToggleItalic,
children: /* @__PURE__ */ jsx(Italic, {})
}),
/* @__PURE__ */ jsx(HvIconButton, {
"aria-label": "Customize Colors",
title: "Customize Colors",
ref: colorConfigBtnRef,
onClick: () => {
setEditing(true);
setColorsConfigOpen(true);
},
children: /* @__PURE__ */ jsx(Palette, {})
}),
/* @__PURE__ */ jsx(HvIconButton, {
"aria-label": "Delete",
title: "Delete",
onClick: handleDeleteSticky,
children: /* @__PURE__ */ jsx(Delete, {})
})
] })
})
}),
/* @__PURE__ */ jsxs("div", {
onMouseEnter: () => setToolbarVisible(true),
onMouseLeave: () => setToolbarVisible(false),
className: classes.textAreaRoot,
children: [/* @__PURE__ */ jsx(HvIconButton, {
className: classes.expandButton,
title: "Fold",
onClick: handleToggleExpand,
children: /* @__PURE__ */ jsx(ActualSize, {})
}), /* @__PURE__ */ jsx("textarea", {
id: `sticky-textarea-${id}`,
value: text || "",
onChange: (e) => setText(e.target.value),
className: classes.textAreaInput,
placeholder: "Type here...",
style: {
color: mergedData.textColor ?? theme.colors.text,
fontWeight: mergedData.bold ? "bold" : "normal",
fontStyle: mergedData.italic ? "italic" : "normal",
fontSize: mergedData.fontSize ?? "14px"
},
onFocus: () => setEditing(true),
onBlur: () => {
setEditing(false);
setColorsConfigOpen(false);
}
})]
})
] }), !mergedData.expanded && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(HvIconButton, {
title: /* @__PURE__ */ jsx("span", {
style: {
whiteSpace: "pre-wrap",
wordBreak: "break-word"
},
children: text
}),
onClick: handleToggleExpand,
children: /* @__PURE__ */ jsx(Fullscreen, {})
}) })]
})
] });
};
//#endregion
export { StickyNode };