@eccenca/gui-elements 24.4.1-featurepreparefinalnextcmem6943.2 → 25.0.0-featureimproveprintstylescmem6985.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 (149) hide show
  1. package/CHANGELOG.md +74 -19
  2. package/dist/cjs/cmem/markdown/Markdown.js +1 -2
  3. package/dist/cjs/cmem/markdown/Markdown.js.map +1 -1
  4. package/dist/cjs/common/index.js +4 -0
  5. package/dist/cjs/common/index.js.map +1 -1
  6. package/dist/cjs/common/utils/reduceToText.js +94 -0
  7. package/dist/cjs/common/utils/reduceToText.js.map +1 -0
  8. package/dist/cjs/components/Application/ApplicationViewability.js +33 -0
  9. package/dist/cjs/components/Application/ApplicationViewability.js.map +1 -0
  10. package/dist/cjs/components/Application/index.js +1 -0
  11. package/dist/cjs/components/Application/index.js.map +1 -1
  12. package/dist/cjs/components/AutocompleteField/AutoCompleteField.js +1 -1
  13. package/dist/cjs/components/AutocompleteField/AutoCompleteField.js.map +1 -1
  14. package/dist/cjs/components/Button/Button.js +1 -1
  15. package/dist/cjs/components/Button/Button.js.map +1 -1
  16. package/dist/cjs/components/ContextOverlay/ContextMenu.js +2 -2
  17. package/dist/cjs/components/ContextOverlay/ContextMenu.js.map +1 -1
  18. package/dist/cjs/components/ContextOverlay/ContextOverlay.js +65 -18
  19. package/dist/cjs/components/ContextOverlay/ContextOverlay.js.map +1 -1
  20. package/dist/cjs/components/Dialog/Modal.js +15 -3
  21. package/dist/cjs/components/Dialog/Modal.js.map +1 -1
  22. package/dist/cjs/components/Dialog/ModalContext.js +51 -0
  23. package/dist/cjs/components/Dialog/ModalContext.js.map +1 -0
  24. package/dist/cjs/components/Dialog/index.js +1 -0
  25. package/dist/cjs/components/Dialog/index.js.map +1 -1
  26. package/dist/cjs/components/Icon/canonicalIconNames.js +25 -2
  27. package/dist/cjs/components/Icon/canonicalIconNames.js.map +1 -1
  28. package/dist/cjs/components/Spinner/Spinner.js +2 -1
  29. package/dist/cjs/components/Spinner/Spinner.js.map +1 -1
  30. package/dist/cjs/components/TextReducer/TextReducer.js +17 -63
  31. package/dist/cjs/components/TextReducer/TextReducer.js.map +1 -1
  32. package/dist/cjs/extensions/react-flow/nodes/NodeContent.js +2 -2
  33. package/dist/cjs/extensions/react-flow/nodes/NodeContent.js.map +1 -1
  34. package/dist/esm/cmem/markdown/Markdown.js +1 -2
  35. package/dist/esm/cmem/markdown/Markdown.js.map +1 -1
  36. package/dist/esm/common/index.js +4 -0
  37. package/dist/esm/common/index.js.map +1 -1
  38. package/dist/esm/common/utils/reduceToText.js +75 -0
  39. package/dist/esm/common/utils/reduceToText.js.map +1 -0
  40. package/dist/esm/components/Application/ApplicationViewability.js +28 -0
  41. package/dist/esm/components/Application/ApplicationViewability.js.map +1 -0
  42. package/dist/esm/components/Application/index.js +1 -0
  43. package/dist/esm/components/Application/index.js.map +1 -1
  44. package/dist/esm/components/AutocompleteField/AutoCompleteField.js +1 -1
  45. package/dist/esm/components/AutocompleteField/AutoCompleteField.js.map +1 -1
  46. package/dist/esm/components/Button/Button.js +1 -1
  47. package/dist/esm/components/Button/Button.js.map +1 -1
  48. package/dist/esm/components/ContextOverlay/ContextMenu.js +2 -2
  49. package/dist/esm/components/ContextOverlay/ContextMenu.js.map +1 -1
  50. package/dist/esm/components/ContextOverlay/ContextOverlay.js +69 -22
  51. package/dist/esm/components/ContextOverlay/ContextOverlay.js.map +1 -1
  52. package/dist/esm/components/Dialog/Modal.js +15 -3
  53. package/dist/esm/components/Dialog/Modal.js.map +1 -1
  54. package/dist/esm/components/Dialog/ModalContext.js +69 -0
  55. package/dist/esm/components/Dialog/ModalContext.js.map +1 -0
  56. package/dist/esm/components/Dialog/index.js +1 -0
  57. package/dist/esm/components/Dialog/index.js.map +1 -1
  58. package/dist/esm/components/Icon/canonicalIconNames.js +25 -2
  59. package/dist/esm/components/Icon/canonicalIconNames.js.map +1 -1
  60. package/dist/esm/components/Spinner/Spinner.js +2 -1
  61. package/dist/esm/components/Spinner/Spinner.js.map +1 -1
  62. package/dist/esm/components/TextReducer/TextReducer.js +17 -41
  63. package/dist/esm/components/TextReducer/TextReducer.js.map +1 -1
  64. package/dist/esm/extensions/react-flow/nodes/NodeContent.js +2 -2
  65. package/dist/esm/extensions/react-flow/nodes/NodeContent.js.map +1 -1
  66. package/dist/types/cmem/react-flow/StickyNoteModal/StickyNoteModal.d.ts +1 -1
  67. package/dist/types/common/index.d.ts +3 -0
  68. package/dist/types/common/utils/reduceToText.d.ts +10 -0
  69. package/dist/types/components/Application/ApplicationViewability.d.ts +36 -0
  70. package/dist/types/components/Application/index.d.ts +1 -0
  71. package/dist/types/components/Button/Button.d.ts +14 -7
  72. package/dist/types/components/ContextOverlay/ContextMenu.d.ts +1 -1
  73. package/dist/types/components/Dialog/Modal.d.ts +9 -1
  74. package/dist/types/components/Dialog/ModalContext.d.ts +13 -0
  75. package/dist/types/components/Dialog/index.d.ts +1 -0
  76. package/dist/types/components/Icon/canonicalIconNames.d.ts +23 -0
  77. package/dist/types/components/Spinner/Spinner.d.ts +11 -4
  78. package/dist/types/components/Tabs/Tab.d.ts +2 -2
  79. package/dist/types/components/TextReducer/TextReducer.d.ts +13 -1
  80. package/dist/types/extensions/react-flow/edges/EdgeLabel.d.ts +1 -1
  81. package/package.json +5 -3
  82. package/src/cmem/ContentBlobToggler/StringPreviewContentBlobToggler.tsx +1 -1
  83. package/src/cmem/markdown/Markdown.tsx +1 -2
  84. package/src/cmem/react-flow/StickyNoteModal/StickyNoteModal.tsx +1 -1
  85. package/src/cmem/react-flow/_minimap.scss +10 -0
  86. package/src/cmem/react-flow/configuration/_colors-graph.scss +12 -12
  87. package/src/cmem/react-flow/configuration/_colors-linking.scss +8 -8
  88. package/src/cmem/react-flow/configuration/_colors-workflow.scss +11 -11
  89. package/src/common/index.ts +6 -0
  90. package/src/common/scss/_color-functions.scss +5 -0
  91. package/src/common/utils/reduceToText.tsx +82 -0
  92. package/src/components/Application/ApplicationViewability.tsx +61 -0
  93. package/src/components/Application/_content.scss +7 -0
  94. package/src/components/Application/_header.scss +12 -3
  95. package/src/components/Application/_viewability.scss +13 -0
  96. package/src/components/Application/application.scss +1 -0
  97. package/src/components/Application/index.ts +1 -0
  98. package/src/components/Application/stories/ApplicationViewability.stories.tsx +37 -0
  99. package/src/components/Application/tests/ApplicationViewability.test.tsx +43 -0
  100. package/src/components/AutocompleteField/AutoCompleteField.tsx +1 -0
  101. package/src/components/Button/Button.stories.tsx +7 -1
  102. package/src/components/Button/Button.tsx +16 -9
  103. package/src/components/Button/button.scss +86 -24
  104. package/src/components/Card/card.scss +6 -0
  105. package/src/components/Chat/stories/ChatField.stories.tsx +6 -1
  106. package/src/components/Checkbox/checkbox.scss +14 -2
  107. package/src/components/ContentGroup/_contentgroup.scss +9 -0
  108. package/src/components/ContextOverlay/ContextMenu.tsx +4 -1
  109. package/src/components/ContextOverlay/ContextOverlay.tsx +77 -18
  110. package/src/components/ContextOverlay/tests/ContextMenu.test.tsx +43 -0
  111. package/src/components/ContextOverlay/tests/ContextOverlay.test.tsx +71 -0
  112. package/src/components/Depiction/depiction.scss +6 -0
  113. package/src/components/Dialog/Modal.tsx +28 -3
  114. package/src/components/Dialog/ModalContext.tsx +56 -0
  115. package/src/components/Dialog/index.ts +1 -0
  116. package/src/components/Dialog/stories/Modal.stories.tsx +10 -7
  117. package/src/components/Dialog/stories/ModalContext.stories.tsx +153 -0
  118. package/src/components/FlexibleLayout/flexiblelayout.scss +16 -0
  119. package/src/components/Grid/grid.scss +17 -0
  120. package/src/components/Grid/stories/Grid.stories.tsx +10 -7
  121. package/src/components/Grid/stories/GridRow.stories.tsx +13 -7
  122. package/src/components/Icon/canonicalIconNames.tsx +25 -2
  123. package/src/components/Icon/icon.scss +6 -0
  124. package/src/components/Icon/stories/Icon.stories.tsx +65 -5
  125. package/src/components/Icon/stories/IconButton.stories.tsx +2 -1
  126. package/src/components/Notification/Notification.stories.tsx +20 -6
  127. package/src/components/Notification/notification.scss +14 -3
  128. package/src/components/OverviewItem/overviewitem.scss +9 -0
  129. package/src/components/ProgressBar/Stories/ProgressBar.stories.tsx +7 -1
  130. package/src/components/PropertyValuePair/propertyvalue.scss +23 -1
  131. package/src/components/Select/Select.stories.tsx +1 -1
  132. package/src/components/Separation/separation.scss +6 -0
  133. package/src/components/Spinner/Spinner.tsx +13 -3
  134. package/src/components/Spinner/Stories/spinner.stories.tsx +1 -1
  135. package/src/components/Spinner/spinner.scss +5 -1
  136. package/src/components/Table/table.scss +22 -0
  137. package/src/components/Tag/tag.scss +95 -68
  138. package/src/components/TextField/textfield.scss +23 -15
  139. package/src/components/TextReducer/TextReducer.stories.tsx +2 -1
  140. package/src/components/TextReducer/TextReducer.test.tsx +44 -0
  141. package/src/components/TextReducer/TextReducer.tsx +17 -44
  142. package/src/components/VisualTour/stories/VisualTour.stories.tsx +1 -1
  143. package/src/configuration/_palettes.scss +2 -1
  144. package/src/extensions/react-flow/_config.scss +8 -3
  145. package/src/extensions/react-flow/_react-flow_v12.scss +10 -14
  146. package/src/extensions/react-flow/edges/EdgeLabel.tsx +1 -1
  147. package/src/extensions/react-flow/edges/_edges.scss +15 -7
  148. package/src/extensions/react-flow/edges/stories/EdgeDefault.stories.tsx +5 -5
  149. package/src/extensions/react-flow/nodes/NodeContent.tsx +2 -2
