@eccenca/gui-elements 24.1.0-rc.5 → 24.1.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 (41) hide show
  1. package/CHANGELOG.md +27 -15
  2. package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js +8 -0
  3. package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
  4. package/dist/cjs/components/OverviewItem/OverviewItem.js +5 -2
  5. package/dist/cjs/components/OverviewItem/OverviewItem.js.map +1 -1
  6. package/dist/cjs/components/OverviewItem/OverviewItemList.js +2 -2
  7. package/dist/cjs/components/OverviewItem/OverviewItemList.js.map +1 -1
  8. package/dist/cjs/components/TextField/SearchField.js +19 -2
  9. package/dist/cjs/components/TextField/SearchField.js.map +1 -1
  10. package/dist/cjs/extensions/codemirror/CodeMirror.js +2 -1
  11. package/dist/cjs/extensions/codemirror/CodeMirror.js.map +1 -1
  12. package/dist/cjs/extensions/react-flow/nodes/NodeContent.js +17 -13
  13. package/dist/cjs/extensions/react-flow/nodes/NodeContent.js.map +1 -1
  14. package/dist/esm/components/AutoSuggestion/AutoSuggestion.js +8 -0
  15. package/dist/esm/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
  16. package/dist/esm/components/OverviewItem/OverviewItem.js +5 -2
  17. package/dist/esm/components/OverviewItem/OverviewItem.js.map +1 -1
  18. package/dist/esm/components/OverviewItem/OverviewItemList.js +2 -2
  19. package/dist/esm/components/OverviewItem/OverviewItemList.js.map +1 -1
  20. package/dist/esm/components/TextField/SearchField.js +35 -2
  21. package/dist/esm/components/TextField/SearchField.js.map +1 -1
  22. package/dist/esm/extensions/codemirror/CodeMirror.js +2 -1
  23. package/dist/esm/extensions/codemirror/CodeMirror.js.map +1 -1
  24. package/dist/esm/extensions/react-flow/nodes/NodeContent.js +17 -13
  25. package/dist/esm/extensions/react-flow/nodes/NodeContent.js.map +1 -1
  26. package/dist/types/components/OverviewItem/OverviewItem.d.ts +13 -1
  27. package/dist/types/components/OverviewItem/OverviewItemList.d.ts +3 -2
  28. package/dist/types/components/TextField/SearchField.d.ts +1 -1
  29. package/package.json +1 -1
  30. package/src/components/AutoSuggestion/AutoSuggestion.tsx +9 -0
  31. package/src/components/Depiction/depiction.scss +7 -0
  32. package/src/components/OverviewItem/OverviewItem.tsx +24 -1
  33. package/src/components/OverviewItem/OverviewItemList.tsx +3 -2
  34. package/src/components/OverviewItem/stories/OverviewItem.stories.tsx +6 -12
  35. package/src/components/TextField/SearchField.tsx +37 -9
  36. package/src/components/TextField/stories/SearchField.stories.tsx +15 -1
  37. package/src/components/TextField/textfield.scss +17 -3
  38. package/src/extensions/codemirror/CodeMirror.tsx +2 -1
  39. package/src/extensions/react-flow/nodes/NodeContent.tsx +18 -14
  40. package/src/extensions/react-flow/nodes/_nodes.scss +1 -1
  41. package/src/extensions/react-flow/nodes/stories/NodeContent.stories.tsx +45 -9
