diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b550f94..ef821cc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - `` - component for hiding elements in specific media - `` - - force children to get displayed as inline content + - force children to get displayed as inline content - `` - - `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 @@ -21,9 +24,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - create more whitespace inside `small` tag - reduce visual impact of border - `` - - take Markdown rendering into account before testing the maximum preview length -- `` - - header-menu items are vertically centered now + - take Markdown rendering into account before testing the maximum preview length +- `` + - fix `disabled` property update ### Changed @@ -37,16 +40,28 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - `` - `` - `` and `` +- `` + - reduce stroke width to only 1px ### Deprecated - `` - - `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 + +- `` + - Add parameter `active` to activity control action to set the `active` state of its button. + +### Changed + +- ``: + - 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 diff --git a/src/cmem/ActivityControl/ActivityControlWidget.tsx b/src/cmem/ActivityControl/ActivityControlWidget.tsx index efda5060..b529f96a 100644 --- a/src/cmem/ActivityControl/ActivityControlWidget.tsx +++ b/src/cmem/ActivityControl/ActivityControlWidget.tsx @@ -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, + ContextOverlay, IconButton, MenuItem, + Notification, + NotificationProps, OverflowText, OverviewItem, OverviewItemActions, @@ -97,7 +100,7 @@ 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; @@ -105,6 +108,16 @@ export interface ActivityControlWidgetAction extends TestableComponent { 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 { @@ -210,26 +223,39 @@ export function ActivityControlWidget(props: ActivityControlWidgetProps) { > {activityActions && activityActions.map((action, idx) => { - return ( - - ); + const ActionButton = () => + return action.notification ? + } + defaultIsOpen={true} + onClose={action.notification.onClose} + > + + : + })} {additionalActions} {activityContextMenu && activityContextMenu.menuItems.length > 0 && ( diff --git a/src/components/Icon/canonicalIconNames.tsx b/src/components/Icon/canonicalIconNames.tsx index 93ed7f87..309226b2 100644 --- a/src/components/Icon/canonicalIconNames.tsx +++ b/src/components/Icon/canonicalIconNames.tsx @@ -1,5 +1,6 @@ import * as icons from "@carbon/react/icons"; import { CarbonIconType as IconType } from "@carbon/react/icons"; +import { transform} from "./transformIcon"; const canonicalIcons = { "application-activities": icons.Activity, @@ -172,8 +173,10 @@ const canonicalIcons = { "state-checked": icons.CheckboxChecked, "state-checkedsimple": icons.Checkmark, "state-confirmed": icons.ThumbsUp, + "state-confirmed-all": icons.ThumbsUpDouble, "state-danger": icons.ErrorFilled, "state-declined": icons.ThumbsDown, + "state-declined-all": transform(icons.ThumbsUpDouble, 0, false, true), "state-flagged": icons.Flag, "state-info": icons.InformationFilled, "state-locked": icons.Locked, diff --git a/src/components/Icon/transformIcon.tsx b/src/components/Icon/transformIcon.tsx new file mode 100644 index 00000000..63a716a8 --- /dev/null +++ b/src/components/Icon/transformIcon.tsx @@ -0,0 +1,17 @@ +import React from "react"; +import { CarbonIconType, CarbonIconProps } from "@carbon/react/icons"; + +export const transform = (IconSymbol: CarbonIconType, rotate: number = 0, flipH: boolean = false, flipV: boolean = false) : CarbonIconType => { + return React.forwardRef((props: CarbonIconProps, ref: React.ForwardedRef) => { + return ( + + ); + }) +} + diff --git a/src/components/MultiSelect/MultiSelect.tsx b/src/components/MultiSelect/MultiSelect.tsx index 3685ed86..eb0f07c1 100644 --- a/src/components/MultiSelect/MultiSelect.tsx +++ b/src/components/MultiSelect/MultiSelect.tsx @@ -10,7 +10,15 @@ import { removeExtraSpaces } from "../../common/utils/stringUtils"; import { CLASSPREFIX as eccgui } from "../../configuration/constants"; import { TestableComponent } from "../interfaces"; -import { ContextOverlayProps, Highlighter, IconButton, MenuItem, OverflowText, Spinner } from "./../../index"; +import { + ContextOverlayProps, + Highlighter, + highlighterUtils, + IconButton, + MenuItem, + OverflowText, + Spinner +} from "./../../index"; export interface MultiSuggestFieldSelectionProps { newlySelected?: T; @@ -53,7 +61,7 @@ interface MultiSuggestFieldCommonProps /** * prop to listen for query changes, when text is entered in the multi-select input */ - runOnQueryChange?: (query: string) => Promise; + runOnQueryChange?: (query: string) => Promise | (T[] | undefined); /** * Whether the component should take up the full width of its container. * This overrides `tagInputProps.fill`. @@ -265,7 +273,8 @@ export function MultiSuggestField({ }; const defaultFilterPredicate = (item: T, query: string) => { - return itemLabel(item).toLowerCase().includes(query); + const searchWords = highlighterUtils.extractSearchWords(query, true) + return highlighterUtils.matchesAllWords(itemLabel(item).toLowerCase(), searchWords) }; /** diff --git a/src/extensions/codemirror/CodeMirror.tsx b/src/extensions/codemirror/CodeMirror.tsx index 1fb52353..8ef1a0bf 100644 --- a/src/extensions/codemirror/CodeMirror.tsx +++ b/src/extensions/codemirror/CodeMirror.tsx @@ -227,10 +227,11 @@ export const CodeEditor = ({ }: CodeEditorProps) => { const parent = useRef(undefined); const [view, setView] = React.useState(); - const currentView = React.useRef() - currentView.current = view - const currentReadOnly = React.useRef(readOnly) - currentReadOnly.current = readOnly + const currentView = React.useRef(); + currentView.current = view; + const currentReadOnly = React.useRef(readOnly); + currentReadOnly.current = readOnly; + //const currentDisabled = React.useRef(disabled); const [showPreview, setShowPreview] = React.useState(false); // CodeMirror Compartments in order to allow for re-configuration after initialization const readOnlyCompartment = React.useRef(compartment()) @@ -377,7 +378,7 @@ export const CodeEditor = ({ } if (disabled) { - view.dom.className += ` ${eccgui}-disabled`; + view.dom.classList.add(`${eccgui}-disabled`); } if (intent) { @@ -432,7 +433,14 @@ export const CodeEditor = ({ }, [tabIntentSize]) React.useEffect(() => { - updateExtension(EditorView?.editable.of(!disabled), disabledCompartment.current) + updateExtension(EditorView?.editable.of(!disabled), disabledCompartment.current); + if (view?.dom) { + if (disabled) { + view.dom.classList.add(`${eccgui}-disabled`); + } else { + view.dom.classList.remove(`${eccgui}-disabled`); + } + } }, [disabled]) React.useEffect(() => { diff --git a/src/extensions/react-flow/_config.scss b/src/extensions/react-flow/_config.scss index 296cfadc..34b1b8d1 100644 --- a/src/extensions/react-flow/_config.scss +++ b/src/extensions/react-flow/_config.scss @@ -8,9 +8,9 @@ $reactflow-node-font-size: $eccgui-size-typo-caption !default; $reactflow-node-border-width: 2 * $button-border-width !default; $reactflow-node-border-radius: $button-border-radius !default; $reactflow-edge-rendering: geometricprecision !default; -$reactflow-edge-stroke-width-default: 2px !default; -$reactflow-edge-stroke-width-hover: 2px !default; -$reactflow-edge-stroke-width-selected: 2px !default; +$reactflow-edge-stroke-width-default: 1px !default; +$reactflow-edge-stroke-width-hover: 1px !default; +$reactflow-edge-stroke-width-selected: 1px !default; $reactflow-edge-stroke-opacity-default: $eccgui-opacity-muted !default; $reactflow-edge-stroke-opacity-hover: $eccgui-opacity-narrow !default; $reactflow-edge-stroke-opacity-selected: $eccgui-opacity-regular !default; diff --git a/src/extensions/react-flow/edges/EdgeLabel.tsx b/src/extensions/react-flow/edges/EdgeLabel.tsx index 767146a2..5ebed73a 100644 --- a/src/extensions/react-flow/edges/EdgeLabel.tsx +++ b/src/extensions/react-flow/edges/EdgeLabel.tsx @@ -81,9 +81,11 @@ export const EdgeLabel = memo( })} )} -
- {typeof text === "string" ? {text} : text} -
+ {(title || text) && ( +
+ {text && (typeof text === "string" ? {text} : text)} +
+ )} {!!actions &&
{actions}
} ); diff --git a/src/extensions/react-flow/edges/_edges.scss b/src/extensions/react-flow/edges/_edges.scss index 9583398b..e1ab9741 100644 --- a/src/extensions/react-flow/edges/_edges.scss +++ b/src/extensions/react-flow/edges/_edges.scss @@ -294,6 +294,7 @@ path.react-flow__edge-path-highlight { border: 0.5 * $reactflow-node-border-width solid transparent; border-color: var(--#{$eccgui}-reactflow-edge-label-color, currentColor); border-radius: $reactflow-node-border-radius; + padding: 0 $eccgui-size-block-whitespace * 0.25; &.#{$eccgui}-graphviz__edge-label--loose { background-color: transparent; @@ -330,7 +331,6 @@ path.react-flow__edge-path-highlight { display: inline-flex; flex-grow: 0; flex-shrink: 0; - margin-left: 2px; .#{$eccgui}-depiction__image { height: calc(#{0.5 * $reactflow-node-largesize} - 4px); @@ -342,7 +342,7 @@ path.react-flow__edge-path-highlight { .#{$eccgui}-graphviz__edge-label__text { flex-grow: 1; flex-shrink: 1; - margin: 0 $eccgui-size-block-whitespace * 0.25; + margin: 0 0 0 $eccgui-size-block-whitespace * 0.25; overflow: hidden; text-overflow: ellipsis; text-align: center;