@@ -20,7 +20,7 @@ export default {
20
20
  },
21
21
  intent: {
22
22
  ...helpersArgTypes.exampleIntent,
23
- options: ["UNDEFINED", "primary", "success", "warning", "danger"],
23
+ options: ["UNDEFINED", "primary", "accent", "success", "warning", "danger"],
24
24
  },
25
25
  },
26
26
  } as Meta<typeof Button>;
@@ -62,6 +62,8 @@ const TemplateSemantic: StoryFn<typeof Button> = (args) => (
62
62
  <Button {...args} affirmative text="Affirmative action" />
63
63
  <Spacing vertical />
64
64
  <Button {...args} disruptive text="Disruptive action" />
65
+ <Spacing vertical />
66
+ <Button {...args} elevated text="Elevated action" />
65
67
  </OverlaysProvider>
66
68
  );
67
69
  export const ButtonSemantics = TemplateSemantic.bind({});
@@ -74,6 +76,10 @@ const TemplateIntent: StoryFn<typeof Button> = (args) => (
74
76
  <Button {...args} text="Warning" intent="warning" />
75
77
  <Spacing vertical />
76
78
  <Button {...args} text="Danger" intent="danger" />
79
+ <Spacing vertical />
80
+ <Button {...args} text="Primary" intent="primary" />
81
+ <Spacing vertical />
82
+ <Button {...args} text="Accent" intent="accent" />
77
83
  </OverlaysProvider>
78
84
  );
