@eccenca/gui-elements 25.0.0-bugfixcenterednodecontentmenuitemscmem7184.0 → 25.0.0-featurecolorwheelinputcmem7327.1

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 (101) hide show
  1. package/CHANGELOG.md +34 -4
  2. package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js +17 -13
  3. package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
  4. package/dist/cjs/common/index.js +1 -0
  5. package/dist/cjs/common/index.js.map +1 -1
  6. package/dist/cjs/common/utils/colorHash.js +25 -11
  7. package/dist/cjs/common/utils/colorHash.js.map +1 -1
  8. package/dist/cjs/components/ColorField/ColorField.js +114 -0
  9. package/dist/cjs/components/ColorField/ColorField.js.map +1 -0
  10. package/dist/cjs/components/ContextOverlay/ContextOverlay.js +6 -6
  11. package/dist/cjs/components/ContextOverlay/ContextOverlay.js.map +1 -1
  12. package/dist/cjs/components/DecoupledOverlay/DecoupledOverlay.js +47 -0
  13. package/dist/cjs/components/DecoupledOverlay/DecoupledOverlay.js.map +1 -0
  14. package/dist/cjs/components/Icon/canonicalIconNames.js +3 -0
  15. package/dist/cjs/components/Icon/canonicalIconNames.js.map +1 -1
  16. package/dist/cjs/components/Icon/transformIcon.js +14 -0
  17. package/dist/cjs/components/Icon/transformIcon.js.map +1 -0
  18. package/dist/cjs/components/MultiSelect/MultiSelect.js +2 -1
  19. package/dist/cjs/components/MultiSelect/MultiSelect.js.map +1 -1
  20. package/dist/cjs/components/RadioButton/RadioButton.js +5 -2
  21. package/dist/cjs/components/RadioButton/RadioButton.js.map +1 -1
  22. package/dist/cjs/components/VisualTour/VisualTour.js +24 -32
  23. package/dist/cjs/components/VisualTour/VisualTour.js.map +1 -1
  24. package/dist/cjs/components/index.js +2 -0
  25. package/dist/cjs/components/index.js.map +1 -1
  26. package/dist/cjs/extensions/codemirror/CodeMirror.js +10 -1
  27. package/dist/cjs/extensions/codemirror/CodeMirror.js.map +1 -1
  28. package/dist/cjs/extensions/react-flow/edges/EdgeLabel.js +1 -1
  29. package/dist/cjs/extensions/react-flow/edges/EdgeLabel.js.map +1 -1
  30. package/dist/esm/cmem/ActivityControl/ActivityControlWidget.js +19 -14
  31. package/dist/esm/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
  32. package/dist/esm/common/index.js +2 -1
  33. package/dist/esm/common/index.js.map +1 -1
  34. package/dist/esm/common/utils/colorHash.js +25 -12
  35. package/dist/esm/common/utils/colorHash.js.map +1 -1
  36. package/dist/esm/components/ColorField/ColorField.js +139 -0
  37. package/dist/esm/components/ColorField/ColorField.js.map +1 -0
  38. package/dist/esm/components/ContextOverlay/ContextOverlay.js +3 -3
  39. package/dist/esm/components/ContextOverlay/ContextOverlay.js.map +1 -1
  40. package/dist/esm/components/DecoupledOverlay/DecoupledOverlay.js +41 -0
  41. package/dist/esm/components/DecoupledOverlay/DecoupledOverlay.js.map +1 -0
  42. package/dist/esm/components/Icon/canonicalIconNames.js +3 -0
  43. package/dist/esm/components/Icon/canonicalIconNames.js.map +1 -1
  44. package/dist/esm/components/Icon/transformIcon.js +21 -0
  45. package/dist/esm/components/Icon/transformIcon.js.map +1 -0
  46. package/dist/esm/components/MultiSelect/MultiSelect.js +3 -2
  47. package/dist/esm/components/MultiSelect/MultiSelect.js.map +1 -1
  48. package/dist/esm/components/RadioButton/RadioButton.js +6 -2
  49. package/dist/esm/components/RadioButton/RadioButton.js.map +1 -1
  50. package/dist/esm/components/VisualTour/VisualTour.js +25 -33
  51. package/dist/esm/components/VisualTour/VisualTour.js.map +1 -1
  52. package/dist/esm/components/index.js +2 -0
  53. package/dist/esm/components/index.js.map +1 -1
  54. package/dist/esm/extensions/codemirror/CodeMirror.js +10 -1
  55. package/dist/esm/extensions/codemirror/CodeMirror.js.map +1 -1
  56. package/dist/esm/extensions/react-flow/edges/EdgeLabel.js +1 -1
  57. package/dist/esm/extensions/react-flow/edges/EdgeLabel.js.map +1 -1
  58. package/dist/types/cmem/ActivityControl/ActivityControlWidget.d.ts +9 -0
  59. package/dist/types/common/index.d.ts +2 -1
  60. package/dist/types/common/utils/colorHash.d.ts +4 -3
  61. package/dist/types/components/ColorField/ColorField.d.ts +31 -0
  62. package/dist/types/components/ContextOverlay/ContextOverlay.d.ts +7 -1
  63. package/dist/types/components/DecoupledOverlay/DecoupledOverlay.d.ts +20 -0
  64. package/dist/types/components/Icon/canonicalIconNames.d.ts +2 -0
  65. package/dist/types/components/Icon/transformIcon.d.ts +2 -0
  66. package/dist/types/components/MultiSelect/MultiSelect.d.ts +1 -1
  67. package/dist/types/components/RadioButton/RadioButton.d.ts +8 -2
  68. package/dist/types/components/index.d.ts +2 -0
  69. package/package.json +1 -1
  70. package/src/cmem/ActivityControl/ActivityControlWidget.tsx +68 -35
  71. package/src/common/index.ts +2 -1
  72. package/src/common/utils/colorHash.ts +36 -18
  73. package/src/components/Application/_colors.scss +15 -0
  74. package/src/components/ColorField/ColorField.stories.tsx +69 -0
  75. package/src/components/ColorField/ColorField.tsx +200 -0
  76. package/src/components/ColorField/_colorfield.scss +56 -0
  77. package/src/components/ContextOverlay/ContextOverlay.tsx +20 -1
  78. package/src/components/DecoupledOverlay/DecoupledOverlay.stories.tsx +30 -0
  79. package/src/components/DecoupledOverlay/DecoupledOverlay.tsx +97 -0
  80. package/src/components/DecoupledOverlay/_decoupledoverlay.scss +46 -0
  81. package/src/components/Icon/canonicalIconNames.tsx +3 -0
  82. package/src/components/Icon/transformIcon.tsx +17 -0
  83. package/src/components/Link/Link.stories.tsx +30 -0
  84. package/src/components/Link/link.scss +28 -2
  85. package/src/components/MultiSelect/MultiSelect.tsx +12 -3
  86. package/src/components/RadioButton/RadioButton.tsx +15 -3
  87. package/src/components/RadioButton/radiobutton.scss +13 -0
  88. package/src/components/Tabs/stories/TabTitle.stories.tsx +7 -2
  89. package/src/components/Typography/_reset.scss +1 -0
  90. package/src/components/Typography/typography.scss +5 -0
  91. package/src/components/VisualTour/VisualTour.tsx +30 -50
  92. package/src/components/VisualTour/visualTour.scss +0 -34
  93. package/src/components/index.scss +2 -0
  94. package/src/components/index.ts +2 -0
  95. package/src/configuration/_customproperties.scss +32 -0
  96. package/src/configuration/stories/customproperties.stories.tsx +118 -0
  97. package/src/extensions/codemirror/CodeMirror.tsx +14 -6
  98. package/src/extensions/react-flow/_config.scss +3 -3
  99. package/src/extensions/react-flow/edges/EdgeLabel.tsx +5 -3
  100. package/src/extensions/react-flow/edges/_edges.scss +3 -2
  101. package/src/index.scss +1 -0
