⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4eb1823
Add parameter to activity control action to set the state of its bu…
andreas-schultz Dec 8, 2025
c9d00c9
MultiSelect: Change default filter predicate to match multi-word queries
andreas-schultz Dec 10, 2025
555cbf1
Merge branch 'develop' into feature/extendActivityControl-CMEM-7150
andreas-schultz Jan 8, 2026
79162a9
extend parameter by property in order to display a notification in …
andreas-schultz Jan 12, 2026
e6cbf3a
fix disabled state changes
haschek Jan 13, 2026
822d56b
Merge remote-tracking branch 'origin/develop' into feature/extendActi…
haschek Jan 13, 2026
9afbdc1
update changelog
haschek Jan 13, 2026
e353885
provide functionality to include transformed carbon icons to the cano…
haschek Jan 15, 2026
ad60605
update changelog
haschek Jan 15, 2026
e01c624
fix edge label when it has no label
haschek Jan 15, 2026
326fa79
reduce stroke width
haschek Jan 15, 2026
2675f1e
use scrollbars on edge tools menu if content is too large on y-axis
haschek Jan 19, 2026
8ed0fa1
fix color of buttons used in tour stepper
haschek Jan 19, 2026
b99587f
add some default margin to each side
haschek Jan 20, 2026
dc09382
Revert "add some default margin to each side"
haschek Jan 20, 2026
39f406c
add DecoupledOverlay component
haschek Jan 20, 2026
123c3cd
use DecoupledOverlay for VisualTour
haschek Jan 20, 2026
6fb807e
fix comment and css classes of component
haschek Jan 20, 2026
239bafb
fix keys in element arrays
haschek Jan 21, 2026
7646e53
provide option to add whitespace around overlay content
haschek Jan 21, 2026
6612baf
support paddingSize property
haschek Jan 21, 2026
a1d12a7
use DecoupledOverlay for the notification
haschek Jan 21, 2026
169e06c
lower z-index, otherwise it is always positioned over other modals.
haschek Jan 22, 2026
9bf99a5
fix z-index
haschek Jan 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- `<ApplicationViewability />`
- component for hiding elements in specific media
- `<InlineText />`
- force children to get displayed as inline content
- force children to get displayed as inline content
- `<StringPreviewContentBlobToggler />`
- `useOnly` property: specify if only parts of the content should be used for the shortened preview, this property replaces `firstNonEmptyLineOnly`
- `useOnly` property: specify if only parts of the content should be used for the shortened preview, this property replaces `firstNonEmptyLineOnly`
- new icons:
- `state-confirmed-all`
- `state-declined-all`

### Fixed

- `<Tag />`
- create more whitespace inside `small` tag
- reduce visual impact of border
- `<StringPreviewContentBlobToggler />`
- take Markdown rendering into account before testing the maximum preview length
- `<NodeContent />`
- header-menu items are vertically centered now
- take Markdown rendering into account before testing the maximum preview length
- `<CodeEditor />`
- fix `disabled` property update

### Changed

Expand All @@ -37,16 +40,28 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- `<FlexibleLayoutItem />`
- `<GridColumn />`
- `<PropertyName />` and `<PropertyValue />`
- `<EdgeDefault />`
- reduce stroke width to only 1px

### Deprecated

- `<StringPreviewContentBlobToggler />`
- `firstNonEmptyLineOnly` will be removed, is replaced by `useOnly="firstNonEmptyLine"`
- `firstNonEmptyLineOnly` will be removed, is replaced by `useOnly="firstNonEmptyLine"`

## [25.0.0] - 2025-12-01

This is a major release, and it might be not compatible with your current usage of our library. Please read about the necessary changes in the section about how to migrate.

### Added

- `<ActivityControlWidget />`
- Add parameter `active` to activity control action to set the `active` state of its button.

### Changed

- `<MultiSelect />`:
- Change default filter predicate to match multi-word queries.

### Migration from v24 to v25

- remove deprecated components, properties and imports from your project, if the info cannot be found here then it was already mentioned in **Deprecated** sections of the past changelogs
Expand Down
65 changes: 44 additions & 21 deletions src/cmem/ActivityControl/ActivityControlWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import React from "react";