79
85
  export const ButtonIntent = TemplateIntent.bind({});
@@ -17,19 +17,23 @@ import Tooltip, { TooltipProps } from "./../Tooltip/Tooltip";
17
17
  interface AdditionalButtonProps {
18
18
  /**
19
19
  * Always use this when the button triggers an affirmative action, e.g. confirm a process.
20
- * The button is displayed with primary color scheme.
20
+ * The button is displayed with accent color intent.
21
21
  */
22
22
  affirmative?: boolean;
23
23
  /**
24
24
  * Always use this when the button triggers an disruptive action, e.g. delete or remove.
25
- * The button is displayed with primary color scheme.
25
+ * The button is displayed with danger color intent.
26
26
  */
27
27
  disruptive?: boolean;
28
28
  /**
29
29
  * Use this when a button is important enough to highlight it in a set of other buttons.
30
- * The button is displayed with primary color scheme.
30
+ * The button is displayed with accent color intent.
31
31
  */
32
32
  elevated?: boolean;
33
+ /**
34
+ * Intent state visualized by color.
35
+ */
36
+ intent?: BlueprintIntent | "accent";
33
37
  /**
34
38
  * Content displayed in a badge that is attached to the button.
35
39
  * By default it is displayed `{ size: "small", position: "top-right", maxLength: 2 }` and with the same intent state of the button.
@@ -49,18 +53,21 @@ interface AdditionalButtonProps {
49
53
  */
50
54
  tooltipProps?: Partial<Omit<TooltipProps, "content" | "children">>;
51
55
  /**
52
- * If an URL is set then the button is included as HTML anchor element instead of a button form element.
56
+ * Icon displayed on button start.
53
57
  */
54
- //href?: string;
55
58
  icon?: ValidIconName | JSX.Element;
59
+ /**
60
+ * Icon displayed on button end.
61
+ */
56
62
  rightIcon?: ValidIconName | JSX.Element;
57
- //target?: string;
58
63
  }
59
64
 
60
- interface ExtendedButtonProps extends AdditionalButtonProps, Omit<BlueprintButtonProps, "icon" | "rightIcon"> {}
65
+ interface ExtendedButtonProps
66
+ extends AdditionalButtonProps,
67
+ Omit<BlueprintButtonProps, "intent" | "icon" | "rightIcon"> {}
61
68
  interface ExtendedAnchorButtonProps
62
69
  extends AdditionalButtonProps,
63
- Omit<BlueprintAnchorButtonProps, "icon" | "rightIcon"> {}
70
+ Omit<BlueprintAnchorButtonProps, "intent" | "icon" | "rightIcon"> {}
64
71
 
65
72
  export type ButtonProps = ExtendedButtonProps & ExtendedAnchorButtonProps;
66
73
 