@@ -0,0 +1,69 @@
1
+ import React from "react";
2
+ import { Meta, StoryFn } from "@storybook/react";
3
+
4
+ import textFieldTest from "../TextField/stories/TextField.stories";
5
+
6
+ import { ColorField, ColorFieldProps } from "./ColorField";
7
+
8
+ export default {
9
+ title: "Forms/ColorField",
10
+ component: ColorField,
11
+ argTypes: {
12
+ ...textFieldTest.argTypes,
13
+ },
14
+ } as Meta<typeof ColorField>;
15
+
16
+ const Template: StoryFn<typeof ColorField> = (args) => <ColorField {...args}></ColorField>;
17
+
18
+ export const Default = Template.bind({});
19
+ Default.args = {
20
+ onChange: (e) => {
21
+ alert(e.target.value);
22
+ },
23
+ };
24
+
25
+ export const NoPalettePresets = Template.bind({});
26
+ NoPalettePresets.args = {
27
+ ...Default.args,
28
+ colorWeightFilter: [],
29
+ paletteGroupFilter: [],
30
+ allowCustomColor: true,
31
+ };
32
+
33
+ interface TemplateColorHashProps
34
+ extends Pick<ColorFieldProps, "onChange" | "allowCustomColor" | "colorWeightFilter" | "paletteGroupFilter"> {
35
+ stringForColorHashValue: string;
36
+ }
37
+
38
+ const TemplateColorHash: StoryFn<TemplateColorHashProps> = (args: TemplateColorHashProps) => (
39
+ <ColorField
40
+ allowCustomColor={args.allowCustomColor}
41
+ colorWeightFilter={args.colorWeightFilter}
42
+ paletteGroupFilter={args.paletteGroupFilter}
43
+ value={ColorField.calculateColorHashValue(args.stringForColorHashValue, {
44
+ allowCustomColor: args.allowCustomColor,
45
+ colorWeightFilter: args.colorWeightFilter,
46
+ paletteGroupFilter: args.paletteGroupFilter,
47
+ })}
48
+ />
49
+ );
50
+
51
+ /**
52
+ * Component provides a helper function to calculate a color hash from a text,
53
+ * that can be used as `value` or `defaultValue`.
54
+ *
55
+ * ```
56
+ * <ColorField value={ColorField.calculateColorHashValue("MyText")} />
57
+ * ```
58
+ *
59
+ * You can add `options` to set the config for the color palette filters.
60
+ * The same default values like on `ColorField` are used for them.
61
+ */
62
+ export const ColorHashValue = TemplateColorHash.bind({});
63
+ ColorHashValue.args = {
64
+ ...Default.args,
65
+ allowCustomColor: true,
66
+ colorWeightFilter: [300, 500, 700],
67
+ paletteGroupFilter: ["layout", "extra"],
68
+ stringForColorHashValue: "My text that will used to create a color hash as initial value.",
69
+ };
@@ -0,0 +1,200 @@
1
+ import React, { CSSProperties } from "react";
2
+ import classNames from "classnames";
3
+
4
+ import { utils } from "../../common";
5
+ import { ColorWeight, PaletteGroup } from "../../common/utils/colorHash";
6
+ import { CLASSPREFIX as eccgui } from "../../configuration/constants";
7
+ import { ContextOverlay } from "../ContextOverlay";
8
+ import { FieldSet } from "../Form";
9
+ import { RadioButton } from "../RadioButton/RadioButton";
10
+ import { Spacing } from "../Separation/Spacing";
11
+ import { Tag, TagList } from "../Tag";
12
+ import { TextField, TextFieldProps } from "../TextField";
13
+ import { Tooltip } from "../Tooltip/Tooltip";
14
+ import { WhiteSpaceContainer } from "../Typography";
15
+
16
+ export interface ColorFieldProps extends Omit<TextFieldProps, "invisibleCharacterWarning"> {
17
+ /**
18
+ * Any color can be selected, not only from the configured color palette.
19
+ */
20
+ allowCustomColor?: boolean;
21
+ /**
22
+ * What color weights should be included in the set of allowed colors.
23
+ */
24
+ colorWeightFilter?: ColorWeight[];
25
+ /**
26
+ * What palette groups should be included in the set of allowed colors.
27
+ */
28
+ paletteGroupFilter?: PaletteGroup[];
29
+ }
30
+
31
+ /**
32
+ * Color input field that provides resets from the configured color palette.
33
+ * Use `colorWeightFilter` and `paletteGroupFilter` to filter them.
34
+ */
35
+ export const ColorField = ({
36
+ className = "",
37
+ allowCustomColor = false,
38
+ colorWeightFilter = [100, 300, 700, 900],
39
+ paletteGroupFilter = ["layout"],
40
+ defaultValue,
41
+ value,
42
+ onChange,
43
+ fullWidth = false,
44
+ ...otherTextFieldProps
45
+ }: ColorFieldProps) => {
46
+ const ref = React.useRef(null);
47
+ const [colorValue, setColorValue] = React.useState<string>(defaultValue || value || "#000000");
48
+
49
+ let allowedPaletteColors, disableNativePicker, disabled;
50
+ const updateConfig = () => {
51
+ allowedPaletteColors = utils.getEnabledColorPropertiesFromPalette({
52
+ includePaletteGroup: paletteGroupFilter,
53
+ includeColorWeight: colorWeightFilter,
54
+ minimalColorDistance: 0, // we use all allowed colors, and do not check distances between them
55
+ });
56
+
57
+ disableNativePicker =
58
+ colorWeightFilter.length > 0 && paletteGroupFilter.length > 0 && allowedPaletteColors.length > 0;
59
+ disabled = (!disableNativePicker && !allowCustomColor) || otherTextFieldProps.disabled;
60
+ };
61
+ updateConfig();
62
+ React.useEffect(() => {
63
+ updateConfig();
64
+ }, [allowCustomColor, colorWeightFilter, paletteGroupFilter, otherTextFieldProps]);
65
+
66
+ React.useEffect(() => {
67
+ setColorValue(defaultValue || value || "#000000");
68
+ }, [defaultValue, value]);
69
+
70
+ const forwardOnChange = (forwardedEvent: React.ChangeEvent<HTMLInputElement>) => {
71
+ setColorValue(forwardedEvent.target.value);
72
+ if (onChange) {
73
+ onChange(forwardedEvent);
74
+ }
75
+ };
76
+
77
+ const colorInput = (
78
+ <TextField
79
+ inputRef={ref}
80
+ className={classNames(`${eccgui}-colorfield`, className, {
81
+ [`${eccgui}-colorfield--custom-picker`]: disableNativePicker,
82
+ })}
83
+ // we cannot use `color` type for the custom picker because we do not have control over it then
84
+ type={!disableNativePicker ? "color" : "text"}
85
+ readOnly={disableNativePicker}
86
+ disabled={disabled}
87
+ value={colorValue}
88
+ fullWidth={fullWidth}
89
+ {...otherTextFieldProps}
90
+ onChange={
91
+ !disableNativePicker
92
+ ? (e: React.ChangeEvent<HTMLInputElement>) => {
93
+ forwardOnChange(e);
94
+ }
95
+ : undefined
96
+ }
97
+ style={{ ...otherTextFieldProps.style, [`--eccgui-colorfield-background`]: colorValue } as CSSProperties}
98
+ />
99
+ );
100
+
101
+ return disableNativePicker && !disabled ? (
102
+ <ContextOverlay
103
+ fill={fullWidth}
104
+ content={
105
+ <WhiteSpaceContainer
106
+ paddingTop={"small"}
107
+ paddingRight={"small"}
108
+ paddingBottom={"small"}
109
+ paddingLeft={"small"}
110
+ className={`${eccgui}-colorfield__picker`}
111
+ >
112
+ {allowCustomColor && (
113
+ <>
114
+ <TextField
115
+ type={"color"}
116
+ value={colorValue}
117
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
118
+ forwardOnChange(e);
119
+ }}
120
+ />
121
+ <Spacing size={"small"} />
122
+ </>
123
+ )}
124
+ <FieldSet>
125
+ <TagList
126
+ className={`${eccgui}-colorfield__palette ${eccgui}-colorfield__palette--${
127
+ colorWeightFilter.length >= 3 ? colorWeightFilter.length * 2 : "8"
128
+ }col`}
129
+ >
130
+ {allowedPaletteColors!.map((color: [string, string], idx: number) => [
131
+ <RadioButton
132
+ className={`${eccgui}-colorfield__palette__color`}
133
+ hideIndicator
134
+ value={color[1]}
135
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
136
+ forwardOnChange(e);
137
+ }}
138
+ >
139
+ <Tooltip key={idx} content={color[0].replace(`${eccgui}-color-palette-`, "")}>
140
+ <Tag
141
+ large
142
+ style={{ [`--eccgui-colorfield-palette-color`]: color[1] } as CSSProperties}
143
+ >
144
+ {color[1]}
145
+ </Tag>
146
+ </Tooltip>
147
+ </RadioButton>,
148
+ // Looks like we cannot force some type of line break in the tag list via CSS only
149
+ (idx + 1) % (colorWeightFilter.length >= 3 ? colorWeightFilter.length * 2 : 8) ===
150
+ 0 && (
151
+ <>
152
+ <br className={`${eccgui}-colorfield__palette-linebreak`} />
153
+ </>
154
+ ),
155
+ ])}
156
+ </TagList>
157
+ </FieldSet>
158
+ </WhiteSpaceContainer>
159
+ }
160
+ >
161
+ {colorInput}
162
+ </ContextOverlay>
163
+ ) : (
164
+ colorInput
165
+ );
166
+ };
167
+
168
+ type calculateColorHashValueProps = Pick<
169
+ ColorFieldProps,
170
+ "allowCustomColor" | "colorWeightFilter" | "paletteGroupFilter"
171
+ >;
172
+
173
+ /**
174
+ * Simple helper function that provide simple access to color hash calculation.
175
+ * Using the same default values for the color palette filter.
176
+ */
177
+ ColorField.calculateColorHashValue = (
178
+ text: string,
179
+ options: calculateColorHashValueProps = {
180
+ allowCustomColor: false,
181
+ colorWeightFilter: [100, 300, 700, 900],
182
+ paletteGroupFilter: ["layout"],
183
+ }
184
+ ) => {
185
+ const hash = utils.textToColorHash({
186
+ text,
187
+ options: {
188
+ returnValidColorsDirectly: options.allowCustomColor as boolean,
189
+ enabledColors: utils.getEnabledColorsFromPalette({
190
+ includePaletteGroup: options.paletteGroupFilter,
191
+ includeColorWeight: options.colorWeightFilter,
192
+ minimalColorDistance: 0,
193
+ }),
194
+ },
195
+ });
196
+
197
+ return hash ? hash : undefined;
198
+ };
199
+
200
+ export default ColorField;
@@ -0,0 +1,56 @@
1
+ .#{$eccgui}-colorfield {
2
+ cursor: default;
3
+
4
+ &:not(.#{$ns}-fill) {
5
+ width: 100%;
6
+ max-width: 4 * $eccgui-size-textfield-height-regular;
7
+ }
8
+
9
+ .#{$ns}-input {
10
+ color: var(--#{$eccgui}-colorfield-background);
11
+ cursor: inherit;
12
+ background-color: var(--#{$eccgui}-colorfield-background);
13
+
14
+ &[type="color"] {
15
+ &::-webkit-color-swatch-wrapper {
16
+ display: none;
17
+ }
18
+
19
+ &::-moz-color-swatch {
20
+ display: none;
21
+ }
22
+ }
23
+ }
24
+
25
+ .#{$ns}-input-left-container {
26
+ top: 1px;
27
+ left: 1px !important;
28
+ height: calc(100% - 2px);
29
+ background-color: $eccgui-color-textfield-background;
30
+ }
31
+ .#{$ns}-input-action {
32
+ top: 1px;
33
+ right: 1px !important;
34
+ height: calc(100% - 2px);
35
+ background-color: $eccgui-color-textfield-background;
36
+ }
37
+ }
38
+
39
+ .#{$eccgui}-colorfield__palette {
40
+ & > li:has(.#{$eccgui}-colorfield__palette-linebreak) {
41
+ display: block;
42
+ width: 100%;
43
+ height: 0;
44
+ margin: 0;
45
+ overflow: hidden;
46
+ }
47
+ }
48
+
49
+ .#{$eccgui}-colorfield__palette__color {
50
+ margin: 0;
51
+ .#{$eccgui}-tag__item {
52
+ width: 3rem;
53
+ color: var(--#{$eccgui}-colorfield-palette-color) !important;
54
+ background-color: var(--#{$eccgui}-colorfield-palette-color) !important;
55
+ }
56
+ }
@@ -7,7 +7,7 @@ import {
7
7
  Utils as BlueprintUtils,
8
8
  } from "@blueprintjs/core";
