Skip to content

Commit 3ece160

Browse files
authored
Merge pull request #390 from eccenca/release/v25.2.0
Release v25.2.0 into main branch
2 parents 95a486e + f4bfd84 commit 3ece160

9 files changed

Lines changed: 358 additions & 250 deletions

File tree

CHANGELOG.md

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

99
### Added
1010

11+
- `<CodeAutocompleteField />`
12+
- Add `intent` property.
13+
- new icons:
14+
- `state-confirmed-all`
15+
16+
### Fixed
17+
18+
- `<Pagination />`
19+
- improve breakpoints to display widgets for page size and page number inside smaller containers
20+
- male the breakpoints configurable via SCSS
21+
22+
## [25.1.0] - 2026-04-13
23+
24+
### Added
25+
1126
- `<ActivityControlWidget />`
1227
- Add parameter `active` to activity control action to set the `active` state of its button.
1328
- action now can have a `active` and `notification` property

package.json

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@eccenca/gui-elements",
33
"description": "GUI elements based on other libraries, usable in React application, written in Typescript.",
4-
"version": "25.1.0",
4+
"version": "25.2.0",
55
"license": "Apache-2.0",
66
"homepage": "https://github.com/eccenca/gui-elements",
77
"bugs": "https://github.com/eccenca/gui-elements/issues",
@@ -122,15 +122,15 @@
122122
"@eslint/eslintrc": "^3.3.1",
123123
"@eslint/js": "^9.39.1",
124124
"@storybook/addon-actions": "^8.6.14",
125-
"@storybook/addon-essentials": "^8.6.14",
125+
"@storybook/addon-essentials": "^8.6.18",
126126
"@storybook/addon-jest": "^8.6.14",
127127
"@storybook/addon-links": "^8.6.14",
128128
"@storybook/addon-webpack5-compiler-babel": "^3.0.6",
129-
"@storybook/cli": "^8.6.14",
129+
"@storybook/cli": "^8.6.18",
130130
"@storybook/preset-scss": "^1.0.3",
131-
"@storybook/react": "^8.6.14",
132-
"@storybook/react-webpack5": "^8.6.14",
133-
"@storybook/test": "^8.6.14",
131+
"@storybook/react": "^8.6.18",
132+
"@storybook/react-webpack5": "^8.6.18",
133+
"@storybook/test": "^8.6.18",
134134
"@testing-library/jest-dom": "^6.9.1",
135135
"@testing-library/react": "^12.1.5",
136136
"@types/color": "^3.0.6",
@@ -164,7 +164,7 @@
164164
"rimraf": "^6.1.3",
165165
"sass": "1.62.1",
166166
"sass-loader": "10.3.1",
167-
"storybook": "^8.6.14",
167+
"storybook": "^8.6.18",
168168
"stylelint": "^17.6.0",
169169
"stylelint-config-recess-order": "^7.7.0",
170170
"stylelint-config-standard-scss": "^17.0.0",
@@ -187,7 +187,10 @@
187187
"hast-util-from-parse5": "8.0.0",
188188
"**/picomatch": "^2.3.2",
189189
"**/minimatch": "^3.1.4",
190-
"**/lodash": "^4.18.0"
190+
"**/lodash": "^4.18.0",
191+
"**/serialize-javascript": "^7.0.3",
192+
"**/tar": "^7.5.11",
193+
"**/immutable": "^4.3.8"
191194
},
192195
"husky": {
193196
"hooks": {

src/components/AutoSuggestion/AutoSuggestion.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Classes as BlueprintClassNames } from "@blueprintjs/core";
44
import { EditorView, Rect } from "@codemirror/view";
55
import { debounce } from "lodash";
66

7+
import { IntentTypes } from "../../common/Intent";
78
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
89
import { SupportedCodeEditorModes } from "../../extensions/codemirror/hooks/useCodemirrorModeExtension.hooks";
910

@@ -154,6 +155,8 @@ export interface CodeAutocompleteFieldProps {
154155
readOnly?: boolean;
155156
/** Properties that should be added to the outer div container. */
156157
outerDivAttributes?: Omit<React.HTMLAttributes<HTMLDivElement>, "id" | "data-test-id">;
158+
/** Intent state of the input field. Validation errors override this. */
159+
intent?: IntentTypes;
157160
}
158161

159162
// Meta data regarding a request
@@ -192,6 +195,7 @@ export const CodeAutocompleteField = ({
192195
height,
193196
readOnly,
194197
outerDivAttributes,
198+
intent,
195199
}: CodeAutocompleteFieldProps) => {
196200
const value = React.useRef<string>(initialValue);
197201
const cursorPosition = React.useRef(0);
@@ -630,6 +634,12 @@ export const CodeAutocompleteField = ({
630634
[]
631635
);
632636

637+
const hasError = !!value.current && !pathIsValid && !pathValidationPending;
638+
const effectiveIntent = hasError ? "danger" : intent;
639+
const blueprintIntent =
640+
effectiveIntent && !["info", "accent", "neutral"].includes(effectiveIntent) ? effectiveIntent : undefined;
641+
const inputIntentClass = effectiveIntent ? ` ${eccgui}-intent--${effectiveIntent}` : "";
642+
633643
const codeEditor = React.useMemo(() => {
634644
return (
635645
<ExtendedCodeEditor
@@ -661,9 +671,8 @@ export const CodeAutocompleteField = ({
661671
multiline,
662672
handleInputMouseDown,
663673
readOnly,
674+
effectiveIntent,
664675
]);
665-
666-
const hasError = !!value.current && !pathIsValid && !pathValidationPending;
667676
const autoSuggestionInput = (
668677
<div
669678
id={id}
@@ -674,7 +683,7 @@ export const CodeAutocompleteField = ({
674683
<div
675684
className={` ${eccgui}-autosuggestion__inputfield ${BlueprintClassNames.INPUT_GROUP} ${
676685
BlueprintClassNames.FILL
677-
} ${hasError ? BlueprintClassNames.INTENT_DANGER : ""}`}
686+
} ${blueprintIntent ? BlueprintClassNames.intentClass(blueprintIntent as any) : ""}${inputIntentClass}`}
678687
>
679688
<ContextOverlay
680689
minimal
@@ -734,13 +743,11 @@ export const CodeAutocompleteField = ({
734743
<>
735744
{label}
736745
&nbsp;
737-
{(pathValidationPending || suggestionsPending) && (
738-
<Spinner size="tiny" position="inline" />
739-
)}
746+
{(pathValidationPending || suggestionsPending) && <Spinner size="tiny" position="inline" />}
740747
</>
741748
),
742749
}}
743-
intent={hasError ? "danger" : undefined}
750+
intent={effectiveIntent}
744751
messageText={hasError ? validationErrorText : undefined}
745752
>
746753
{withRightElement}

src/components/CodeAutocompleteField/CodeAutocompleteField.stories.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@ import { OverlaysProvider } from "@blueprintjs/core";
33
import { Meta, StoryFn } from "@storybook/react";
44
import { fn } from "@storybook/test";
55

6+
import { helpersArgTypes } from "../../../.storybook/helpers";
67
import { CodeAutocompleteField, CodeAutocompleteFieldProps } from "../../../index";
78
import { CodeAutocompleteFieldPartialAutoCompleteResult } from "../AutoSuggestion/AutoSuggestion";
89

910
export default {
1011
title: "Forms/CodeAutocompleteField",
1112
component: CodeAutocompleteField,
12-
argTypes: {},
13+
argTypes: {
14+
intent: {
15+
...helpersArgTypes.exampleIntent,
16+
options: ["UNDEFINED", "primary", "accent", "success", "warning", "danger"],
17+
},
18+
},
1319
args: {
1420
onInputChecked: fn(),
1521
},

src/components/Icon/canonicalIconNames.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const canonicalIcons = {
4040
"artefact-task-sendemail": icons.Email,
4141
"artefact-dataset-csv": icons.Csv,
4242
"artefact-dataset-eccencadataplatform": icons.DataVis_1,
43+
"artefact-dataset-inmemory": icons.DataVis_1,
4344
"artefact-dataset-excel": icons.Xls,
4445
"artefact-dataset-file": icons.DataVis_1,
4546
"artefact-dataset": icons.Data_2,

src/components/Pagination/Stories/Pagination.stories.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ export default {
1010

1111
const PaginationExample = (args) => <Pagination {...args} />;
1212

13+
const ContainerQueriesExample = (args) => (
14+
<>
15+
<Pagination {...args} style={{ maxWidth: "100%" }} />
16+
<Pagination {...args} style={{ maxWidth: "32rem" }} />
17+
<Pagination {...args} style={{ maxWidth: "26rem" }} />
18+
</>
19+
);
20+
1321
export const Default: StoryFn<typeof Pagination> = PaginationExample.bind({});
1422
Default.args = {
1523
pageSizes: [10, 20, 50, 100],
@@ -28,3 +36,27 @@ ExtendedPagesizeSelection.args = {
2836
{ text: "Large page with 100 items", value: "100" },
2937
],
3038
};
39+
40+
/**
41+
* This story demonstrates a minimal pagination and is a check that elements are always hidden.
42+
*/
43+
export const MinimalPagination: StoryFn<typeof Pagination> = PaginationExample.bind({});
44+
MinimalPagination.args = {
45+
...Default.args,
46+
hidePageSizeConfiguration: true,
47+
hidePageSelect: true,
48+
hideInfoText: true,
49+
hideNavigationArrows: false,
50+
hideBorders: false,
51+
};
52+
53+
/**
54+
* Demonstrates the breakpoints of the container queries.
55+
* If the container gets too small, some elements are removed automatically.
56+
* First, page selector disappears, then the page size selector.
57+
* Info text and navigation arrow are never hidden automatically.
58+
*/
59+
export const ContainerQueries: StoryFn<typeof Pagination> = ContainerQueriesExample.bind({});
60+
ContainerQueries.args = {
61+
...Default.args,
62+
};

src/components/Pagination/pagination.scss

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ $eccgui-size-typo-pagination: $eccgui-size-typo-caption !default;
77
$eccgui-size-pagination-height-medium: $pt-button-height !default;
88
$eccgui-size-pagination-height-small: $pt-button-height-small !default;
99
$eccgui-size-pagination-height-large: $pt-button-height-large !default;
10+
$eccgui-size-pagination-breakpoint-wide: 32rem !default;
11+
$eccgui-size-pagination-breakpoint-small: 26rem !default;
1012

1113
.#{$prefix}--pagination {
1214
min-block-size: $eccgui-size-pagination-height-medium;
@@ -38,7 +40,7 @@ span.#{$prefix}--pagination__text {
3840
padding-left: 0;
3941

4042
& > *:not(:last-child) {
41-
display: none;
43+
display: none !important;
4244
}
4345
}
4446
}
@@ -56,7 +58,7 @@ span.#{$prefix}--pagination__text {
5658

5759
.#{$eccgui}-pagination--hideinfotext {
5860
.#{$prefix}--pagination__left > .#{$prefix}--pagination__text:last-child {
59-
display: none;
61+
display: none !important;
6062
}
6163

6264
& .#{$prefix}--select__item-count .#{$prefix}--select-input {
@@ -66,13 +68,13 @@ span.#{$prefix}--pagination__text {
6668

6769
.#{$eccgui}-pagination--hidepageselect {
6870
.#{$prefix}--pagination__right > *:not(.#{$prefix}--pagination__control-buttons) {
69-
display: none;
71+
display: none !important;
7072
}
7173
}
7274

7375
.#{$eccgui}-pagination--hidenavigation {
7476
.#{$prefix}--pagination__right > .#{$prefix}--pagination__control-buttons {
75-
display: none;
77+
display: none !important;
7678
}
7779
}
7880

@@ -137,3 +139,51 @@ span.#{$prefix}--pagination__text {
137139
line-height: $eccgui-size-pagination-height-large;
138140
}
139141
}
142+
143+
// fix breakpoints for container queries
144+
// Carbon does not provide the option to configure that breakpoint
145+
@container pagination (min-width: #{$eccgui-size-pagination-breakpoint-small}) {
146+
.#{$prefix}--pagination.#{$eccgui}-pagination {
147+
.#{$prefix}--pagination__control-buttons {
148+
display: flex;
149+
}
150+
.#{$prefix}--pagination__left > * {
151+
display: inherit;
152+
}
153+
}
154+
}
155+
156+
@container pagination (min-width: #{$eccgui-size-pagination-breakpoint-wide}) {
157+
.#{$prefix}--pagination.#{$eccgui}-pagination {
158+
.#{$prefix}--pagination__right > * {
159+
display: inherit;
160+
}
161+
}
162+
}
163+
164+
@container pagination (max-width: #{$eccgui-size-pagination-breakpoint-small}) {
165+
.#{$prefix}--pagination.#{$eccgui}-pagination {
166+
.#{$prefix}--pagination__left > * {
167+
display: none;
168+
}
169+
.#{$prefix}--pagination__items-count {
170+
margin-left: 0;
171+
}
172+
}
173+
}
174+
175+
@container pagination (max-width: #{$eccgui-size-pagination-breakpoint-wide}) {
176+
.#{$prefix}--pagination.#{$eccgui}-pagination {
177+
.#{$prefix}--pagination__right > * {
178+
display: none;
179+
}
180+
181+
.#{$prefix}--pagination__items-count {
182+
display: initial;
183+
}
184+
185+
.#{$prefix}--pagination__control-buttons {
186+
display: flex;
187+
}
188+
}
189+
}

src/extensions/codemirror/CodeMirror.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,20 @@ export const CodeEditor = ({
326326
];
327327
}
328328

329+
const syncIntentClass = React.useCallback((editorView: EditorView | undefined, nextIntent?: CodeEditorProps["intent"]) => {
330+
if (!editorView?.dom) {
331+
return;
332+
}
333+
334+
Array.from(editorView.dom.classList)
335+
.filter((className) => className.startsWith(`${eccgui}-intent--`))
336+
.forEach((className) => editorView.dom.classList.remove(className));
337+
338+
if (nextIntent) {
339+
editorView.dom.classList.add(`${eccgui}-intent--${nextIntent}`);
340+
}
341+
}, []);
342+
329343
React.useEffect(() => {
330344
const domEventHandlers = {
331345
...addHandlersFor(!!onScroll, "scroll", onScroll),
@@ -360,7 +374,7 @@ export const CodeEditor = ({
360374
onSelection(v.state.selection.ranges.filter((r) => !r.empty).map(({ from, to }) => ({ from, to })));
361375

362376
if (onFocusChange && currentIntent.current && !v.view.dom.classList?.contains(`${eccgui}-intent--${currentIntent.current}`)) {
363-
v.view.dom.classList.add(`${eccgui}-intent--${currentIntent.current}`);
377+
syncIntentClass(v.view, currentIntent.current);
364378
}
365379

366380
if (onCursorChange) {
@@ -410,9 +424,7 @@ export const CodeEditor = ({
410424
view.dom.classList.add(`${eccgui}-disabled`);
411425
}
412426

413-
if (currentIntent.current) {
414-
view.dom.className += ` ${eccgui}-intent--${currentIntent.current}`;
415-
}
427+
syncIntentClass(view, currentIntent.current);
416428

417429
if (autoFocus) {
418430
view.focus();
@@ -472,6 +484,10 @@ export const CodeEditor = ({
472484
}
473485
}, [disabled])
474486

487+
React.useEffect(() => {
488+
syncIntentClass(view, intent);
489+
}, [intent, view, syncIntentClass]);
490+
475491
React.useEffect(() => {
476492
setEditorAppearance({
477493
...editorAppearance,

0 commit comments

Comments
 (0)