@@ -86,7 +93,7 @@ export const Button = ({
86
93
  let intentByFunction;
87
94
  switch (true) {
88
95
  case affirmative || elevated:
89
- intentByFunction = BlueprintIntent.PRIMARY;
96
+ intentByFunction = "accent";
90
97
  break;
91
98
  case disruptive:
92
99
  intentByFunction = BlueprintIntent.DANGER;
@@ -1,5 +1,6 @@
1
1
  @use "sass:color";
2
2
  @use "sass:map";
3
+ @use "sass:list";
3
4
 
4
5
  $button-height: $pt-button-height;
5
6
  $button-border-width: 1px; // !default;
@@ -49,64 +50,125 @@ $dark-button-gradient: $button-gradient; // !default;
49
50
  // $button-outlined-border-disabled-intent-opacity: 0.2 !default;
50
51
 
51
52
  $button-intents: (
52
- "primary": (
53
+ // default - hover - active
54
+ "primary":
55
+ (
56
+ eccgui-color-var("identity", "brand", "900"),
57
+ eccgui-color-mix(
58
+ eccgui-color-var("identity", "brand", "900"),
59
+ eccgui-color-var("identity", "text", "900") 10%
60
+ ),
61
+ eccgui-color-mix(
62
+ eccgui-color-var("identity", "brand", "900"),
63
+ eccgui-color-var("identity", "text", "900") 20%
64
+ )
65
+ ),
66
+ "accent": (
53
67
  eccgui-color-var("identity", "accent", "900"),
54
- eccgui-color-var("identity", "accent", "700"),
55
- eccgui-color-var("identity", "accent", "500"),
68
+ eccgui-color-mix(
69
+ eccgui-color-var("identity", "accent", "900"),
70
+ eccgui-color-var("identity", "text", "900") 10%
71
+ ),
72
+ eccgui-color-mix(eccgui-color-var("identity", "accent", "900"), eccgui-color-var("identity", "text", "900") 20%)
56
73
  ),
57
74
  "success": (
58
75
  eccgui-color-var("semantic", "success", "900"),
59
- eccgui-color-var("semantic", "success", "700"),
60
- eccgui-color-var("semantic", "success", "500"),
76
+ eccgui-color-mix(
77
+ eccgui-color-var("semantic", "success", "900"),
78
+ eccgui-color-var("identity", "text", "900") 10%
79
+ ),
80
+ eccgui-color-mix(
81
+ eccgui-color-var("semantic", "success", "900"),
82
+ eccgui-color-var("identity", "text", "900") 20%
83
+ )
61
84
  ),
62
85
  "warning": (
63
86
  eccgui-color-var("semantic", "warning", "900"),
64
- eccgui-color-var("semantic", "warning", "700"),
65
- eccgui-color-var("semantic", "warning", "500"),
87
+ eccgui-color-mix(
88
+ eccgui-color-var("semantic", "warning", "900"),
89
+ eccgui-color-var("identity", "text", "900") 10%
90
+ ),
91
+ eccgui-color-mix(
92
+ eccgui-color-var("semantic", "warning", "900"),
93
+ eccgui-color-var("identity", "text", "900") 20%
94
+ )
66
95
  ),
67
96
  "danger": (
68
97
  eccgui-color-var("semantic", "danger", "900"),
69
- eccgui-color-var("semantic", "danger", "700"),
70
- eccgui-color-var("semantic", "danger", "500"),
71
- ),
98
+ eccgui-color-mix(
99
+ eccgui-color-var("semantic", "danger", "900"),
100
+ eccgui-color-var("identity", "text", "900") 10%
101
+ ),
102
+ eccgui-color-mix(eccgui-color-var("semantic", "danger", "900"), eccgui-color-var("identity", "text", "900") 20%)
103
+ )
72
104
  );
73
105
 
74
106
  @import "~@blueprintjs/core/src/components/button/button";
75
107
 
76
- .#{$ns}-button {
77
- position: relative;
78
-
79
- .#{$ns}-large {
80
- min-height: mini-units(6);
81
- }
82
-
83
- // special case override: blueprint do not use configured colors here
84
- &.#{$ns}-intent-warning {
85
- @include pt-button-intent(map.get($button-intents, "warning")...);
108
+ @mixin eccgui-enhance-blueprint-button-intent($intentvalue) {
109
+ &.#{$ns}-intent-#{$intentvalue} {
110
+ @include pt-button-intent(map.get($button-intents, $intentvalue)...);
86
111
 
87
112
  &:not(.#{$ns}-disabled).#{$ns}-icon > svg {
88
113
  fill: eccgui-color-rgba($white, 0.7);
89
114
  }
90
115
 
91
116
  &:not(.#{$ns}-disabled):not(.#{$ns}-minimal):not(.#{$ns}-outlined) {
92
- @include pt-button-intent(map.get($button-intents, "warning")...);
117
+ @include pt-button-intent(map.get($button-intents, $intentvalue)...);
93
118
  }
94
119
 
95
120
  &.#{$ns}-minimal,
96
121
  &.#{$ns}-outlined {
97
- color: $eccgui-color-warning-text;
122
+ color: list.nth(map.get($button-intents, $intentvalue), 1);
98
123
  background: none;
99
- border-color: $eccgui-color-warning-text;
124
+ border-color: list.nth(map.get($button-intents, $intentvalue), 1);
100
125
  box-shadow: none;
101
126
 
102
127
  &:disabled,
103
128
  &.#{$ns}-disabled {
104
- color: eccgui-color-rgba($eccgui-color-warning-text, 0.39);
129
+ color: eccgui-color-rgba(list.nth(map.get($button-intents, $intentvalue), 1), $eccgui-opacity-disabled);
130
+ border-color: eccgui-color-rgba(
131
+ list.nth(map.get($button-intents, $intentvalue), 1),
132
+ $eccgui-opacity-disabled
133
+ );
134
+ }
135
+
136
+ &:active:not(:disabled):not(.#{$ns}-disabled),
137
+ &.#{$ns}-active:not(:disabled):not(.#{$ns}-disabled) {
138
+ color: list.nth(map.get($button-intents, $intentvalue), 3);
139
+ background-color: eccgui-color-rgba(
140
+ list.nth(map.get($button-intents, $intentvalue), 3),
141
+ $eccgui-opacity-ghostly
142
+ );
143
+ border-color: list.nth(map.get($button-intents, $intentvalue), 3);
144
+ }
145
+
146
+ &:focus:not(:disabled):not(.#{$ns}-disabled),
147
+ &:hover:not(:disabled):not(.#{$ns}-disabled) {
148
+ color: list.nth(map.get($button-intents, $intentvalue), 2);
149
+ background-color: eccgui-color-rgba(
150
+ list.nth(map.get($button-intents, $intentvalue), 2),
151
+ 0.5 * $eccgui-opacity-ghostly
152
+ );
153
+ border-color: list.nth(map.get($button-intents, $intentvalue), 2);
105
154
  }
106
155
  }
107
156
  }
108
157
  }