9
9
 
10
- import { CLASSPREFIX as eccgui } from "../../configuration/constants";
10
+ import { CLASSPREFIX as eccgui, WhiteSpaceContainer, WhiteSpaceContainerProps } from "../../index";
11
11
 
12
12
  export interface ContextOverlayProps extends Omit<BlueprintPopoverProps, "position"> {
13
13
  /**
@@ -24,6 +24,11 @@ export interface ContextOverlayProps extends Omit<BlueprintPopoverProps, "positi
24
24
  * Currently experimental.
25
25
  */
26
26
  usePlaceholder?: boolean;
27
+ /**
28
+ * Adds white space to each side of the overlay content.
29
+ * For more control use `WhiteSpaceContainer` directly as wrapper for the content children.
30
+ */
31
+ paddingSize?: WhiteSpaceContainerProps["paddingTop"];
27
32
  }
28
33
 
29
34
  /**
@@ -36,6 +41,8 @@ export const ContextOverlay = ({
36
41
  preventTopPosition,
37
42
  className = "",
38
43
  usePlaceholder = false,
44
+ paddingSize,
45
+ content,
39
46
  ...otherPopoverProps
40
47
  }: ContextOverlayProps) => {
41
48
  const placeholderRef = React.useRef<HTMLElement>(null);
@@ -169,6 +176,18 @@ export const ContextOverlay = ({
169
176
  ) : (
170
177
  <BlueprintPopover
171
178
  placement="bottom"
179
+ content={content ? (
180
+ paddingSize ? (
181
+ <WhiteSpaceContainer
182
+ paddingTop={paddingSize}
183
+ paddingRight={paddingSize}
184
+ paddingBottom={paddingSize}
185
+ paddingLeft={paddingSize}
186
+ >
187
+ {content}
188
+ </WhiteSpaceContainer>
189
+ ) : content
190
+ ) : undefined}
172
191
  {...otherPopoverProps}
173
192
  className={targetClassName}
174
193
  portalClassName={portalClassNameFinal.trim() ?? undefined}
@@ -0,0 +1,30 @@
1
+ import React from "react";
2
+ import { Meta, StoryFn } from "@storybook/react";
3
+
4
+ import { DecoupledOverlay, DecoupledOverlayProps, Tag, WhiteSpaceContainer } from "../../../index";
5
+
6
+ export default {
7
+ title: "Components/DecoupledOverlay",
8
+ component: DecoupledOverlay,
9
+ argTypes: {},
10
+ } as Meta<typeof DecoupledOverlay>;
11
+
12
+ const Template: StoryFn<typeof DecoupledOverlay> = (args: DecoupledOverlayProps) => {
13
+ return (
14
+ <>
15
+ <Tag id={"decoupledTarget"}>Decoupled target</Tag>
16
+ <DecoupledOverlay {...args} />
17
+ </>
18
+ );
19
+ };
20
+
21
+ export const Default = Template.bind({});
22
+
23
+ Default.args = {
24
+ children: (
25
+ <WhiteSpaceContainer marginTop={"small"} marginRight={"small"} marginBottom={"small"} marginLeft={"small"}>
26
+ Decoupled overlay
27
+ </WhiteSpaceContainer>
28
+ ),
29
+ targetSelectorOrElement: "#decoupledTarget",
30
+ };
@@ -0,0 +1,97 @@
1
+ import React from "react";
2
+ import { createPortal } from "react-dom";
3
+ import { Classes as BlueprintClasses } from "@blueprintjs/core";
4
+ import { createPopper } from "@popperjs/core";
5
+
6
+ import { CLASSPREFIX as eccgui, ContextOverlayProps, TestableComponent, TooltipSize, WhiteSpaceContainer } from "../../index";
7
+
8
+ export interface DecoupledOverlayProps
9
+ extends React.HTMLAttributes<HTMLDivElement>,
10
+ TestableComponent,
11
+ Pick<ContextOverlayProps, "usePortal" | "portalContainer" | "placement" | "minimal" | "paddingSize"> {
12
+ /**
13
+ * Element that should be used. The step content is displayed as a tooltip instead of a modal.
14
+ * In case of an array, the first match is highlighted. */
15
+ targetSelectorOrElement: string | Element;
16
+ /**
17
+ * The size of the overlay.
18
+ * */
19
+ size?: TooltipSize;
20
+ }
21
+
22
+ /**
23
+ * Use an overlay popover without the necessity to use a target that need to be rendered in place.
24
+ * The target is referenced by a selector string or element object.
25
+ * It can exist somewhere in the DOM, but it must exist when the overlay is rendered.
26
+ * It is always displayed, close it by removement.
27
+ */
28
+ export const DecoupledOverlay = ({
29
+ targetSelectorOrElement,
30
+ usePortal = true,
31
+ portalContainer = document.body,
32
+ minimal = false,
33
+ placement = "auto",
34
+ size = "large",
35
+ paddingSize,
36
+ children,
37
+ }: DecoupledOverlayProps) => {
38
+ const overlayRef = React.useCallback(
39
+ (overlay: HTMLDivElement | null) => {
40
+ const target =
41
+ typeof targetSelectorOrElement === "string"
42
+ ? document.querySelector(targetSelectorOrElement)
43
+ : targetSelectorOrElement;
44
+ if (overlay && target) {
45
+ createPopper(target, overlay, {
46
+ placement: placement,
47
+ modifiers: [
48
+ {
49
+ name: "offset",
50
+ options: {
51
+ offset: [0, 15],
52
+ },
53
+ },
54
+ ],
55
+ });
56
+ }
57
+ },
58
+ [targetSelectorOrElement]
59
+ );
60
+
61
+ const overlay = (
62
+ <div
63
+ className={
64
+ `${eccgui}-decoupled-overlay` +
65
+ ` ${eccgui}-decoupled-overlay--${size}` +
66
+ ` ${BlueprintClasses.POPOVER}` +
67
+ (minimal ? ` ${BlueprintClasses.MINIMAL}` : "")
68
+ }
69
+ role="tooltip"
70
+ ref={overlayRef}
71
+ >
72
+ {!minimal && (
73
+ <div
74
+ className={`${eccgui}-decoupled-overlay__arrow ${BlueprintClasses.POPOVER_ARROW}`}
75
+ data-popper-arrow
76
+ aria-hidden
77
+ />
78
+ )}
79
+ <div className={`${BlueprintClasses.POPOVER_CONTENT} ${eccgui}-decoupled-overlay__content`}>
80
+ {paddingSize ? (
81
+ <WhiteSpaceContainer
82
+ paddingTop={paddingSize}
83
+ paddingRight={paddingSize}
84
+ paddingBottom={paddingSize}
85
+ paddingLeft={paddingSize}
86
+ >
87
+ {children}
88
+ </WhiteSpaceContainer>
89
+ ) : children}
90
+ </div>
91
+ </div>
92
+ );
93
+
94
+ return usePortal ? createPortal(overlay, portalContainer) : overlay;
95
+ };
96
+
97
+ export default DecoupledOverlay;
@@ -0,0 +1,46 @@
1
+ .#{$eccgui}-decoupled-overlay__arrow {
2
+ &::before {
3
+ background: $card-background-color;
4
+ }
5
+
6
+ .#{$eccgui}-decoupled-overlay[data-popper-placement="top"] & {
7
+ bottom: -0.5 * $eccgui-size-block-whitespace;
8
+ }
9
+ .#{$eccgui}-decoupled-overlay[data-popper-placement="right"] & {
10
+ left: -0.5 * $eccgui-size-block-whitespace;
11
+ }
12
+ .#{$eccgui}-decoupled-overlay[data-popper-placement="bottom"] & {
13
+ top: -0.5 * $eccgui-size-block-whitespace;
14
+ }
15
+ .#{$eccgui}-decoupled-overlay[data-popper-placement="left"] & {
16
+ right: -0.5 * $eccgui-size-block-whitespace;
17
+ }
18
+ }
19
+
20
+ .#{$eccgui}-decoupled-overlay {
21
+ &.#{$prefix-blueprintjs}-popover {
22
+ z-index: 8001;
23
+ }
24
+
25
+ &--small {
26
+ @extend .#{$eccgui}-tooltip--small;
27
+ }
28
+
29
+ &--medium {
30
+ @extend .#{$eccgui}-tooltip--medium;
31
+ }
32
+
33
+ &--large {
34
+ @extend .#{$eccgui}-tooltip--large;
35
+ }
36
+
37
+ &:has(.#{$eccgui}-decoupled-overlay__arrow) {
38
+ .#{$eccgui}-decoupled-overlay__content {
39
+ min-height: 30px; // height of blueprint arrow
40
+ }
41
+ }
42
+ }
43
+
44
+ .#{$eccgui}-decoupled-overlay__content {
45
+ padding: 0.1px; // force margins of children to stay inside
46
+ }
@@ -1,5 +1,6 @@
1
1
  import * as icons from "@carbon/react/icons";
