@eccenca/gui-elements 24.1.0-rc.6 → 24.2.0-featuresupportprojectvariableautocompletioncmem5572.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.
Files changed (126) hide show
  1. package/CHANGELOG.md +78 -18
  2. package/README.md +10 -7
  3. package/dist/cjs/cmem/markdown/Markdown.js +13 -11
  4. package/dist/cjs/cmem/markdown/Markdown.js.map +1 -1
  5. package/dist/cjs/cmem/markdown/highlightSearchWords.js +6 -1
  6. package/dist/cjs/cmem/markdown/highlightSearchWords.js.map +1 -1
  7. package/dist/cjs/common/Intent/index.js +4 -11
  8. package/dist/cjs/common/Intent/index.js.map +1 -1
  9. package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js +37 -26
  10. package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
  11. package/dist/cjs/components/AutoSuggestion/ExtendedCodeEditor.js +2 -2
  12. package/dist/cjs/components/AutoSuggestion/ExtendedCodeEditor.js.map +1 -1
  13. package/dist/cjs/components/Button/Button.js +2 -2
  14. package/dist/cjs/components/Button/Button.js.map +1 -1
  15. package/dist/cjs/components/ContextOverlay/ContextMenu.js +3 -2
  16. package/dist/cjs/components/ContextOverlay/ContextMenu.js.map +1 -1
  17. package/dist/cjs/components/ContextOverlay/ContextOverlay.js +46 -2
  18. package/dist/cjs/components/ContextOverlay/ContextOverlay.js.map +1 -1
  19. package/dist/cjs/components/Form/FieldItem.js +3 -2
  20. package/dist/cjs/components/Form/FieldItem.js.map +1 -1
  21. package/dist/cjs/components/Form/FieldSet.js +3 -2
  22. package/dist/cjs/components/Form/FieldSet.js.map +1 -1
  23. package/dist/cjs/components/Icon/canonicalIconNames.js +1 -0
  24. package/dist/cjs/components/Icon/canonicalIconNames.js.map +1 -1
  25. package/dist/cjs/components/MultiSelect/MultiSelect.js +18 -14
  26. package/dist/cjs/components/MultiSelect/MultiSelect.js.map +1 -1
  27. package/dist/cjs/components/Notification/Notification.js +7 -4
  28. package/dist/cjs/components/Notification/Notification.js.map +1 -1
  29. package/dist/cjs/components/OverviewItem/OverviewItemActions.js +9 -2
  30. package/dist/cjs/components/OverviewItem/OverviewItemActions.js.map +1 -1
  31. package/dist/cjs/components/Spinner/Spinner.js +7 -5
  32. package/dist/cjs/components/Spinner/Spinner.js.map +1 -1
  33. package/dist/cjs/components/Tooltip/Tooltip.js +75 -7
  34. package/dist/cjs/components/Tooltip/Tooltip.js.map +1 -1
  35. package/dist/cjs/extensions/react-flow/nodes/NodeContent.js +17 -13
  36. package/dist/cjs/extensions/react-flow/nodes/NodeContent.js.map +1 -1
  37. package/dist/esm/cmem/markdown/Markdown.js +13 -11
  38. package/dist/esm/cmem/markdown/Markdown.js.map +1 -1
  39. package/dist/esm/cmem/markdown/highlightSearchWords.js +6 -1
  40. package/dist/esm/cmem/markdown/highlightSearchWords.js.map +1 -1
  41. package/dist/esm/common/Intent/index.js +14 -10
  42. package/dist/esm/common/Intent/index.js.map +1 -1
  43. package/dist/esm/components/AutoSuggestion/AutoSuggestion.js +42 -33
  44. package/dist/esm/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
  45. package/dist/esm/components/AutoSuggestion/ExtendedCodeEditor.js +2 -2
  46. package/dist/esm/components/AutoSuggestion/ExtendedCodeEditor.js.map +1 -1
  47. package/dist/esm/components/Button/Button.js +2 -2
  48. package/dist/esm/components/Button/Button.js.map +1 -1
  49. package/dist/esm/components/ContextOverlay/ContextMenu.js +3 -2
  50. package/dist/esm/components/ContextOverlay/ContextMenu.js.map +1 -1
  51. package/dist/esm/components/ContextOverlay/ContextOverlay.js +63 -3
  52. package/dist/esm/components/ContextOverlay/ContextOverlay.js.map +1 -1
  53. package/dist/esm/components/Form/FieldItem.js +3 -2
  54. package/dist/esm/components/Form/FieldItem.js.map +1 -1
  55. package/dist/esm/components/Form/FieldSet.js +3 -2
  56. package/dist/esm/components/Form/FieldSet.js.map +1 -1
  57. package/dist/esm/components/Icon/canonicalIconNames.js +1 -0
  58. package/dist/esm/components/Icon/canonicalIconNames.js.map +1 -1
  59. package/dist/esm/components/MultiSelect/MultiSelect.js +18 -14
  60. package/dist/esm/components/MultiSelect/MultiSelect.js.map +1 -1
  61. package/dist/esm/components/Notification/Notification.js +7 -4
  62. package/dist/esm/components/Notification/Notification.js.map +1 -1
  63. package/dist/esm/components/OverviewItem/OverviewItemActions.js +25 -2
  64. package/dist/esm/components/OverviewItem/OverviewItemActions.js.map +1 -1
  65. package/dist/esm/components/Spinner/Spinner.js +9 -5
  66. package/dist/esm/components/Spinner/Spinner.js.map +1 -1
  67. package/dist/esm/components/Tooltip/Tooltip.js +92 -8
  68. package/dist/esm/components/Tooltip/Tooltip.js.map +1 -1
  69. package/dist/esm/extensions/react-flow/nodes/NodeContent.js +17 -13
  70. package/dist/esm/extensions/react-flow/nodes/NodeContent.js.map +1 -1
  71. package/dist/types/cmem/markdown/Markdown.d.ts +8 -1
  72. package/dist/types/common/Intent/index.d.ts +10 -1
  73. package/dist/types/components/AutoSuggestion/AutoSuggestion.d.ts +5 -1
  74. package/dist/types/components/AutoSuggestion/ExtendedCodeEditor.d.ts +5 -1
  75. package/dist/types/components/Button/Button.d.ts +5 -1
  76. package/dist/types/components/ContextOverlay/ContextMenu.d.ts +9 -2
  77. package/dist/types/components/ContextOverlay/ContextOverlay.d.ts +6 -1
  78. package/dist/types/components/Form/FieldItem.d.ts +10 -1
  79. package/dist/types/components/Form/FieldSet.d.ts +10 -1
  80. package/dist/types/components/Icon/canonicalIconNames.d.ts +1 -0
  81. package/dist/types/components/MultiSelect/MultiSelect.d.ts +12 -4
  82. package/dist/types/components/Notification/Notification.d.ts +10 -1
  83. package/dist/types/components/OverviewItem/OverviewItemActions.d.ts +13 -1
  84. package/dist/types/components/ProgressBar/ProgressBar.d.ts +2 -2
  85. package/dist/types/components/Spinner/Spinner.d.ts +8 -3
  86. package/dist/types/components/Structure/TitleSubsection.d.ts +7 -0
  87. package/dist/types/components/Table/TableContainer.d.ts +2 -2
  88. package/dist/types/components/Table/TableExpandRow.d.ts +1 -1
  89. package/dist/types/components/Table/index.d.ts +1 -0
  90. package/dist/types/components/Tabs/Tab.d.ts +14 -0
  91. package/dist/types/components/Tooltip/Tooltip.d.ts +9 -1
  92. package/package.json +47 -48
  93. package/src/cmem/markdown/Markdown.tsx +25 -14
  94. package/src/cmem/markdown/highlightSearchWords.test.ts +8 -2
  95. package/src/cmem/markdown/highlightSearchWords.ts +6 -1
  96. package/src/common/Intent/index.ts +6 -6
  97. package/src/components/AutoSuggestion/AutoSuggestion.tsx +50 -32
  98. package/src/components/AutoSuggestion/ExtendedCodeEditor.tsx +8 -0
  99. package/src/components/Button/Button.stories.tsx +10 -6
  100. package/src/components/Button/Button.tsx +7 -2
  101. package/src/components/ContextOverlay/ContextMenu.stories.tsx +1 -1
  102. package/src/components/ContextOverlay/ContextMenu.tsx +26 -13
  103. package/src/components/ContextOverlay/ContextOverlay.tsx +83 -5
  104. package/src/components/Form/FieldItem.tsx +14 -3
  105. package/src/components/Form/FieldSet.tsx +13 -2
  106. package/src/components/Form/Stories/FieldItem.stories.tsx +4 -0
  107. package/src/components/Form/Stories/FieldSet.stories.tsx +4 -0
  108. package/src/components/Icon/canonicalIconNames.tsx +1 -0
  109. package/src/components/MultiSelect/MultiSelect.tsx +27 -15
  110. package/src/components/MultiSuggestField/MultiSuggestField.stories.tsx +6 -0
  111. package/src/components/Notification/Notification.stories.tsx +4 -0
  112. package/src/components/Notification/Notification.tsx +17 -4
  113. package/src/components/OverviewItem/OverviewItemActions.tsx +24 -1
  114. package/src/components/OverviewItem/stories/OverviewItemList.stories.tsx +2 -7
  115. package/src/components/OverviewItem/stories/OverviewItemListPerformance.tsx +174 -0
  116. package/src/components/OverviewItem/stories/OverviewItemPerformance.stories.tsx +19 -0
  117. package/src/components/Spinner/Spinner.tsx +13 -5
  118. package/src/components/Spinner/Stories/spinner.stories.tsx +6 -1
  119. package/src/components/Table/TableContainer.tsx +2 -2
  120. package/src/components/Table/TableExpandRow.tsx +1 -1
  121. package/src/components/Table/index.tsx +1 -0
  122. package/src/components/Tooltip/Tooltip.stories.tsx +3 -2
  123. package/src/components/Tooltip/Tooltip.tsx +121 -10
  124. package/src/extensions/react-flow/nodes/NodeContent.tsx +18 -14
  125. package/src/extensions/react-flow/nodes/_nodes.scss +1 -1
  126. package/src/extensions/react-flow/nodes/stories/NodeContent.stories.tsx +45 -9
