Skip to content

Commit 33be4ad

Browse files
committed
Merge remote-tracking branch 'origin/develop' into release/v25.1.0
2 parents 231fc24 + 1a1387c commit 33be4ad

24 files changed

Lines changed: 615 additions & 144 deletions

.storybook/preview.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@ export const decorators = [
1919
];
2020

2121
export const parameters = {
22-
actions: { argTypesRegex: "^on[A-Z].*" },
22+
options: {
23+
storySort: {
24+
order: ["Configuration", "Components", "Forms", "Extensions", "CMEM", "*"],
25+
},
26+
},
27+
actions: {
28+
argTypesRegex: "^on[A-Z].*",
29+
},
2330
controls: {
2431
matchers: {
2532
color: /(background|color)$/i,

CHANGELOG.md

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,53 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
88

99
### Added
1010

11+
- `<ActivityControlWidget />`
12+
- Add parameter `active` to activity control action to set the `active` state of its button.
13+
- action now can have a `active` and `notification` property
1114
- `<ApplicationViewability />`
1215
- component for hiding elements in specific media
1316
- `<InlineText />`
14-
- force children to get displayed as inline content
17+
- force children to get displayed as inline content
18+
- `<DecoupledOverlay />`
19+
- similar to `ContextOverlay` component but not directly linked to a React element, it specifies the target in the DOM to get connected lazy
1520
- `<StringPreviewContentBlobToggler />`
16-
- `useOnly` property: specify if only parts of the content should be used for the shortened preview, this property replaces `firstNonEmptyLineOnly`
21+
- `useOnly` property: specify if only parts of the content should be used for the shortened preview, this property replaces `firstNonEmptyLineOnly`
22+
- `<ContextOverlay />`
23+
- `paddingSize` property to add easily some white space
24+
- CSS custom properties
25+
- beside the color palette we now mirror the most important layout configuration variables as CSS custom properties
26+
- new icons:
27+
- `state-confirmed-all`
28+
- `state-declined-all`
1729

1830
### Fixed
1931

2032
- `<Tag />`
2133
- create more whitespace inside `small` tag
2234
- reduce visual impact of border
2335
- `<StringPreviewContentBlobToggler />`
24-
- take Markdown rendering into account before testing the maximum preview length
36+
- take Markdown rendering into account before testing the maximum preview length
37+
- `<CodeEditor />`
38+
- fix `disabled` property update
39+
- `<VisualTour />`
40+
- fix color of buttons to move to previous/next step
41+
- take Markdown rendering into account before testing the maximum preview length
2542
- `<NodeContent />`
2643
- header-menu items are vertically centered now
44+
- `<Link />`
45+
- stabilize font size for on hover state
46+
- use correct font sizes when `size` property is set
2747
- `Typography`
28-
- adjust displaying fallback symbols in different browsers
48+
- adjust displaying fallback symbols in different browsers
49+
- `<CodeMirror />`
50+
- use the latest provided `onChange` function
2951

3052
### Changed
3153

54+
- `<MultiSelect />`:
55+
- Change default filter predicate to match multi-word queries.
56+
- `<EdgeDefault />`
57+
- reduce stroke width to only 1px
3258
- automatically hide user interaction elements in print view
3359
- all application header components except `<WorkspaceHeader />`
3460
- `<CardActions />` and `<CardOptions />`
@@ -43,7 +69,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
4369
### Deprecated
4470

4571
- `<StringPreviewContentBlobToggler />`
46-
- `firstNonEmptyLineOnly` will be removed, is replaced by `useOnly="firstNonEmptyLine"`
72+
- `firstNonEmptyLineOnly` will be removed, is replaced by `useOnly="firstNonEmptyLine"`
4773

4874
## [25.0.0] - 2025-12-01
4975

src/cmem/ActivityControl/ActivityControlWidget.tsx

Lines changed: 68 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
import React from "react";
22

3-
import { ValidIconName } from "../../components/Icon/canonicalIconNames";
4-
import { IconProps } from "../../components/Icon/Icon";
5-
import { TestIconProps } from "../../components/Icon/TestIcon";
6-
import { TestableComponent } from "../../components/interfaces";
7-
import { ProgressBarProps } from "../../components/ProgressBar/ProgressBar";
8-
import { SpinnerProps } from "../../components/Spinner/Spinner";
9-
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
3+
import {ValidIconName} from "../../components/Icon/canonicalIconNames";
4+
import {IconProps} from "../../components/Icon/Icon";
5+
import {TestIconProps} from "../../components/Icon/TestIcon";
6+
import {TestableComponent} from "../../components/interfaces";
7+
import {ProgressBarProps} from "../../components/ProgressBar/ProgressBar";
8+
import {SpinnerProps} from "../../components/Spinner/Spinner";
9+
import {CLASSPREFIX as eccgui} from "../../configuration/constants";
1010
import {
1111
Card,
1212
ContextMenu,
13+
DecoupledOverlay,
1314
IconButton,
1415
MenuItem,
16+
Notification,
17+
NotificationProps,
1518
OverflowText,
1619
OverviewItem,
1720
OverviewItemActions,
@@ -97,14 +100,24 @@ interface IActivityContextMenu extends TestableComponent {
97100
export interface ActivityControlWidgetAction extends TestableComponent {
98101
// The action that should be triggered
99102
action: () => void;
100-
// The tooltip that should be shown over the action icon
103+
// The tooltip that should be shown over the action icon on hover
101104
tooltip?: string;
102105
// The icon of the action button
103106
icon: ValidIconName | React.ReactElement<TestIconProps>;
104107
// Action is currently disabled (but shown)
105108
disabled?: boolean;
106109
// Warning state
107110
hasStateWarning?: boolean;
111+
// Active state
112+
active?: boolean
113+
/** A notification that is shown in an overlay pointing at the activity action button. */
114+
notification?: {
115+
message: string
116+
onClose: () => void
117+
intent?: NotificationProps["intent"]
118+
// Timeout in ms before notification is closed. Default: none
119+
timeout?: number
120+
}
108121
}
109122

110123
interface IActivityMenuAction extends ActivityControlWidgetAction {
@@ -209,28 +222,11 @@ export function ActivityControlWidget(props: ActivityControlWidgetProps) {
209222
data-test-id={dataTestIdLegacy ? `${dataTestIdLegacy}-actions` : undefined}
210223
>
211224
{activityActions &&
212-
activityActions.map((action, idx) => {
213-
return (
214-
<IconButton
215-
key={
216-
typeof action.icon === "string"
217-
? action.icon
218-
: action["data-test-id"] ?? action["data-testid"] ?? idx
219-
}
220-
data-test-id={action["data-test-id"]}
221-
data-testid={action["data-testid"]}
222-
name={action.icon}
223-
text={action.tooltip}
224-
onClick={action.action}
225-
disabled={action.disabled}
226-
intent={action.hasStateWarning ? "warning" : undefined}
227-
tooltipProps={{
228-
hoverOpenDelay: 200,
229-
placement: "bottom",
230-
}}
231-
/>
232-
);
233-
})}
225+
activityActions.map((action, idx) => <ActivityActionButton
226+
key={idx}
227+
action={action}
228+
/>
229+
)}
234230
{additionalActions}
235231
{activityContextMenu && activityContextMenu.menuItems.length > 0 && (
236232
<ContextMenu
@@ -241,11 +237,7 @@ export function ActivityControlWidget(props: ActivityControlWidgetProps) {
241237
return (
242238
<MenuItem
243239
icon={menuAction.icon}
244-
key={
245-
typeof menuAction.icon === "string"
246-
? menuAction.icon
247-
: menuAction["data-test-id"] ?? idx
248-
}
240+
key={idx}
249241
onClick={menuAction.action}
250242
text={menuAction.tooltip}
251243
/>
@@ -267,3 +259,44 @@ export function ActivityControlWidget(props: ActivityControlWidgetProps) {
267259
<div className={classname}>{widget}</div>
268260
);
269261
}
262+
263+
interface ActivityActionButtonProps {
264+
action: ActivityControlWidgetAction
265+
}
266+
267+
const ActivityActionButton = ({action}: ActivityActionButtonProps) => {
268+
const actionButtonRef = React.useRef(null);
269+
const ActionButton = () => (
270+
<IconButton
271+
data-test-id={action["data-test-id"]}
272+
data-testid={action["data-testid"]}
273+
name={action.icon}
274+
text={action.tooltip}
275+
onClick={action.action}
276+
disabled={action.disabled}
277+
intent={action.hasStateWarning ? "warning" : undefined}
278+
tooltipProps={{
279+
hoverOpenDelay: 200,
280+
placement: "bottom"
281+
}}
282+
active={action.active}
283+
/>
284+
)
285+
return action.notification ?
286+
<>
287+
<span ref={actionButtonRef}>
288+
<ActionButton/>
289+
</span>
290+
{actionButtonRef.current && (
291+
<DecoupledOverlay targetSelectorOrElement={actionButtonRef.current} paddingSize={"small"}>
292+
<Notification
293+
message={action.notification.message}
294+
intent={action.notification.intent ?? "neutral"}
295+
onDismiss={action.notification.onClose}
296+
timeout={action.notification.timeout}
297+
/>
298+
</DecoupledOverlay>
299+
)}
300+
</> :
301+
<ActionButton/>
302+
}

src/components/Application/_colors.scss

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
@use "sass:list";
33

44
:root {
5+
// creating css custom properties from palette colors
56
@each $palette-group-name, $palette-group-tints in $eccgui-color-palette-light {
67
@each $palette-tint-name, $palette-tint-colors in $palette-group-tints {
78
@for $i from 1 through list.length($palette-tint-colors) {
@@ -12,4 +13,18 @@
1213
}
1314
}
1415
}
16+
17+
// set aliases for base colors
18+
--#{$eccgui}-color-primary: #{$eccgui-color-primary};
19+
--#{$eccgui}-color-primary-contrast: #{$eccgui-color-primary-contrast};
20+
--#{$eccgui}-color-accent: #{$eccgui-color-accent};
21+
--#{$eccgui}-color-accent-contrast: #{$eccgui-color-accent-contrast};
22+
--#{$eccgui}-color-success-foreground: #{$eccgui-color-success-text};
23+
--#{$eccgui}-color-success-background: #{$eccgui-color-success-background};
24+
--#{$eccgui}-color-info-foreground: #{$eccgui-color-info-text};
25+
--#{$eccgui}-color-info-background: #{$eccgui-color-info-background};
26+
--#{$eccgui}-color-warning-foreground: #{$eccgui-color-warning-text};
27+
--#{$eccgui}-color-warning-background: #{$eccgui-color-warning-background};
28+
--#{$eccgui}-color-danger-foreground: #{$eccgui-color-danger-text};
29+
--#{$eccgui}-color-danger-background: #{$eccgui-color-danger-background};
1530
}

src/components/ContextOverlay/ContextOverlay.tsx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
Utils as BlueprintUtils,
88
} from "@blueprintjs/core";
99

10-
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
10+
import { CLASSPREFIX as eccgui, WhiteSpaceContainer, WhiteSpaceContainerProps } from "../../index";
1111

1212
export interface ContextOverlayProps extends Omit<BlueprintPopoverProps, "position"> {
1313
/**
@@ -24,6 +24,11 @@ export interface ContextOverlayProps extends Omit<BlueprintPopoverProps, "positi
2424
* Currently experimental.
2525
*/
2626
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"];
2732
}
2833

2934
/**
@@ -36,6 +41,8 @@ export const ContextOverlay = ({
3641
preventTopPosition,
3742
className = "",
3843
usePlaceholder = false,
44+
paddingSize,
45+
content,
3946
...otherPopoverProps
4047
}: ContextOverlayProps) => {
4148
const placeholderRef = React.useRef<HTMLElement>(null);
@@ -169,6 +176,18 @@ export const ContextOverlay = ({
169176
) : (
170177
<BlueprintPopover
171178
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}
172191
{...otherPopoverProps}
173192
className={targetClassName}
174193
portalClassName={portalClassNameFinal.trim() ?? undefined}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 commit comments

Comments
 (0)