2
2
  import { CarbonIconType as IconType } from "@carbon/react/icons";
3
+ import { transform} from "./transformIcon";
3
4
 
4
5
  const canonicalIcons = {
5
6
  "application-activities": icons.Activity,
@@ -172,8 +173,10 @@ const canonicalIcons = {
172
173
  "state-checked": icons.CheckboxChecked,
173
174
  "state-checkedsimple": icons.Checkmark,
174
175
  "state-confirmed": icons.ThumbsUp,
176
+ "state-confirmed-all": icons.ThumbsUpDouble,
175
177
  "state-danger": icons.ErrorFilled,
176
178
  "state-declined": icons.ThumbsDown,
179
+ "state-declined-all": transform(icons.ThumbsUpDouble, 0, false, true),
177
180
  "state-flagged": icons.Flag,
178
181
  "state-info": icons.InformationFilled,
179
182
  "state-locked": icons.Locked,
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ import { CarbonIconType, CarbonIconProps } from "@carbon/react/icons";
3
+
4
+ export const transform = (IconSymbol: CarbonIconType, rotate: number = 0, flipH: boolean = false, flipV: boolean = false) : CarbonIconType => {
5
+ return React.forwardRef((props: CarbonIconProps, ref: React.ForwardedRef<React.ReactSVGElement>) => {
6
+ return (
7
+ <IconSymbol
8
+ {...props}
9
+ ref={ref}
10
+ transform={
11
+ `scale(${flipH ? "-1" : "1"}, ${flipV ? "-1" : "1"}) rotate(${rotate})`
12
+ }
13
+ />
14
+ );
15
+ })
16
+ }
17
+
@@ -0,0 +1,30 @@
1
+ import React from "react";
2
+ import { Meta, StoryFn } from "@storybook/react";
3
+
4
+ import { Link } from "../../../index";
5
+
6
+ export default {
7
+ title: "Components/Link",
8
+ component: Link,
9
+ argTypes: {
10
+ target: {
11
+ control: "select",
12
+ options: ["_self", "_blank", "_parent", "_top"],
13
+ },
14
+ },
15
+ } as Meta<typeof Link>;
16
+
17
+ const Template: StoryFn<typeof Link> = (args) => <Link {...args} />;
18
+
19
+ export const Default = Template.bind({});
20
+ Default.args = {
21
+ children: "Example link",
22
+ href: "https://example.com/",
23
+ };
24
+
25
+ export const Disabled = Template.bind({});
26
+ Disabled.args = {
27
+ children: "Disabled link",
28
+ href: "https://example.com/",
29
+ disabled: true,
30
+ };
@@ -2,8 +2,34 @@
2
2
  @include link.link;
3
3
 
4
4
  .#{$prefix}--link {
5
- font-size: 1em;
6
- line-height: inherit;
5
+ &,
6
+ &:hover {
7
+ // default case: use font size from context
8
+ font-size: inherit;
9
+ line-height: inherit;
10
+ }
11
+
12
+ &.#{$prefix}--link--sm {
13
+ &,
14
+ &:hover {
15
+ font-size: $eccgui-size-typo-caption;
16
+ line-height: $eccgui-size-typo-caption-lineheight;
17
+ }
18
+ }
19
+ &.#{$prefix}--link--md {
20
+ &,
21
+ &:hover {
22
+ font-size: $eccgui-size-typo-text;
23
+ line-height: $eccgui-size-typo-text-lineheight;
24
+ }
25
+ }
26
+ &.#{$prefix}--link--lg {
27
+ &,
28
+ &:hover {
29
+ font-size: $eccgui-size-typo-subtitle;
30
+ line-height: $eccgui-size-typo-subtitle-lineheight;
31
+ }
32
+ }
7
33
 