@@ -11,14 +11,19 @@ import { CLASSPREFIX as eccgui } from "../../configuration/constants";
11
11
  type SpinnerPosition = "local" | "inline" | "global";
12
12
  type SpinnerSize = "tiny" | "small" | "medium" | "large" | "xlarge" | "inherit";
13
13
  type SpinnerStroke = "thin" | "medium" | "bold";
14
- type Intent = "inherit" | "primary" | "success" | "warning" | "danger";
14
+ type Intent = "inherit" | "primary" | "success" | "warning" | "danger" | "none";
15
15
 
16
16
  /** A spinner that is either displayed globally or locally. */
17
- export interface SpinnerProps extends Omit<BlueprintSpinnerProps, "size"> {
17
+ export interface SpinnerProps extends Omit<BlueprintSpinnerProps, "size" | "intent"> {
18
18
  /**
19
19
  * intent value or a valid css color definition
20
+ * @deprecated (v25) it will allow in the future only a color value string and that for other states the intent property needs to be used
20
21
  */
21
22
  color?: Intent | string;
23
+ /**
24
+ * Intent state of the field item.
25
+ */
26
+ intent?: Intent;
22
27
  /**
23
28
  * Additional CSS class names.
24
29
  */
@@ -66,12 +71,14 @@ export interface SpinnerProps extends Omit<BlueprintSpinnerProps, "size"> {
66
71
  export const Spinner = ({
67
72
  className = "",
68
73
  color = "inherit",
74
+ intent,
69
75
  position = "local",
70
76
  size,
71
77
  stroke,
72
78
  showLocalBackdrop = false,
73
79
  delay = 0,
74
80
  overlayProps,
81
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
75
82
  description = "Loading indicator", // currently unsupported (FIXME):
76
83
  ...otherProps
77
84
  }: SpinnerProps) => {
@@ -91,8 +98,9 @@ export const Spinner = ({
91
98
  };
92
99
 
93
100
  const spinnerElement = position === "inline" ? "span" : "div";
94
- const spinnerColor = availableIntent.indexOf(color) < 0 ? color : null;
95
- const spinnerIntent = availableIntent.indexOf(color) < 0 ? "usercolor" : color;
101
+
102
+ const spinnerColor = !intent && availableIntent.indexOf(color) < 0 ? color : null;
103
+ const spinnerIntent = !intent && availableIntent.indexOf(color) < 0 ? "usercolor" : intent || color;
96
104
 
97
105
  let spinnerSize;
98
106
  let spinnerStroke;
@@ -130,7 +138,7 @@ export const Spinner = ({
130
138
  />
131
139
  );
132
140
 
133
- if (spinnerColor) {
141
+ if (spinnerColor && spinnerIntent === "usercolor") {
134
142
  spinner = <span style={{ color: spinnerColor }}>{spinner}</span>;
135
143
  }
136
144
 
@@ -1,12 +1,17 @@
1
1
  import React from "react";
2
2
  import { Meta, StoryFn } from "@storybook/react";
3
3
 
4
+ import { helpersArgTypes } from "../../../../.storybook/helpers";
4
5
  import Spinner from "../Spinner";
5
6
  export default {
6
7
  title: "Components/Spinner",
7
8
  component: Spinner,
8
9
  argTypes: {
9
- color: { control: "radio", options: ["inherit", "primary", "success", "warning", "danger"] },
10
+ color: { control: "color" },
11
+ intent: {
12
+ ...helpersArgTypes.exampleIntent,
13
+ options: ["UNDEFINED", "primary", "success", "warning", "danger", "none"],
14
+ },
10
15
  position: { control: "radio", options: ["local", "inline", "global"] },
11
16
  size: { control: "radio", options: ["tiny", "small", "medium", "large", "xlarge", "inherit"] },
12
17
  stroke: { control: "radio", options: ["thin", "medium", "bold"] },
@@ -11,7 +11,7 @@ import { CLASSPREFIX as eccgui } from "../../configuration/constants";
11
11
 
12
12
  import { TableRowHeightSize, tableRowHeightSizes } from "./Table";
13
13
 
14
- interface TableDataContainerProps
14
+ export interface TableDataContainerProps
15
15
  extends Omit<
16
16
  CarbonDataTableProps<
17
17
  Array<Omit<CarbonDataTableRow<Array<CarbonDataTableHeader>>, "cells">>,
@@ -23,7 +23,7 @@ interface TableDataContainerProps
23
23
  children(signature: any): JSX.Element;
24
24
  size?: TableRowHeightSize;
25
25
  }
26
- interface TableSimpleContainerProps
26
+ export interface TableSimpleContainerProps
27
27
  extends Omit<CarbonTableContainerProps, "description" | "stickyHeader" | "title" | "useStaticWidth">,
28
28
  React.HTMLAttributes<HTMLDivElement> {
29
29
  children?: JSX.Element;
@@ -11,7 +11,7 @@ import { TableCell } from "./index";
11
11
  // workaround to get type/interface
12
12
  type CarbonTableExpandRowProps = React.ComponentProps<typeof CarbonTableExpandRow>;
13
13
  export interface TableExpandRowProps
14
- extends Omit<CarbonTableExpandRowProps, "ref" | "ariaLabel" | "expandIconDescription" | "aria-label">,
14
+ extends Omit<CarbonTableExpandRowProps, "children" | "ref" | "ariaLabel" | "expandIconDescription" | "aria-label">,
15
15
  React.HTMLAttributes<HTMLTableRowElement> {
16
16
  /**
17
17
  * This text is displayed as tooltip for the button that toggles the expanded/collapsed state.
@@ -7,3 +7,4 @@ export * from "./TableCell";
7
7
 
8
8
  // TODO, we may wrap to add own classes (currently not necessary)
9
9
  export { TableHead, TableBody, TableExpandedRow, TableHeader } from "@carbon/react";
10
+ export type { TableHeadProps, TableBodyProps, TableExpandedRowProps, TableHeaderProps, DataTableRenderProps } from "@carbon/react";
@@ -11,9 +11,10 @@ export default {
11
11
  argTypes: {},
12
12
  } as Meta<typeof Tooltip>;
13
13
 
14
+ let forcedUpdateKey = 0; // @see https://github.com/storybookjs/storybook/issues/13375#issuecomment-1291011856
14
15
  const Template: StoryFn<typeof Tooltip> = (args) => (
15
16
  <OverlaysProvider>
16
- <Tooltip {...args} />
17
+ <Tooltip {...args} key={++forcedUpdateKey} />
17
18
  </OverlaysProvider>
18
19
  );
19
20
 
@@ -30,7 +31,7 @@ const testContent = loremIpsum({
30
31
  * */
31
32
  export const Default = Template.bind({});
32
33
  Default.args = {
33
- children: <span>hover me</span>,
34
+ children: "hover me",
34
35
  content: testContent,
35
36
  addIndicator: true,
36
37
  };
@@ -3,6 +3,7 @@ import {
3
3
  Classes as BlueprintClasses,
4
4
  Tooltip as BlueprintTooltip,
5
5
  TooltipProps as BlueprintTooltipProps,
6
+ Utils as BlueprintUtils,
6
7
  } from "@blueprintjs/core";
7
8
 
8
9
  import { CLASSPREFIX as eccgui } from "../../configuration/constants";
@@ -33,6 +34,14 @@ export interface TooltipProps extends Omit<BlueprintTooltipProps, "position"> {
33
34
  * Set properties for the Markdown parser
34
35
  */
35
36
  markdownProps?: Omit<MarkdownProps, "children">;
37
+ /**
38
+ * Use the overlay target as placeholder before the real `<Tooltip /` is rendered on first hover or focus event.
39
+ * This can boost performance massive but it is currently experimental.
40
+ * Placeholders are never used when `disabled`, `defaultIsOpen` or `isOpen` is set to `true`, or if `renderTarget` is set.
41
+ * If the tooltip `content` is only a string then a placeholder is automatically used, too.
42
+ * You can prevent it in any case by setting it to `false`.
43
+ */
44
+ usePlaceholder?: boolean;
36
45
  }
37
46
 
38
47
  export const Tooltip = ({
@@ -43,8 +52,106 @@ export const Tooltip = ({
43
52
  addIndicator = false,
44
53
  markdownEnabler = "\n\n",
45
54
  markdownProps,
46
- ...otherProps
55
+ usePlaceholder,
56
+ hoverOpenDelay = 500,
57
+ ...otherTooltipProps
47
58
  }: TooltipProps) => {
59
+ const placeholderRef = React.useRef(null);
60
+ const eventMemory = React.useRef<null | "afterhover" | "afterfocus">(null);
61
+ const searchId = React.useRef<null | string>(null);
62
+ const swapDelayTime = 100;
63
+ const [placeholder, setPlaceholder] = React.useState<boolean>(
64
+ !otherTooltipProps.disabled &&
65
+ !otherTooltipProps.defaultIsOpen &&
66
+ !otherTooltipProps.isOpen &&
67
+ otherTooltipProps.renderTarget === undefined &&
68
+ hoverOpenDelay > swapDelayTime &&
69
+ (usePlaceholder === true || (typeof content === "string" && usePlaceholder !== false))
70
+ );
71
+
72
+ const targetClassName =
73
+ `${eccgui}-tooltip__wrapper` +
74
+ (className ? " " + className : "") +
75
+ (addIndicator === true ? " " + BlueprintClasses.TOOLTIP_INDICATOR : "");
76
+
77
+ React.useEffect(() => {
78
+ if (placeholderRef.current !== null) {
79
+ const swap = (ev: MouseEvent | globalThis.FocusEvent) => {
80
+ const swapDelay = setTimeout(() => {
81
+ // we delay the swap to prevent unwanted effects
82
+ // (e.g. forced mouseover after the swap but the cursor is already somewhere else)
83
+ eventMemory.current = ev.type === "focusin" ? "afterfocus" : "afterhover";
84
+ searchId.current = Date.now().toString(16) + Math.random().toString(16).slice(2);
85
+ setPlaceholder(false);
86
+ }, swapDelayTime);
87
+ if (placeholderRef.current !== null) {
88
+ const eventType = ev.type === "focusin" ? "focusout" : "mouseleave";
89
+ (placeholderRef.current as HTMLElement).addEventListener(
90
+ eventType,
91
+ () => {
92
+ if (eventType === "focusout" && eventMemory.current === "afterfocus" ||
93
+ eventType === "mouseleave" && eventMemory.current === "afterhover") {
94
+ eventMemory.current = null
95
+ }
96
+ clearTimeout(swapDelay)
97
+ }
98
+ );
99
+ }
100
+ };
101
+ (placeholderRef.current as HTMLElement).addEventListener("mouseenter", swap);
102
+ (placeholderRef.current as HTMLElement).addEventListener("focusin", swap);
103
+ return () => {
104
+ if (placeholderRef.current) {
105
+ (placeholderRef.current as HTMLElement).removeEventListener("mouseenter", swap);
106
+ (placeholderRef.current as HTMLElement).removeEventListener("focusin", swap);
107
+ }
108
+ };
109
+ }
110
+ return () => {};
111
+ }, [!!placeholderRef.current]);
112
+
113
+ const refocus = React.useCallback((node) => {
114
+ if (eventMemory.current && node) {
115
+ // we do not have a `targetRef` here, so we need to workaround it
116
+ // const target = node.targetRef.current.children[0];
117
+ const target = document.body.querySelector(
118
+ `[data-postplaceholder=id${eventMemory.current}${searchId.current}]`
119
+ )?.children[0];
120
+ if (target) {
121
+ switch (eventMemory.current) {
122
+ case "afterfocus":
123
+ (target as HTMLElement).focus();
124
+ break;
125
+ case "afterhover":
126
+ (target as HTMLElement).dispatchEvent(new MouseEvent("mouseover", { bubbles: true }));
127
+ break;
128
+ }
129
+ }
130
+ }
131
+ }, []);
132
+
133
+ const displayPlaceholder = () => {
134
+ const PlaceholderElement = otherTooltipProps?.targetTagName ?? (otherTooltipProps?.fill ? "div" : "span");
135
+ const childTarget = BlueprintUtils.ensureElement(React.Children.toArray(children)[0]);
136
+ if (!childTarget) {
137
+ return null;
138
+ }
139
+ return React.createElement(
140
+ PlaceholderElement,
141
+ {
142
+ ...otherTooltipProps?.targetProps,
143
+ className: `${BlueprintClasses.POPOVER_TARGET} ${targetClassName} ${eccgui}-tooltip__wrapper--placeholder`,
144
+ ref: placeholderRef,
145
+ },
146
+ React.cloneElement(childTarget, {
147
+ ...childTarget.props,
148
+ className:
149
+ childTarget.props.className ?? "" + (otherTooltipProps.fill ? ` ${BlueprintClasses.FILL}` : ""),
150
+ tabIndex: 0,
151
+ })
152
+ );
153
+ };
154
+
48
155
  let tooltipContent = content;
49
156
 
50
157
  if (
@@ -55,23 +162,27 @@ export const Tooltip = ({
55
162
  tooltipContent = <Markdown {...markdownProps}>{content}</Markdown>;
56
163
  }
57
164
 
58
- return (
165
+ return placeholder ? (
166
+ displayPlaceholder()
167
+ ) : (
59
168
  <BlueprintTooltip
60
169
  lazy={true}
61
- hoverOpenDelay={500}
62
- {...otherProps}
170
+ hoverOpenDelay={hoverOpenDelay - swapDelayTime}
171
+ {...otherTooltipProps}
63
172
  content={tooltipContent}
64
- className={
65
- `${eccgui}-tooltip__wrapper` +
66
- (className ? " " + className : "") +
67
- (addIndicator === true ? " " + BlueprintClasses.TOOLTIP_INDICATOR : "")
68
- }
69
- //targetClassName={`${eccgui}-tooltip__target` + (className ? " " + className + "__target" : "")}
173
+ className={targetClassName}
70
174
  popoverClassName={
71
175
  `${eccgui}-tooltip__content` +
72
176
  ` ${eccgui}-tooltip--${size}` +
73
177
  (className ? " " + className + "__content" : "")
74
178
  }
179
+ ref={refocus}
180
+ targetProps={
181
+ {
182
+ ...otherTooltipProps.targetProps,
183
+ "data-postplaceholder": `id${eventMemory.current}${searchId.current}`,
184
+ } as React.HTMLProps<HTMLElement>
185
+ }
75
186
  >
76
187
  {children}
77
188
  </BlueprintTooltip>
@@ -390,15 +390,19 @@ export function NodeContent<CONTENT_PROPS = any>({
390
390
  flowVersionCheck === "legacy" ? ([] as NodeContentHandleLegacyProps[]) : ([] as NodeContentHandleNextProps[]);
391
391
 
392
392
  const saveOriginalSize = () => {
393
+ const currentClassNames = nodeContentRef.current.classList;
394
+ if (currentClassNames.contains("was-resized") && !width && !height) {
395
+ currentClassNames.remove("was-resized");
396
+ }
393
397
  originalSize.current.width = nodeContentRef.current.offsetWidth as number;
394
398
  originalSize.current.height = nodeContentRef.current.offsetHeight as number;
395
399
  }
396
400
 
397
401
  React.useEffect(() => {
398
- if(nodeContentRef.current && !(originalSize.current.width || originalSize.current.height)) {
402
+ if(nodeContentRef.current && (!(originalSize.current.width || originalSize.current.height) || !(width || height))) {
399
403
  saveOriginalSize();
400
404
  }
401
- }, [!!nodeContentRef.current, !(originalSize.current.width || originalSize.current.height)])
405
+ }, [!!nodeContentRef.current, !(originalSize.current.width || originalSize.current.height), !(width || height)])
402
406
 
403
407
  // Update width and height when node dimensions parameters has changed
404
408
  React.useEffect(() => {
@@ -406,15 +410,11 @@ export function NodeContent<CONTENT_PROPS = any>({
406
410
  const updateHeight = nodeDimensions?.height ? validateHeight(nodeDimensions?.height) : undefined;
407
411
  setWidth(updateWidth);
408
412
  setHeight(updateHeight);
409
- if (!nodeDimensions?.width && !nodeDimensions?.height) {
410
- // provoke new measuring if no dimensions are set
411
- saveOriginalSize();
412
- }
413
413
  }, [nodeDimensions]);
414
414
 
415
415
  const isResizingActive = React.useCallback((): boolean => {
416
416
  const currentClassNames = nodeContentRef.current.classList;
417
- return resizeDirections.right === currentClassNames.contains("is-resizable-horizontal") &&
417
+ return resizeDirections.right === currentClassNames.contains("is-resizable-horizontal") ||
418
418
  resizeDirections.bottom === currentClassNames.contains("is-resizable-vertical");
419
419
  }, [])
420
420
 
@@ -439,17 +439,17 @@ export function NodeContent<CONTENT_PROPS = any>({
439
439
 
440
440
  if (isResizable && !resizingActive) {
441
441
  if (currentClassNames.contains("is-resizable-horizontal")) {
442
- nodeContentRef.current.classList.remove("is-resizable-horizontal");
442
+ currentClassNames.remove("is-resizable-horizontal");
443
443
  }
444
444
  if (currentClassNames.contains("is-resizable-vertical")) {
445
- nodeContentRef.current.classList.remove("is-resizable-vertical");
445
+ currentClassNames.remove("is-resizable-vertical");
446
446
  }
447
-
447
+
448
448
  if (resizeDirections.right) {
449
- nodeContentRef.current.classList.add("is-resizable-horizontal");
449
+ currentClassNames.add("is-resizable-horizontal");
450
450
  }
451
451
  if (resizeDirections.bottom) {
452
- nodeContentRef.current.classList.add("is-resizable-vertical");
452
+ currentClassNames.add("is-resizable-vertical");
453
453
  }
454
454
  }
455
455
  }); // need to be done everytime a property is changed and the element is re-rendered, otherwise the resizing class is lost
@@ -524,8 +524,8 @@ export function NodeContent<CONTENT_PROPS = any>({
524
524
  ? {
525
525
  width,
526
526
  height,
527
- maxWidth: resizeMaxDimensions?.width ?? undefined,
528
- maxHeight: resizeMaxDimensions?.height ?? undefined,
527
+ maxWidth: resizeDirections.right ? resizeMaxDimensions?.width ?? undefined : undefined,
528
+ maxHeight: resizeDirections.bottom ? resizeMaxDimensions?.height ?? undefined : undefined,
529
529
  }
530
530
  : {};
531
531
 
@@ -705,6 +705,10 @@ export function NodeContent<CONTENT_PROPS = any>({
705
705
  const nextHeight = resizeDirections.bottom
706
706
  ? (height ?? originalSize.current.height ?? 0) + d.height
707
707
  : undefined;
708
+ if (nextWidth || nextHeight) {
709
+ const currentClassNames = nodeContentRef.current.classList;
710
+ currentClassNames.add("was-resized");
711
+ }
708
712
  if (nextWidth) {
709
713
  nodeContentRef.current.style.width = `${nextWidth}px`;
710
714
  }
@@ -50,7 +50,7 @@
50
50
  box-shadow: 0 0 0 6 * $reactflow-node-border-width rgba($reactflow-edge-stroke-color-selected, 0.05);
51
51
  }
52
52
 
53
- &.is-resizable-vertical {
53
+ &.was-resized.is-resizable-vertical {
54
54
  max-height: unset;
55
55
  }
56
56
  }
@@ -103,11 +103,12 @@ export default {
103
103
  },
104
104
  intent: {
105
105
  control: "select",
106
- options: { "Not set": undefined, ...Definitions },
106
+ options: [ undefined, ...Object.values(Definitions) ],
107
107
  },
108
108
  highlightColor: {
109
109
  control: "select",
110
- options: {
110
+ options: [ "Not set", "Default", "Alternate", "Default + alternate", "Custom (red)", "Default + Custom (red)", "Custom (green) + alternate", "Custom (purple) + custom (yellow)"],
111
+ mapping: {
111
112
  "Not set": undefined,
112
113
  Default: "default",
113
114
  Alternate: "alternate",
@@ -118,8 +119,8 @@ export default {
118
119
  "Custom (purple) + custom (yellow)": ["purple", "yellow"],
119
120
  },
120
121
  },
121
- content: { control: "none" },
122
- footerContent: { control: "none" },
122
+ content: { control: false },
123
+ footerContent: { control: false },
123
124
  isConnectable: { table: { disable: true } },
124
125
  targetPosition: { table: { disable: true } },
125
126
  sourcePosition: { table: { disable: true } },
@@ -128,17 +129,52 @@ export default {
128
129
  },
129
130
  } as Meta<typeof NodeContent>;
130
131
 
132
+ let forcedUpdateKey = 0; // @see https://github.com/storybookjs/storybook/issues/13375#issuecomment-1291011856
131
133
  const NodeContentExample = (args: any) => {
132
134
  const [reactflowInstance, setReactflowInstance] = useState(null);
133
135
  const [elements, setElements] = useState([] as Elements);
134
136
 
137
+ const defaultElement = {
138
+ id: "example-1",
139
+ type: "default",
140
+ data: args,
141
+ position: { x: 50, y: 50 },
142
+ };
143
+
135
144
  useEffect(() => {
145
+ const sizeReset = {}
146
+ if (args.resizeMaxDimensions && args.resizeDirections) {
147
+ sizeReset["onNodeResize"] = (dimensions) => {
148
+ // eslint-disable-next-line no-console
149
+ console.log("call onNodeResize method")
150
+ if (args.onNodeResize) {
151
+ args.onNodeResize(dimensions);
152
+ }
153
+ if (dimensions?.width || dimensions?.height) {
154
+ sizeReset["menuButtons"] = <IconButton name="item-reset" onClick={() => {
155
+ // eslint-disable-next-line no-console
156
+ console.log("reset size");
157
+ setElements([
158
+ {
159
+ ...defaultElement,
160
+ data: {...defaultElement.data, ...sizeReset, ...{ nodeDimensions: {} }},
161
+ },
162
+ ] as Elements);
163
+
164
+ }}/>;
165
+ }
166
+ setElements([
167
+ {
168
+ ...defaultElement,
169
+ data: {...defaultElement.data, ...sizeReset, ...{ nodeDimensions: dimensions }},
170
+ },
171
+ ] as Elements);
172
+ }
173
+ }
136
174
  setElements([
137
175
  {
138
- id: "example-1",
139
- type: "default",
140
- data: args,
141
- position: { x: 50, y: 50 },
176
+ ...defaultElement,
177
+ data: {...defaultElement.data, ...sizeReset},
142
178
  },
143
179
  ] as Elements);
144
180
  }, [args]);
@@ -165,7 +201,7 @@ const NodeContentExample = (args: any) => {
165
201
  );
166
202
  };
167
203
 
168
- const Template: StoryFn<typeof NodeContent> = (args) => <NodeContentExample {...args} /*some comment*/ />;
204
+ const Template: StoryFn<typeof NodeContent> = (args) => <NodeContentExample {...args} /*some comment*/ key={++forcedUpdateKey} />;
169
205
 
170
206
  export const Default = Template.bind({});
171
207
  Default.args = {