@@ -5,6 +5,7 @@ import { CLASSPREFIX as eccgui } from "../../configuration/constants";
5
5
  export interface OverviewItemListProps extends React.HTMLAttributes<HTMLOListElement> {
6
6
  /**
7
7
  * Displays the element using reduced height and less white space inside.
8
+ * @deprecated (v25) use property directly on `OverviewItem` children.
8
9
  */
9
10
  densityHigh?: boolean;
10
11
  /**
@@ -23,8 +24,8 @@ export interface OverviewItemListProps extends React.HTMLAttributes<HTMLOListEle
23
24
  }
24
25
 
25
26
  /**
26
- * This element can include all basic information and actions to give an overview about the item.
27
- * Mainly used in items list or to create basic widgets.
27
+ * This component is a listing container for multiple `OverviewItem` elements.
28
+ * It should only contains `OverviewItem` children but it does not check and control that condition.
28
29
  */
29
30
  export const OverviewItemList = ({
30
31
  children,
@@ -27,7 +27,7 @@ export default {
27
27
  },
28
28
  argTypes: {
29
29
  children: {
30
- control: "none",
30
+ control: false,
31
31
  description: "Elements used as depiction, text and interactive elements of an overview-item.",
32
32
  },
33
33
  },
@@ -47,6 +47,9 @@ ItemExample.args = {
47
47
  <OverviewItemActions children={ActionsExample.args.children[0]} hiddenInteractions key="hiddenactions" />,
48
48
  <OverviewItemActions children={ActionsExample.args.children[1]} key="actions" />,
49
49
  ],
50
+ densityHigh: false,
51
+ hasSpacing: false,
52
+ hasCardWrapper: false,
50
53
  };
51
54
 
52
55
  export const ItemWithDepictionElement = Template.bind({});
@@ -69,16 +72,7 @@ ItemWithDepictionElement.args = {
69
72
  <OverviewItemActions children={ActionsExample.args.children[0]} hiddenInteractions />,
70
73
  <OverviewItemActions children={ActionsExample.args.children[1]} />,
71
74
  ],
72
- };
73
-
74
- const TemplateCard: StoryFn<typeof OverviewItem> = (args) => (
75
- <Card isOnlyLayout>
76
- <OverviewItem {...args}></OverviewItem>
77
- </Card>
78
- );
79
-
80
- export const ItemInCard = TemplateCard.bind({});
81
- ItemInCard.args = {
82
- ...ItemExample.args,
75
+ densityHigh: false,
83
76
  hasSpacing: true,
77
+ hasCardWrapper: true,
84
78
  };
@@ -35,10 +35,38 @@ export const SearchField = ({
35
35
  className = "",
36
36
  emptySearchInputMessage = "Enter search term",
37
37
  onClearanceHandler,
38
- onClearanceText = "Clear input",
38
+ onClearanceText = "Clear current search term",
39
+ onChange,
39
40
  leftIcon = <Icon name="operation-search" />,
41
+ rightElement,
40
42
  ...otherProps
41
43
  }: SearchFieldProps) => {
44
+ const [value, setValue] = React.useState<string>("");
45
+
46
+ const clearanceButton =
47
+ onClearanceHandler && value ? (
48
+ <IconButton
49
+ data-test-id={otherProps["data-test-id"] && `${otherProps["data-test-id"]}-clear-btn`}
50
+ name="operation-clear"
51
+ text={onClearanceText}
52
+ onClick={() => {
53
+ setValue("");
54
+ onClearanceHandler();
55
+ }}
56
+ />
57
+ ) : undefined;
58
+
59
+ const changeHandlerProcess = (e: React.ChangeEvent<HTMLInputElement>) => {
60
+ setValue(e.target.value);
61
+ if (onChange) {
62
+ onChange(e);
63
+ }
64
+ };
65
+
66
+ React.useEffect(() => {
67
+ setValue(otherProps.value ?? otherProps.defaultValue ?? "");
68
+ }, [otherProps.value, otherProps.defaultValue]);
69
+
42
70
  return (
43
71
  <TextField
44
72
  className={
@@ -50,16 +78,16 @@ export const SearchField = ({
50
78
  placeholder={emptySearchInputMessage}
51
79
  aria-label={emptySearchInputMessage}
52
80
  rightElement={
53
- onClearanceHandler && otherProps.value ? (
54
- <IconButton
55
- data-test-id={otherProps["data-test-id"] && `${otherProps["data-test-id"]}-clear-btn`}
56
- name="operation-clear"
57
- text={onClearanceText ? onClearanceText : "Clear current search term"}
58
- onClick={onClearanceHandler}
59
- />
60
- ) : undefined
81
+ (clearanceButton || rightElement) && (
82
+ <>
83
+ {rightElement}
84
+ {clearanceButton}
85
+ </>
86
+ )
61
87
  }
88
+ onChange={changeHandlerProcess}
62
89
  {...otherProps}
90
+ value={value}
63
91
  type={"search"}
64
92
  leftIcon={leftIcon}
65
93
  round={true}
@@ -1,12 +1,20 @@
1
1
  import React from "react";
2
2
  import { Meta, StoryFn } from "@storybook/react";
3
3
 
4
+ import { helpersArgTypes } from "../../../../.storybook/helpers";
5
+
4
6
  import SearchField from "./../SearchField";
5
7
 
6
8
  export default {
7
9
  title: "Components/SearchField",
8
10
  component: SearchField,
9
11
  argTypes: {
12
+ leftIcon: {
13
+ ...helpersArgTypes.exampleIcon,
14
+ },
15
+ rightElement: {
16
+ ...helpersArgTypes.exampleIcon,
17
+ },
10
18
  hasStatePrimary: { table: { disable: true } },
11
19
  hasStateSuccess: { table: { disable: true } },
12
20
  hasStateWarning: { table: { disable: true } },
@@ -23,7 +31,7 @@ Default.args = {
23
31
  onClearanceText: "",
24
32
  };
25
33
 
26
- export const SearchFieldWithClearanceIcon: StoryFn<typeof SearchField> = (args) => {
34
+ const SearchFieldWithClearanceIconTemplate: StoryFn<typeof SearchField> = (args) => {
27
35
  const [query, setQuery] = React.useState<string>("");
28
36
  return (
29
37
  <SearchField
@@ -34,3 +42,9 @@ export const SearchFieldWithClearanceIcon: StoryFn<typeof SearchField> = (args)
34
42
  />
35
43
  );
36
44
  };
45
+
46
+ export const SearchFieldWithClearanceIcon = SearchFieldWithClearanceIconTemplate.bind({});
47
+ SearchFieldWithClearanceIcon.args = {
48
+ onClearanceHandler: null,
49
+ onClearanceText: "Clear field",
50
+ };
@@ -4,7 +4,8 @@
4
4
  // own vars
5
5
  $eccgui-size-textfield-height-small: $eccgui-size-block-whitespace * 2 !default;
6
6
  $eccgui-size-textfield-height-regular: $eccgui-size-textfield-height-small * $eccgui-size-type-levelratio !default;
7
- $eccgui-size-textfield-height-large: $eccgui-size-textfield-height-regular * $eccgui-size-type-levelratio * $eccgui-size-type-levelratio !default;
7
+ $eccgui-size-textfield-height-large: $eccgui-size-textfield-height-regular * $eccgui-size-type-levelratio *
8
+ $eccgui-size-type-levelratio !default;
8
9
  $eccgui-size-textfield-padding-horizontal-regular: $eccgui-size-inline-whitespace !default;
9
10
  $eccgui-size-textfield-padding-horizontal-small: $eccgui-size-inline-whitespace * 0.5 !default;
10
11
  $eccgui-typo-textfield-fontweight: $eccgui-font-weight-regular !default;
@@ -50,10 +51,23 @@ $input-button-height-small: math.div($eccgui-size-textfield-height-small, $eccgu
50
51
  height: 100%;
51
52
  max-height: $input-button-height-large;
52
53
 
53
- & > .#{eccgui}-icon {
54
+ & > * {
55
+ vertical-align: middle;
56
+ }
57
+
58
+ & > .#{eccgui}-icon,
59
+ & > .#{eccgui}-tooltip__wrapper {
54
60
  display: inline-flex;
61
+ align-items: center;
55
62
  height: 100%;
56
- margin: 0 0.5 * $eccgui-size-block-whitespace;
63
+
64
+ &:first-child {
65
+ margin-left: 0.5 * $eccgui-size-block-whitespace;
66
+ }
67
+
68
+ &:last-child {
69
+ margin-right: 0.5 * $eccgui-size-block-whitespace;
70
+ }
57
71
  }
58
72
  }
59
73
  }
@@ -297,7 +297,8 @@ export const CodeEditor = ({
297
297
  EditorView?.updateListener.of((v: ViewUpdate) => {
298
298
  if (disabled) return;
299
299
 
300
- if (onChange) {
300
+ if (onChange && v.docChanged) {
301
+ // Only fire if the text has actually been changed
301
302
  onChange(v.state.doc.toString());
302
303
  }
303
304
 
@@ -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 = {