import { ValidIconName } from "../../components/Icon/canonicalIconNames";
import { IconProps } from "../../components/Icon/Icon";
import { TestIconProps } from "../../components/Icon/TestIcon";
import { TestableComponent } from "../../components/interfaces";
import { ProgressBarProps } from "../../components/ProgressBar/ProgressBar";
import { SpinnerProps } from "../../components/Spinner/Spinner";
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
import {ValidIconName} from "../../components/Icon/canonicalIconNames";
import {IconProps} from "../../components/Icon/Icon";
import {TestIconProps} from "../../components/Icon/TestIcon";
import {TestableComponent} from "../../components/interfaces";
import {ProgressBarProps} from "../../components/ProgressBar/ProgressBar";
import {SpinnerProps} from "../../components/Spinner/Spinner";
import {CLASSPREFIX as eccgui} from "../../configuration/constants";
import {
Card,
ContextMenu,
DecoupledOverlay,
IconButton,
MenuItem,
Notification,
NotificationProps,
OverflowText,
OverviewItem,
OverviewItemActions,
Expand Down Expand Up @@ -97,14 +100,24 @@ interface IActivityContextMenu extends TestableComponent {
export interface ActivityControlWidgetAction extends TestableComponent {
// The action that should be triggered
action: () => void;
// The tooltip that should be shown over the action icon
// The tooltip that should be shown over the action icon on hover
tooltip?: string;
// The icon of the action button
icon: ValidIconName | React.ReactElement<TestIconProps>;
// Action is currently disabled (but shown)
disabled?: boolean;
// Warning state
hasStateWarning?: boolean;
// Active state
active?: boolean
/** A notification that is shown in an overlay pointing at the activity action button. */
notification?: {
message: string
onClose: () => void
intent?: NotificationProps["intent"]
// Timeout in ms before notification is closed. Default: none
timeout?: number
}
}

interface IActivityMenuAction extends ActivityControlWidgetAction {
Expand Down Expand Up @@ -210,13 +223,9 @@ export function ActivityControlWidget(props: ActivityControlWidgetProps) {
>
{activityActions &&
activityActions.map((action, idx) => {
return (
const actionButtonRef = React.useRef(null);
const ActionButton = () => (
<IconButton
key={
typeof action.icon === "string"
? action.icon
: action["data-test-id"] ?? action["data-testid"] ?? idx
}
data-test-id={action["data-test-id"]}
data-testid={action["data-testid"]}
name={action.icon}
Expand All @@ -226,10 +235,28 @@ export function ActivityControlWidget(props: ActivityControlWidgetProps) {
intent={action.hasStateWarning ? "warning" : undefined}
tooltipProps={{
hoverOpenDelay: 200,
placement: "bottom",
placement: "bottom"
}}
active={action.active}
/>
);
)
return action.notification ?
<>
<span key={idx} ref={actionButtonRef}>
<ActionButton />
</span>
{actionButtonRef.current && (
<DecoupledOverlay targetSelectorOrElement={actionButtonRef.current} paddingSize={"small"}>
<Notification
message={action.notification.message}
intent={action.notification.intent ?? "neutral"}
onDismiss={action.notification.onClose}
timeout={action.notification.timeout}
/>
</DecoupledOverlay>
)}
</> :
<ActionButton key={idx} />
})}
{additionalActions}
{activityContextMenu && activityContextMenu.menuItems.length > 0 && (
Expand All @@ -241,11 +268,7 @@ export function ActivityControlWidget(props: ActivityControlWidgetProps) {
return (
<MenuItem
icon={menuAction.icon}
key={
typeof menuAction.icon === "string"
? menuAction.icon
: menuAction["data-test-id"] ?? idx
}
key={idx}
onClick={menuAction.action}
text={menuAction.tooltip}
/>
Expand Down
21 changes: 20 additions & 1 deletion src/components/ContextOverlay/ContextOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
Utils as BlueprintUtils,
} from "@blueprintjs/core";

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

export interface ContextOverlayProps extends Omit<BlueprintPopoverProps, "position"> {
/**
Expand All @@ -24,6 +24,11 @@ export interface ContextOverlayProps extends Omit<BlueprintPopoverProps, "positi
* Currently experimental.
*/
usePlaceholder?: boolean;
/**
* Adds white space to each side of the overlay content.
* For more control use `WhiteSpaceContainer` directly as wrapper for the content children.
*/
paddingSize?: WhiteSpaceContainerProps["paddingTop"];
}

/**
Expand All @@ -36,6 +41,8 @@ export const ContextOverlay = ({
preventTopPosition,
className = "",
usePlaceholder = false,
paddingSize,
content,
...otherPopoverProps
}: ContextOverlayProps) => {
const placeholderRef = React.useRef<HTMLElement>(null);
Expand Down Expand Up @@ -169,6 +176,18 @@ export const ContextOverlay = ({
) : (
<BlueprintPopover
placement="bottom"
content={content ? (
paddingSize ? (
<WhiteSpaceContainer
paddingTop={paddingSize}
paddingRight={paddingSize}
paddingBottom={paddingSize}
paddingLeft={paddingSize}
>
{content}
</WhiteSpaceContainer>
) : content
) : undefined}
{...otherPopoverProps}
className={targetClassName}
portalClassName={portalClassNameFinal.trim() ?? undefined}
Expand Down
30 changes: 30 additions & 0 deletions src/components/DecoupledOverlay/DecoupledOverlay.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from "react";
import { Meta, StoryFn } from "@storybook/react";

import { DecoupledOverlay, DecoupledOverlayProps, Tag, WhiteSpaceContainer } from "../../../index";

export default {
title: "Components/DecoupledOverlay",
component: DecoupledOverlay,
argTypes: {},
} as Meta<typeof DecoupledOverlay>;

const Template: StoryFn<typeof DecoupledOverlay> = (args: DecoupledOverlayProps) => {
return (
<>
<Tag id={"decoupledTarget"}>Decoupled target</Tag>
<DecoupledOverlay {...args} />
</>
);
};

export const Default = Template.bind({});

Default.args = {
children: (
<WhiteSpaceContainer marginTop={"small"} marginRight={"small"} marginBottom={"small"} marginLeft={"small"}>
Decoupled overlay
</WhiteSpaceContainer>
),
targetSelectorOrElement: "#decoupledTarget",
};
97 changes: 97 additions & 0 deletions src/components/DecoupledOverlay/DecoupledOverlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from "react";
import { createPortal } from "react-dom";
import { Classes as BlueprintClasses } from "@blueprintjs/core";
import { createPopper } from "@popperjs/core";

import { CLASSPREFIX as eccgui, ContextOverlayProps, TestableComponent, TooltipSize, WhiteSpaceContainer } from "../../index";

export interface DecoupledOverlayProps
extends React.HTMLAttributes<HTMLDivElement>,
TestableComponent,
Pick<ContextOverlayProps, "usePortal" | "portalContainer" | "placement" | "minimal" | "paddingSize"> {
/**
* Element that should be used. The step content is displayed as a tooltip instead of a modal.
* In case of an array, the first match is highlighted. */
targetSelectorOrElement: string | Element;
/**
* The size of the overlay.
* */
size?: TooltipSize;
}

/**
* Use an overlay popover without the necessity to use a target that need to be rendered in place.
* The target is referenced by a selector string or element object.
* It can exist somewhere in the DOM, but it must exist when the overlay is rendered.
* It is always displayed, close it by removement.
*/
export const DecoupledOverlay = ({
targetSelectorOrElement,
usePortal = true,
portalContainer = document.body,
minimal = false,
placement = "auto",
size = "large",
paddingSize,
children,
}: DecoupledOverlayProps) => {
const overlayRef = React.useCallback(
(overlay: HTMLDivElement | null) => {
const target =
typeof targetSelectorOrElement === "string"
? document.querySelector(targetSelectorOrElement)
: targetSelectorOrElement;
if (overlay && target) {
createPopper(target, overlay, {
placement: placement,
modifiers: [
{
name: "offset",
options: {
offset: [0, 15],
},
},
],
});
}
},
[targetSelectorOrElement]
);

const overlay = (
<div
className={
`${eccgui}-decoupled-overlay` +
` ${eccgui}-decoupled-overlay--${size}` +
` ${BlueprintClasses.POPOVER}` +
(minimal ? ` ${BlueprintClasses.MINIMAL}` : "")
}
role="tooltip"
ref={overlayRef}
>
{!minimal && (
<div
className={`${eccgui}-decoupled-overlay__arrow ${BlueprintClasses.POPOVER_ARROW}`}
data-popper-arrow
aria-hidden
/>
)}
<div className={`${BlueprintClasses.POPOVER_CONTENT} ${eccgui}-decoupled-overlay__content`}>
{paddingSize ? (
<WhiteSpaceContainer
paddingTop={paddingSize}
paddingRight={paddingSize}
paddingBottom={paddingSize}
paddingLeft={paddingSize}
>
{children}
</WhiteSpaceContainer>
) : children}
</div>
</div>
);

return usePortal ? createPortal(overlay, portalContainer) : overlay;
};

export default DecoupledOverlay;
46 changes: 46 additions & 0 deletions src/components/DecoupledOverlay/_decoupledoverlay.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
.#{$eccgui}-decoupled-overlay__arrow {
&::before {
background: $card-background-color;
}

.#{$eccgui}-decoupled-overlay[data-popper-placement="top"] & {
bottom: -0.5 * $eccgui-size-block-whitespace;
}
.#{$eccgui}-decoupled-overlay[data-popper-placement="right"] & {
left: -0.5 * $eccgui-size-block-whitespace;
}
.#{$eccgui}-decoupled-overlay[data-popper-placement="bottom"] & {
top: -0.5 * $eccgui-size-block-whitespace;
}
.#{$eccgui}-decoupled-overlay[data-popper-placement="left"] & {
right: -0.5 * $eccgui-size-block-whitespace;
}
}

.#{$eccgui}-decoupled-overlay {
&.#{$prefix-blueprintjs}-popover {
z-index: 8001;
}

&--small {
@extend .#{$eccgui}-tooltip--small;
}

&--medium {
@extend .#{$eccgui}-tooltip--medium;
}

&--large {
@extend .#{$eccgui}-tooltip--large;
}

&:has(.#{$eccgui}-decoupled-overlay__arrow) {
.#{$eccgui}-decoupled-overlay__content {
min-height: 30px; // height of blueprint arrow
}
}
}

.#{$eccgui}-decoupled-overlay__content {
padding: 0.1px; // force margins of children to stay inside
}
Loading