@hitachivantara/uikit-react-lab 6.0.0-next.1 → 6.0.0-next.3

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.
@@ -1,4 +1,4 @@
1
- import { useNodeId as useNodeId$1 } from "@xyflow/react";
1
+ import { useNodeId as useNodeId$1 } from "reactflow";
2
2
  function useNodeId(id) {
3
3
  const currentNodeId = useNodeId$1();
4
4
  return id ?? currentNodeId;
@@ -0,0 +1,89 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useLabels, HvDialog, HvDialogTitle, HvDialogContent, HvEmptyState, HvDialogActions, HvButton } from "@hitachivantara/uikit-react-core";
3
+ import { Info } from "@hitachivantara/uikit-react-icons";
4
+ import { useClasses } from "./DashboardNode.styles.js";
5
+ import { staticClasses } from "./DashboardNode.styles.js";
6
+ import { HvFlowNode } from "../Node/Node.js";
7
+ import { HvDashboard } from "../../Dashboard/Dashboard.js";
8
+ const DEFAULT_LABELS = {
9
+ emptyMessage: "No visualizations connected to the dashboard.",
10
+ dialogTitle: "Configure dashboard",
11
+ dialogSubtitle: "Please configure the layout of your dashboard as needed.",
12
+ dialogApply: "Apply",
13
+ dialogCancel: "Cancel"
14
+ };
15
+ const HvDashboardNode = (props) => {
16
+ const {
17
+ id,
18
+ open,
19
+ layout,
20
+ labels: labelsProp,
21
+ classes: classesProp,
22
+ previewItems,
23
+ children,
24
+ dialogProps,
25
+ dashboardProps,
26
+ onApply,
27
+ onCancel,
28
+ onClose,
29
+ ...others
30
+ } = props;
31
+ const labels = useLabels(DEFAULT_LABELS, labelsProp);
32
+ const { classes } = useClasses(classesProp);
33
+ return /* @__PURE__ */ jsxs(
34
+ HvFlowNode,
35
+ {
36
+ id,
37
+ classes,
38
+ labels,
39
+ ...others,
40
+ children: [
41
+ children,
42
+ /* @__PURE__ */ jsxs(
43
+ HvDialog,
44
+ {
45
+ open,
46
+ maxWidth: "lg",
47
+ fullWidth: true,
48
+ onClose,
49
+ ...dialogProps,
50
+ children: [
51
+ /* @__PURE__ */ jsx(HvDialogTitle, { variant: "info", children: labels?.dialogTitle }),
52
+ /* @__PURE__ */ jsxs(HvDialogContent, { indentContent: true, children: [
53
+ labels?.dialogSubtitle,
54
+ layout && layout?.length > 0 ? /* @__PURE__ */ jsx(
55
+ HvDashboard,
56
+ {
57
+ cols: 12,
58
+ layout,
59
+ compactType: "vertical",
60
+ rowHeight: 80,
61
+ margin: [16, 16],
62
+ containerPadding: [0, 16],
63
+ ...dashboardProps,
64
+ children: previewItems
65
+ }
66
+ ) : /* @__PURE__ */ jsx(
67
+ HvEmptyState,
68
+ {
69
+ className: classes.empty,
70
+ icon: /* @__PURE__ */ jsx(Info, {}),
71
+ message: labels?.emptyMessage
72
+ }
73
+ )
74
+ ] }),
75
+ /* @__PURE__ */ jsxs(HvDialogActions, { children: [
76
+ /* @__PURE__ */ jsx(HvButton, { variant: "primary", onClick: onApply, children: labels?.dialogApply }),
77
+ /* @__PURE__ */ jsx(HvButton, { variant: "secondarySubtle", onClick: onCancel, children: labels?.dialogCancel })
78
+ ] })
79
+ ]
80
+ }
81
+ )
82
+ ]
83
+ }
84
+ );
85
+ };
86
+ export {
87
+ HvDashboardNode,
88
+ staticClasses as hvDashboardNodeClasses
89
+ };
@@ -0,0 +1,16 @@
1
+ import { createClasses, theme } from "@hitachivantara/uikit-react-core";
2
+ import { staticClasses as staticClasses$1 } from "../Node/Node.styles.js";
3
+ const baseClasses = Object.fromEntries(
4
+ Object.keys(staticClasses$1).map((key) => [key, {}])
5
+ );
6
+ const { staticClasses, useClasses } = createClasses("HvDashboardNode", {
7
+ empty: {
8
+ padding: theme.spacing("sm", 0, 0, 0)
9
+ },
10
+ // Spread here to know if we are overriding classes from parents
11
+ ...baseClasses
12
+ });
13
+ export {
14
+ staticClasses,
15
+ useClasses
16
+ };
@@ -0,0 +1,439 @@
1
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
+ import { useMemo, useState, useRef, useCallback } from "react";
3
+ import { css, cx } from "@emotion/css";
4
+ import Popover from "@mui/material/Popover";
5
+ import { useReactFlow, NodeResizer, NodeToolbar, Position } from "reactflow";
6
+ import { theme, HvDialogTitle, HvDialogContent, HvColorPicker, HvCheckBox, HvButton, HvSelectionList, HvListItem, HvMultiButton, HvIconButton } from "@hitachivantara/uikit-react-core";
7
+ import { FontSize, Bold, Italic, Palette, Delete, ActualSize, Fullscreen } from "@hitachivantara/uikit-react-icons";
8
+ const defaultData = {
9
+ title: "Sticky Note",
10
+ backgroundColor: theme.colors.warningSubtle,
11
+ borderColor: theme.colors.warningSubtle,
12
+ textColor: theme.colors.text,
13
+ hasShadow: true,
14
+ bold: false,
15
+ italic: false,
16
+ fontSize: 14,
17
+ expanded: true,
18
+ visible: true
19
+ };
20
+ const classes = {
21
+ root: css({
22
+ width: "100%",
23
+ height: "100%",
24
+ position: "relative",
25
+ display: "flex",
26
+ outline: "none"
27
+ }),
28
+ nodeToolbar: css({
29
+ backgroundColor: "transparent",
30
+ borderRadius: theme.radii.full,
31
+ top: 10
32
+ }),
33
+ buttonsContainer: css({
34
+ padding: theme.space.xs
35
+ }),
36
+ textAreaRoot: css({
37
+ flex: 1,
38
+ width: "100%",
39
+ border: "none",
40
+ background: "transparent",
41
+ outline: "none"
42
+ }),
43
+ textAreaInput: css({
44
+ resize: "none",
45
+ height: "100%",
46
+ width: "100%",
47
+ padding: theme.space.xs,
48
+ "&:focus-visible": {
49
+ outline: "none"
50
+ },
51
+ paddingRight: 32
52
+ }),
53
+ textAreaInputFolded: css({
54
+ resize: "none",
55
+ width: "100%",
56
+ padding: 0,
57
+ border: "none",
58
+ overflow: "hidden",
59
+ minHeight: "1.5rem",
60
+ height: "auto"
61
+ }),
62
+ colorConfig: css({
63
+ display: "flex",
64
+ flexDirection: "column",
65
+ gap: theme.space.sm
66
+ }),
67
+ folded: css({
68
+ width: 34,
69
+ height: 34
70
+ }),
71
+ expandButton: css({
72
+ position: "absolute",
73
+ top: theme.space.xxs,
74
+ right: theme.space.xxs
75
+ }),
76
+ fontSizes: css({
77
+ maxHeight: 160,
78
+ overflowY: "auto",
79
+ padding: theme.space.xs
80
+ })
81
+ };
82
+ const colorsToConfig = ["textColor", "backgroundColor", "borderColor"];
83
+ const fontSizes = [10, 11, 12, 14, 16, 20, 24, 32, 36, 40, 48, 64, 96, 128];
84
+ const StickyNode = ({
85
+ id,
86
+ selected,
87
+ data = {}
88
+ }) => {
89
+ const mergedData = useMemo(() => ({ ...defaultData, ...data }), [data]);
90
+ const [text, setText] = useState("");
91
+ const { setNodes } = useReactFlow();
92
+ const [editing, setEditing] = useState(false);
93
+ const [toolbarVisible, setToolbarVisible] = useState(false);
94
+ const [colorsConfigOpen, setColorsConfigOpen] = useState(false);
95
+ const [fontSizeConfigOpen, setFontSizeConfigOpen] = useState(false);
96
+ const [fontSize, setFontSize] = useState(mergedData.fontSize ?? 14);
97
+ const colorConfigBtnRef = useRef(null);
98
+ const fontSizeConfigBtnRef = useRef(null);
99
+ const handleToggleBold = useCallback(() => {
100
+ setNodes(
101
+ (nds) => nds.map((node) => {
102
+ if (node.id === id) {
103
+ node.data = {
104
+ ...node.data,
105
+ bold: !node.data?.bold
106
+ };
107
+ }
108
+ return node;
109
+ })
110
+ );
111
+ }, [setNodes, id]);
112
+ const handleToggleItalic = useCallback(() => {
113
+ setNodes(
114
+ (nds) => nds.map((node) => {
115
+ if (node.id === id) {
116
+ node.data = {
117
+ ...node.data,
118
+ italic: !node.data?.italic
119
+ };
120
+ }
121
+ return node;
122
+ })
123
+ );
124
+ }, [setNodes, id]);
125
+ const handleChangeFontSize = useCallback(
126
+ (size) => {
127
+ setFontSize(size);
128
+ setNodes(
129
+ (nds) => nds.map((node) => {
130
+ if (node.id === id) {
131
+ node.data = {
132
+ ...node.data,
133
+ fontSize: size
134
+ };
135
+ }
136
+ return node;
137
+ })
138
+ );
139
+ setFontSizeConfigOpen(false);
140
+ },
141
+ [setNodes, id]
142
+ );
143
+ const handleToggleExpand = useCallback(() => {
144
+ setNodes(
145
+ (nds) => nds.map((node) => {
146
+ if (node.id === id) {
147
+ node.data = {
148
+ ...node.data,
149
+ expanded: !node.data?.expanded
150
+ };
151
+ }
152
+ return node;
153
+ })
154
+ );
155
+ }, [setNodes, id]);
156
+ const handleResetColors = useCallback(() => {
157
+ setNodes(
158
+ (nds) => nds.map((node) => {
159
+ if (node.id === id) {
160
+ node.data = {
161
+ ...node.data,
162
+ backgroundColor: defaultData.backgroundColor,
163
+ borderColor: defaultData.borderColor,
164
+ textColor: defaultData.textColor,
165
+ hasShadow: defaultData.hasShadow
166
+ };
167
+ }
168
+ return node;
169
+ })
170
+ );
171
+ }, [setNodes, id]);
172
+ const handleDeleteSticky = useCallback(() => {
173
+ setNodes((nds) => nds.filter((node) => node.id !== id));
174
+ mergedData.onDelete?.();
175
+ }, [mergedData, setNodes, id]);
176
+ if (!mergedData.visible) return null;
177
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
178
+ /* @__PURE__ */ jsxs(
179
+ Popover,
180
+ {
181
+ open: colorsConfigOpen,
182
+ anchorEl: colorConfigBtnRef.current,
183
+ onClose: () => {
184
+ setColorsConfigOpen(false);
185
+ setEditing(false);
186
+ },
187
+ anchorOrigin: {
188
+ vertical: "bottom",
189
+ horizontal: "left"
190
+ },
191
+ transformOrigin: {
192
+ vertical: "top",
193
+ horizontal: "left"
194
+ },
195
+ children: [
196
+ /* @__PURE__ */ jsx(HvDialogTitle, { children: "Customize Colors" }),
197
+ /* @__PURE__ */ jsx(HvDialogContent, { children: /* @__PURE__ */ jsxs("div", { className: classes.colorConfig, children: [
198
+ colorsToConfig.map((c) => /* @__PURE__ */ jsx(
199
+ HvColorPicker,
200
+ {
201
+ label: `${c.charAt(0).toUpperCase() + c.slice(1).replace("Color", " Color")}`,
202
+ value: mergedData[c] ?? "",
203
+ onChange: (color) => {
204
+ setNodes(
205
+ (nds) => nds.map((node) => {
206
+ if (node.id === id) {
207
+ node.data = {
208
+ ...node.data,
209
+ [c]: color
210
+ };
211
+ }
212
+ return node;
213
+ })
214
+ );
215
+ }
216
+ },
217
+ c
218
+ )),
219
+ /* @__PURE__ */ jsx(
220
+ HvCheckBox,
221
+ {
222
+ label: "Drop Shadow",
223
+ defaultChecked: mergedData.hasShadow,
224
+ onChange: (_, checked) => {
225
+ setNodes(
226
+ (nds) => nds.map((node) => {
227
+ if (node.id === id) {
228
+ node.data = {
229
+ ...node.data,
230
+ hasShadow: checked
231
+ };
232
+ }
233
+ return node;
234
+ })
235
+ );
236
+ }
237
+ }
238
+ ),
239
+ /* @__PURE__ */ jsx(HvButton, { variant: "secondarySubtle", onClick: handleResetColors, children: "Reset to defaults" })
240
+ ] }) })
241
+ ]
242
+ }
243
+ ),
244
+ /* @__PURE__ */ jsx(
245
+ Popover,
246
+ {
247
+ open: fontSizeConfigOpen,
248
+ anchorEl: fontSizeConfigBtnRef.current,
249
+ onClose: () => {
250
+ setFontSizeConfigOpen(false);
251
+ setEditing(false);
252
+ },
253
+ anchorOrigin: {
254
+ vertical: "bottom",
255
+ horizontal: "right"
256
+ },
257
+ transformOrigin: {
258
+ vertical: "top",
259
+ horizontal: "right"
260
+ },
261
+ children: /* @__PURE__ */ jsx(
262
+ HvSelectionList,
263
+ {
264
+ className: classes.fontSizes,
265
+ value: fontSize,
266
+ onChange: (evt, newValue) => {
267
+ handleChangeFontSize(newValue);
268
+ },
269
+ children: fontSizes.map((size) => /* @__PURE__ */ jsx(HvListItem, { value: size, children: size }, size))
270
+ }
271
+ )
272
+ }
273
+ ),
274
+ /* @__PURE__ */ jsxs(
275
+ "div",
276
+ {
277
+ className: cx(
278
+ classes.root,
279
+ "nowheel",
280
+ !mergedData.expanded && classes.folded
281
+ ),
282
+ style: {
283
+ backgroundColor: mergedData.backgroundColor ?? theme.colors.bgContainer,
284
+ boxShadow: mergedData.hasShadow ? "0 8px 12px rgba(65,65,65,0.25)" : "none",
285
+ border: mergedData.borderColor ? `1px solid ${mergedData.borderColor}` : "none",
286
+ fontSize: `${mergedData.fontSize ?? 14}px`,
287
+ lineHeight: `${mergedData.fontSize ?? 14}px`
288
+ },
289
+ children: [
290
+ mergedData.expanded && /* @__PURE__ */ jsxs(Fragment, { children: [
291
+ /* @__PURE__ */ jsx(
292
+ NodeResizer,
293
+ {
294
+ isVisible: selected,
295
+ minWidth: 100,
296
+ minHeight: 75,
297
+ lineStyle: {
298
+ color: theme.colors.primary,
299
+ borderStyle: "solid"
300
+ },
301
+ handleStyle: {
302
+ width: 6,
303
+ height: 6,
304
+ border: `1px solid ${theme.colors.primary}`,
305
+ backgroundColor: mergedData.backgroundColor ?? "transparent",
306
+ borderRadius: theme.radii.full
307
+ }
308
+ }
309
+ ),
310
+ /* @__PURE__ */ jsx(
311
+ NodeToolbar,
312
+ {
313
+ isVisible: editing || toolbarVisible || selected,
314
+ position: Position.Top,
315
+ className: classes.nodeToolbar,
316
+ onMouseEnter: () => setToolbarVisible(true),
317
+ onMouseLeave: () => setToolbarVisible(false),
318
+ children: /* @__PURE__ */ jsx("div", { className: classes.buttonsContainer, children: /* @__PURE__ */ jsxs(HvMultiButton, { children: [
319
+ /* @__PURE__ */ jsx(
320
+ HvIconButton,
321
+ {
322
+ "aria-label": "Font Size",
323
+ title: "Font Size",
324
+ ref: fontSizeConfigBtnRef,
325
+ onClick: () => {
326
+ setEditing(true);
327
+ setFontSizeConfigOpen(true);
328
+ },
329
+ children: /* @__PURE__ */ jsx(FontSize, {})
330
+ }
331
+ ),
332
+ /* @__PURE__ */ jsx(
333
+ HvIconButton,
334
+ {
335
+ "aria-label": "Bold",
336
+ title: "Bold",
337
+ selected: mergedData.bold,
338
+ onClick: handleToggleBold,
339
+ children: /* @__PURE__ */ jsx(Bold, {})
340
+ }
341
+ ),
342
+ /* @__PURE__ */ jsx(
343
+ HvIconButton,
344
+ {
345
+ "aria-label": "Italic",
346
+ title: "Italic",
347
+ selected: mergedData.italic,
348
+ onClick: handleToggleItalic,
349
+ children: /* @__PURE__ */ jsx(Italic, {})
350
+ }
351
+ ),
352
+ /* @__PURE__ */ jsx(
353
+ HvIconButton,
354
+ {
355
+ "aria-label": "Customize Colors",
356
+ title: "Customize Colors",
357
+ ref: colorConfigBtnRef,
358
+ onClick: () => {
359
+ setEditing(true);
360
+ setColorsConfigOpen(true);
361
+ },
362
+ children: /* @__PURE__ */ jsx(Palette, {})
363
+ }
364
+ ),
365
+ /* @__PURE__ */ jsx(
366
+ HvIconButton,
367
+ {
368
+ "aria-label": "Delete",
369
+ title: "Delete",
370
+ onClick: handleDeleteSticky,
371
+ children: /* @__PURE__ */ jsx(Delete, {})
372
+ }
373
+ )
374
+ ] }) })
375
+ }
376
+ ),
377
+ /* @__PURE__ */ jsxs(
378
+ "div",
379
+ {
380
+ onMouseEnter: () => setToolbarVisible(true),
381
+ onMouseLeave: () => setToolbarVisible(false),
382
+ className: classes.textAreaRoot,
383
+ children: [
384
+ /* @__PURE__ */ jsx(
385
+ HvIconButton,
386
+ {
387
+ className: classes.expandButton,
388
+ title: "Fold",
389
+ onClick: handleToggleExpand,
390
+ children: /* @__PURE__ */ jsx(ActualSize, {})
391
+ }
392
+ ),
393
+ /* @__PURE__ */ jsx(
394
+ "textarea",
395
+ {
396
+ id: `sticky-textarea-${id}`,
397
+ value: text || "",
398
+ onChange: (e) => setText(e.target.value),
399
+ className: classes.textAreaInput,
400
+ placeholder: "Type here...",
401
+ style: {
402
+ color: mergedData.textColor ?? theme.colors.text,
403
+ fontWeight: mergedData.bold ? "bold" : "normal",
404
+ fontStyle: mergedData.italic ? "italic" : "normal",
405
+ fontSize: mergedData.fontSize ?? "14px"
406
+ },
407
+ onFocus: () => setEditing(true),
408
+ onBlur: () => {
409
+ setEditing(false);
410
+ setColorsConfigOpen(false);
411
+ }
412
+ }
413
+ )
414
+ ]
415
+ }
416
+ )
417
+ ] }),
418
+ !mergedData.expanded && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
419
+ HvIconButton,
420
+ {
421
+ title: /* @__PURE__ */ jsx(
422
+ "span",
423
+ {
424
+ style: { whiteSpace: "pre-wrap", wordBreak: "break-word" },
425
+ children: text
426
+ }
427
+ ),
428
+ onClick: handleToggleExpand,
429
+ children: /* @__PURE__ */ jsx(Fullscreen, {})
430
+ }
431
+ ) })
432
+ ]
433
+ }
434
+ )
435
+ ] });
436
+ };
437
+ export {
438
+ StickyNode
439
+ };