109
158
 
159
+ .#{$ns}-button {
160
+ position: relative;
161
+
162
+ .#{$ns}-large {
163
+ min-height: mini-units(6);
164
+ }
165
+
166
+ // special case override: blueprint do not use configured colors here
167
+ @include eccgui-enhance-blueprint-button-intent("primary");
168
+ @include eccgui-enhance-blueprint-button-intent("accent");
169
+ @include eccgui-enhance-blueprint-button-intent("warning");
170
+ }
171
+
110
172
  .#{$ns}-button-text {
111
173
  min-width: 0;
112
174
  }
@@ -288,3 +288,9 @@ $eccgui-size-card-spacing: $eccgui-size-typo-base !default;
288
288
  }
289
289
  }
290
290
  }
291
+
292
+ @media print {
293
+ .#{$eccgui}-card__actions {
294
+ display: none;
295
+ }
296
+ }
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import { Meta, StoryFn } from "@storybook/react";
3
3
 
4
- import { ChatField } from "../../../index";
4
+ import { ChatField, ContextMenu, MenuItem } from "../../../index";
5
5
 
6
6
  export default {
7
7
  title: "Components/Chat/ChatField",
@@ -15,4 +15,9 @@ const TemplateFull: StoryFn<typeof ChatField> = (args) => <ChatField {...args} k
15
15
  export const Default = TemplateFull.bind({});
16
16
  Default.args = {
17
17
  onTextSubmit: (value) => alert(value),
18
+ rightElement: (
19
+ <ContextMenu>
20
+ <MenuItem text="Just a test" />
21
+ </ContextMenu>
22
+ ),
18
23
  };
@@ -24,9 +24,15 @@ $control-indicator-spacing: $eccgui-size-inline-whitespace !default;
24
24
  // $switch-background-color-active: rgba($gray1, 0.5) !default;
25
25
  // $switch-background-color-disabled: $button-background-color-disabled !default;
26
26
  $switch-checked-background-color: $eccgui-color-accent !default;
27
- $switch-checked-background-color-hover: eccgui-color-rgba($switch-checked-background-color, $eccgui-opacity-narrow) !default;
27
+ $switch-checked-background-color-hover: eccgui-color-rgba(
28
+ $switch-checked-background-color,
29
+ $eccgui-opacity-narrow
30
+ ) !default;
28
31
  $switch-checked-background-color-active: $switch-checked-background-color-hover !default;
29
- $switch-checked-background-color-disabled: eccgui-color-rgba($switch-checked-background-color, $eccgui-opacity-disabled) !default;
32
+ $switch-checked-background-color-disabled: eccgui-color-rgba(
33
+ $switch-checked-background-color,
34
+ $eccgui-opacity-disabled
35
+ ) !default;
30
36
 
31
37
  @import "~@blueprintjs/core/src/components/forms/controls"; // Checkbox, Radio, Switch
32
38
 
@@ -73,3 +79,9 @@ $switch-checked-background-color-disabled: eccgui-color-rgba($switch-checked-bac
73
79
  display: inline-block;
74
80
  vertical-align: text-top;
75
81
  }
82
+
83
+ @media print {
84
+ .#{$ns}-control {
85
+ print-color-adjust: exact;
86
+ }
87
+ }
@@ -60,3 +60,12 @@ $eccgui-color-scontentgroup-border-sub: eccgui-color-rgba(
60
60
  flex-shrink: 1;
61
61
  width: 100%;
62
62
  }