8
34
  &:focus {
9
35
  outline: none;
@@ -10,7 +10,15 @@ import { removeExtraSpaces } from "../../common/utils/stringUtils";
10
10
  import { CLASSPREFIX as eccgui } from "../../configuration/constants";
11
11
  import { TestableComponent } from "../interfaces";
12
12
 
13
- import { ContextOverlayProps, Highlighter, IconButton, MenuItem, OverflowText, Spinner } from "./../../index";
13
+ import {
14
+ ContextOverlayProps,
15
+ Highlighter,
16
+ highlighterUtils,
17
+ IconButton,
18
+ MenuItem,
19
+ OverflowText,
20
+ Spinner
21
+ } from "./../../index";
14
22
 
15
23
  export interface MultiSuggestFieldSelectionProps<T> {
16
24
  newlySelected?: T;
@@ -53,7 +61,7 @@ interface MultiSuggestFieldCommonProps<T>
53
61
  /**
54
62
  * prop to listen for query changes, when text is entered in the multi-select input
55
63
  */
56
- runOnQueryChange?: (query: string) => Promise<T[] | undefined>;
64
+ runOnQueryChange?: (query: string) => Promise<T[] | undefined> | (T[] | undefined);
57
65
  /**
58
66
  * Whether the component should take up the full width of its container.
59
67
  * This overrides `tagInputProps.fill`.
@@ -265,7 +273,8 @@ export function MultiSuggestField<T>({
265
273
  };
266
274
 
267
275
  const defaultFilterPredicate = (item: T, query: string) => {
268
- return itemLabel(item).toLowerCase().includes(query);
276
+ const searchWords = highlighterUtils.extractSearchWords(query, true)
277
+ return highlighterUtils.matchesAllWords(itemLabel(item).toLowerCase(), searchWords)
269
278
  };
270
279
 
271
280
  /**