63
+
64
+ @media print {
65
+ .#{$eccgui}-contentgroup__header__options {
66
+ display: none;
67
+ }
68
+ .#{$eccgui}-contentgroup--border-sub::after {
69
+ print-color-adjust: exact;
70
+ }
71
+ }
@@ -66,6 +66,8 @@ export const ContextMenu = ({
66
66
  so by default we use the title attribute instead of Tooltip. */
67
67
  tooltipAsTitle = true,
68
68
  preventPlaceholder = false,
69
+ "data-test-id": dataTestId,
70
+ "data-testid": dataTestid,
69
71
  ...restProps
70
72
  }: ContextMenuProps) => {
71
73
  const toggleButton =
@@ -76,7 +78,8 @@ export const ContextMenu = ({
76
78
  text={togglerText}
77
79
  large={togglerLarge}
78
80
  disabled={!!disabled}
79
- data-test-id={restProps["data-test-id"]}
81
+ data-test-id={dataTestId ?? undefined}
82
+ data-testid={dataTestid ?? undefined}
80
83
  />
81
84
  ) : (
82
85
  (togglerElement as ReactElement)
@@ -2,6 +2,7 @@ import React from "react";
2
2
  import {
3
3
  Classes as BlueprintClasses,
4
4
  Popover as BlueprintPopover,
5
+ PopoverInteractionKind as InteractionKind,
5
6
  PopoverProps as BlueprintPopoverProps,
6
7
  Utils as BlueprintUtils,
7
8
  } from "@blueprintjs/core";
@@ -37,8 +38,11 @@ export const ContextOverlay = ({
37
38
  usePlaceholder = false,
38
39
  ...otherPopoverProps
39
40
  }: ContextOverlayProps) => {
40
- const placeholderRef = React.useRef(null);
41
- const eventMemory = React.useRef<undefined | "afterhover" | "afterfocus">(undefined);
41
+ const placeholderRef = React.useRef<HTMLElement>(null);
42
+ const eventMemory = React.useRef<undefined | "mouseenter" | "focusin" | "click">(undefined);
43
+ const swapDelay = React.useRef<null | NodeJS.Timeout>(null);
44
+ const interactionKind = React.useRef<InteractionKind>(otherPopoverProps.interactionKind ?? InteractionKind.CLICK);
45
+ const swapDelayTime = 15;
42
46
  const [placeholder, setPlaceholder] = React.useState<boolean>(
43
47
  // use placeholder only for "simple" overlays without special states
44
48
  !otherPopoverProps.disabled &&
@@ -48,30 +52,85 @@ export const ContextOverlay = ({
48
52
  usePlaceholder
49
53
  );
50
54
 
55
+ const swap = (ev: MouseEvent | globalThis.FocusEvent) => {
56
+ const waitForClick =
57
+ interactionKind.current === InteractionKind.CLICK ||
58
+ interactionKind.current === InteractionKind.CLICK_TARGET_ONLY;
59
+
60
+ if (swapDelay.current) {
61
+ clearTimeout(swapDelay.current);
62
+ }
63
+
64
+ const replacePlaceholder = () => {
65
+ eventMemory.current = ev.type as "mouseenter" | "focusin" | "click";
66
+ setPlaceholder(false);
67
+ };
68
+
69
+ if (waitForClick) {
70
+ ev.stopImmediatePropagation();
71
+ replacePlaceholder();
72
+ return;
73
+ }
74
+
75
+ swapDelay.current = setTimeout(
76
+ replacePlaceholder,
77
+ // we delay the swap for hover/focus to prevent unwanted effects
78
+ // (e.g. event hickup after replacing elements when it is not really necessary)
79
+ swapDelayTime
80
+ );
81
+ };
82
+
51
83
  React.useEffect(() => {
84
+ interactionKind.current = otherPopoverProps.interactionKind ?? InteractionKind.CLICK;
85
+ const waitForClick =
86
+ interactionKind.current === InteractionKind.CLICK ||
87
+ interactionKind.current === InteractionKind.CLICK_TARGET_ONLY;
88
+ const removeEvents = () => {
89
+ if (placeholderRef.current) {
90
+ placeholderRef.current.removeEventListener("click", swap);
91
+ placeholderRef.current.removeEventListener("mouseenter", swap);
92
+ placeholderRef.current.removeEventListener("focusin", swap);
93
+ }
94
+ return;
95
+ };
52
96
  if (placeholderRef.current) {
53
- const swap = (ev: MouseEvent | globalThis.FocusEvent) => {
54
- eventMemory.current = ev.type === "focusin" ? "afterfocus" : "afterhover";
55
- setPlaceholder(false);
56
- };
57
- (placeholderRef.current as HTMLElement).addEventListener("mouseenter", swap);
58
- (placeholderRef.current as HTMLElement).addEventListener("focusin", swap);
97
+ removeEvents(); // remove events in case of interaction kind changed during existence
98
+ if (waitForClick) {
99
+ placeholderRef.current.addEventListener("click", swap);
100
+ } else {
101
+ placeholderRef.current.addEventListener("mouseenter", swap);
102
+ placeholderRef.current.addEventListener("focusin", swap);
103
+ }
59
104
  return () => {
60
- if (placeholderRef.current) {
61
- (placeholderRef.current as HTMLElement).removeEventListener("mouseenter", swap);
62
- (placeholderRef.current as HTMLElement).removeEventListener("focusin", swap);
63
- }
105
+ removeEvents();
64
106
  };
65
107
  }
66
108
  return () => {};
67
- }, [!!placeholderRef.current]);
109
+ }, [!!placeholderRef.current, otherPopoverProps.interactionKind]);
68
110
 
69
111
  const refocus = React.useCallback((node) => {
70
- if (eventMemory.current === "afterfocus" && node) {
71
- const target = node.targetRef.current.children[0];
72
- if (target) {
112
+ const target = node?.targetRef.current.children[0];
113
+ if (!eventMemory.current || !target) {
114
+ return;
115
+ }
116
+ switch (eventMemory.current) {
117
+ case "focusin":
73
118
  target.focus();
74
- }
119
+ break;
120
+ case "click":
121
+ target.click();
122
+ break;
123
+ case "mouseenter":
124
+ // re-check if the cursor is still over the element after swapping the placeholder before triggering the event to bubble up
125
+ (target as HTMLElement).addEventListener(
126
+ "mouseover",
127
+ () => (target as HTMLElement).dispatchEvent(new MouseEvent("mouseover", { bubbles: true })),
128
+ {
129
+ capture: true,
130
+ once: true,
131
+ }
132
+ );
133
+ break;
75
134
  }
76
135
  }, []);
77
136
 
@@ -87,7 +146,7 @@ export const ContextOverlay = ({
87
146
  PlaceholderElement,
88
147
  {
89
148
  ...otherPopoverProps?.targetProps,
90
- className: `${BlueprintClasses.POPOVER_TARGET} ${targetClassName}`,
149
+ className: `${BlueprintClasses.POPOVER_TARGET} ${targetClassName} ${eccgui}-contextoverlay__wrapper--placeholder`,
91
150
  ref: placeholderRef,
92
151
  },
93
152
  React.cloneElement(childTarget, {
@@ -0,0 +1,43 @@
1
+ import React from "react";
2
+ import { fireEvent, render, screen } from "@testing-library/react";
3
+
4
+ import "@testing-library/jest-dom";
5
+
6
+ import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
7
+
8
+ import ContextMenu from "./../ContextMenu";
9
+ import { Default as ContextMenuStory } from "./../ContextMenu.stories";
10
+
11
+ const overlayWrapper = `${eccgui}-contextoverlay`;
12
+ const placeholderClass = `${overlayWrapper}__wrapper--placeholder`;
13
+
14
+ const checkForPlaceholderClass = (container: HTMLElement, tobe: number) => {
15
+ expect(container.getElementsByClassName(placeholderClass).length).toBe(tobe);
16
+ };
17
+
18
+ describe("ContextMenu", () => {
19
+ it("should render placeholder automatically", () => {
20
+ const { container } = render(<ContextMenu {...ContextMenuStory.args} />);
21
+ checkForPlaceholderClass(container, 1);
22
+ });
23
+ it("should not render placeholder when `preventPlaceholder===true`", () => {
24
+ const { container } = render(<ContextMenu {...ContextMenuStory.args} preventPlaceholder={true} />);
25
+ checkForPlaceholderClass(container, 0);
26
+ });
27
+ it("should render placeholder when `preventPlaceholder===false`", () => {
28
+ const { container } = render(<ContextMenu {...ContextMenuStory.args} preventPlaceholder={false} />);
29
+ checkForPlaceholderClass(container, 1);
30
+ });
31
+ it("if no placeholder is used the menu should be displayed on click", async () => {
32
+ const { container } = render(<ContextMenu {...ContextMenuStory.args} preventPlaceholder={true} />);
33
+ checkForPlaceholderClass(container, 0);
34
+ fireEvent.click(container.getElementsByClassName(overlayWrapper)[0]);
35
+ expect(await screen.findByText("First option")).toBeVisible();
36
+ });
37
+ it("if placeholder is used the menu should be displayed on click", async () => {
38
+ const { container } = render(<ContextMenu {...ContextMenuStory.args} preventPlaceholder={false} />);
39
+ checkForPlaceholderClass(container, 1);
40
+ fireEvent.click(container.getElementsByClassName(overlayWrapper)[0]);
41
+ expect(await screen.findByText("First option")).toBeVisible();
42
+ });
43
+ });
@@ -0,0 +1,71 @@
1
+ import React from "react";
2
+ import { PopoverInteractionKind } from "@blueprintjs/core";
3
+ import { fireEvent, render, screen, waitFor } from "@testing-library/react";
4
+
5
+ import "@testing-library/jest-dom";
6
+
7
+ import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
8
+
9
+ import ContextOverlay from "./../ContextOverlay";
10
+ import { Default as ContextOverlayStory } from "./../ContextOverlay.stories";
11
+
12
+ const overlayWrapper = `${eccgui}-contextoverlay`;
13
+ const placeholderClass = `${overlayWrapper}__wrapper--placeholder`;
14
+
15
+ const checkForPlaceholderClass = (container: HTMLElement, tobe: number) => {
16
+ expect(container.getElementsByClassName(placeholderClass).length).toBe(tobe);
17
+ };
18
+
19
+ describe("ContextOverlay", () => {
20
+ it("should not render placeholder automatically", () => {
21
+ const { container } = render(<ContextOverlay {...ContextOverlayStory.args} />);
22
+ checkForPlaceholderClass(container, 0);
23
+ });
24
+ it("should render placeholder when `usePlaceholder===true`", () => {
25
+ const { container } = render(<ContextOverlay {...ContextOverlayStory.args} usePlaceholder={true} />);
26
+ checkForPlaceholderClass(container, 1);
27
+ });
28
+ it("should render no placeholder when `usePlaceholder===false`", () => {
29
+ const { container } = render(<ContextOverlay {...ContextOverlayStory.args} usePlaceholder={false} />);
30
+ checkForPlaceholderClass(container, 0);
31
+ });
32
+ it("if no placeholder is used the overlay should be displayed on click", async () => {
33
+ const { container } = render(<ContextOverlay {...ContextOverlayStory.args} usePlaceholder={false} />);
34
+ fireEvent.click(container.getElementsByClassName(overlayWrapper)[0]);
35
+ expect(await screen.findByText("Overlay:")).toBeVisible();
36
+ });
37
+ it("if no placeholder is used the overlay should be displayed on hover (hover interactionKind)", async () => {
38
+ const { container } = render(
39
+ <ContextOverlay
40
+ {...ContextOverlayStory.args}
41
+ usePlaceholder={false}
42
+ interactionKind={PopoverInteractionKind.HOVER}
43
+ />
44
+ );
45
+ fireEvent.mouseEnter(container.getElementsByClassName(overlayWrapper)[0]);
46
+ expect(await screen.findByText("Overlay:")).toBeVisible();
47
+ });
48
+ it("if placeholder is used the overlay should be displayed on click", async () => {
49
+ const { container } = render(<ContextOverlay {...ContextOverlayStory.args} usePlaceholder={true} />);
50
+ fireEvent.click(container.getElementsByClassName(overlayWrapper)[0]);
51
+ expect(await screen.findByText("Overlay:")).toBeVisible();
52
+ });
53
+ it("if placeholder is used the overlay should be displayed on hover (hover interactionKind)", async () => {
54
+ const { container } = render(
55
+ <ContextOverlay
56
+ {...ContextOverlayStory.args}
57
+ usePlaceholder={true}
58
+ interactionKind={PopoverInteractionKind.HOVER}
59
+ />
60
+ );
61
+ checkForPlaceholderClass(container, 1);
62
+ fireEvent.mouseEnter(container.getElementsByClassName(overlayWrapper)[0]);
63
+ await waitFor(async () => {
64
+ expect(screen.queryByDisplayValue("Overlay:")).toBeNull();
65
+ checkForPlaceholderClass(container, 0);
66
+ // we need to emulate another mouseover to simulate real user behaviour
67
+ fireEvent.mouseOver(container.getElementsByClassName(overlayWrapper)[0]);
68
+ expect(await screen.findByText("Overlay:")).toBeVisible();
69
+ });
70
+ });
71
+ });
@@ -220,3 +220,9 @@ $eccgui-size-depiction-border-radius: $pt-border-radius !default;
220
220
  position: fixed;
221
221
  left: -5000rem;
222
222
  }
223
+
224
+ @media print {
225
+ .#{$eccgui}-depiction {
226
+ print-color-adjust: exact;
227
+ }
228
+ }
@@ -5,12 +5,13 @@ import {
5
5
  Overlay2Props as BlueprintOverlayProps,
6
6
  } from "@blueprintjs/core";
7
7
 
8
+ import { preventReactFlowActionsClasses } from "../../cmem";
8
9
  import { utils } from "../../common";
9
10
  import { CLASSPREFIX as eccgui } from "../../configuration/constants";
10
11
  import { TestableComponent } from "../interfaces";
11
12
 
12
13
  import { Card } from "./../Card";
13
- import {preventReactFlowActionsClasses} from "../../cmem";
14
+ import { ModalContext } from "./ModalContext";
14
15
 
15
16
  export interface ModalProps extends TestableComponent, BlueprintOverlayProps {
16
17
  children: React.ReactNode | React.ReactNode[];
@@ -43,9 +44,17 @@ export interface ModalProps extends TestableComponent, BlueprintOverlayProps {
43
44
  * If this option is used inflationary then this could harm the visibility of other overlays.
44
45
  */
45
46
  forceTopPosition?: boolean;
47
+ /**
48
+ * Modal ID that should be globally unique. If a ModalContext is provided this can be used to track opening/closing of this modal.
49
+ */
50
+ modalId?: string;
51
+ /**
52
+ * Prevents that pan and zooming actions of an existing react-flow instance are triggered while this Modal is open.
53
+ */
54
+ preventReactFlowEvents?: boolean;
46
55
  }
47
56
 
48
- export type ModalSize = "tiny" | "small" | "regular" | "large" | "xlarge" | "fullscreen"
57
+ export type ModalSize = "tiny" | "small" | "regular" | "large" | "xlarge" | "fullscreen";
49
58
 
50
59
  /**
51
60
  * Displays contents on top of other elements, used to create dialogs.
@@ -68,8 +77,24 @@ export const Modal = ({
68
77
  onOpening,
69
78
  "data-test-id": dataTestId,
70
79
  "data-testid": dataTestid,
80
+ modalId,
81
+ preventReactFlowEvents = true,
71
82
  ...otherProps
72
83
  }: ModalProps) => {
84
+ const modalContext = React.useContext(ModalContext)
85
+ const uniqueModalId = React.useRef<string>(modalId ?? Date.now().toString(36) + Math.random().toString(36).substring(2))
86
+
87
+ React.useEffect(() => {
88
+ return () => {
89
+ // Make sure to always remove flag when modal is removed
90
+ modalContext.setModalOpen(uniqueModalId.current, false)
91
+ }
92
+ }, [])
93
+
94
+ React.useEffect(() => {
95
+ modalContext.setModalOpen(uniqueModalId.current, otherProps.isOpen)
96
+ }, [otherProps.isOpen])
97
+
73
98
  const backdropProps: React.HTMLProps<HTMLDivElement> | undefined =
74
99
  !canOutsideClickClose && canEscapeKeyClose
75
100
  ? {
@@ -117,7 +142,7 @@ export const Modal = ({
117
142
  <BlueprintOverlay
118
143
  {...otherProps}
119
144
  backdropProps={backdropProps}
120
- className={`${overlayClassName} ${preventReactFlowActionsClasses}`}
145
+ className={`${overlayClassName} ${preventReactFlowEvents ? preventReactFlowActionsClasses : ""}`}
121
146
  backdropClassName={`${eccgui}-dialog__backdrop`}
122
147
  canOutsideClickClose={canOutsideClickClose}
123
148
  canEscapeKeyClose={canEscapeKeyClose}