Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
67df4a3
re-configure breakpoints for pagination container queries
haschek Apr 1, 2026
a6610a7
Update changelog section to 25.1.0
haschek Apr 13, 2026
0417f33
Merge pull request #387 from eccenca/maintain/mergeReleaseTag-v25.1.0
haschek Apr 13, 2026
2a6baaf
Merge branch 'develop' into bugfix/paginationBreakpoints-CMEM-7458
haschek Apr 13, 2026
ad4607f
update chagelog
haschek Apr 13, 2026
716e2e1
Add pagination story or debugging
andreas-schultz Apr 17, 2026
db6c08e
force to hide elements regardless of container queries, add storybook…
haschek Apr 20, 2026
6037854
fix container queries and remove unnecessary margin
haschek Apr 20, 2026
47cdaef
Merge pull request #385 from eccenca/bugfix/paginationBreakpoints-CME…
andreas-schultz Apr 20, 2026
6b87ea5
Add intent property to CodeAutocompleteField
andreas-schultz Apr 27, 2026
945fe96
Update In-Memory dataset icon
robertisele Apr 28, 2026
422a935
Merge branch 'develop' into feature/updateInMemoryDatasetIcon-CMEM-7363
haschek Apr 29, 2026
c369528
update changelog
haschek Apr 29, 2026
11d26cf
Merge pull request #389 from eccenca/feature/updateInMemoryDatasetIco…
haschek Apr 29, 2026
47e6caa
fix intent layout
haschek Apr 29, 2026
fad4a1c
Merge remote-tracking branch 'origin/develop' into feature/improvedDe…
haschek Apr 29, 2026
cb75fef
Merge pull request #388 from eccenca/feature/improvedDependentParamet…
haschek Apr 29, 2026
8575433
Prepare release v25.2.0
haschek Apr 29, 2026
166e14a
update storybook packages and set resolutions for related subpackes t…
haschek Apr 30, 2026
f4bfd84
set resolution to fix high security issues of scss sublibraries
haschek Apr 30, 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
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

### Added

- `<CodeAutocompleteField />`
- Add `intent` property.
- new icons:
- `state-confirmed-all`

### Fixed

- `<Pagination />`
- improve breakpoints to display widgets for page size and page number inside smaller containers
- male the breakpoints configurable via SCSS

## [25.1.0] - 2026-04-13

### Added

- `<ActivityControlWidget />`
- Add parameter `active` to activity control action to set the `active` state of its button.
- action now can have a `active` and `notification` property
Expand Down
19 changes: 11 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@eccenca/gui-elements",
"description": "GUI elements based on other libraries, usable in React application, written in Typescript.",
"version": "25.1.0",
"version": "25.2.0",
"license": "Apache-2.0",
"homepage": "https://github.com/eccenca/gui-elements",
"bugs": "https://github.com/eccenca/gui-elements/issues",
Expand Down Expand Up @@ -122,15 +122,15 @@
"@eslint/eslintrc": "^3.3.1",
"@eslint/js": "^9.39.1",
"@storybook/addon-actions": "^8.6.14",
"@storybook/addon-essentials": "^8.6.14",
"@storybook/addon-essentials": "^8.6.18",
"@storybook/addon-jest": "^8.6.14",
"@storybook/addon-links": "^8.6.14",
"@storybook/addon-webpack5-compiler-babel": "^3.0.6",
"@storybook/cli": "^8.6.14",
"@storybook/cli": "^8.6.18",
"@storybook/preset-scss": "^1.0.3",
"@storybook/react": "^8.6.14",
"@storybook/react-webpack5": "^8.6.14",
"@storybook/test": "^8.6.14",
"@storybook/react": "^8.6.18",
"@storybook/react-webpack5": "^8.6.18",
"@storybook/test": "^8.6.18",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^12.1.5",
"@types/color": "^3.0.6",
Expand Down Expand Up @@ -164,7 +164,7 @@
"rimraf": "^6.1.3",
"sass": "1.62.1",
"sass-loader": "10.3.1",
"storybook": "^8.6.14",
"storybook": "^8.6.18",
"stylelint": "^17.6.0",
"stylelint-config-recess-order": "^7.7.0",
"stylelint-config-standard-scss": "^17.0.0",
Expand All @@ -187,7 +187,10 @@
"hast-util-from-parse5": "8.0.0",
"**/picomatch": "^2.3.2",
"**/minimatch": "^3.1.4",
"**/lodash": "^4.18.0"
"**/lodash": "^4.18.0",
"**/serialize-javascript": "^7.0.3",
"**/tar": "^7.5.11",
"**/immutable": "^4.3.8"
},
"husky": {
"hooks": {
Expand Down
21 changes: 14 additions & 7 deletions src/components/AutoSuggestion/AutoSuggestion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Classes as BlueprintClassNames } from "@blueprintjs/core";
import { EditorView, Rect } from "@codemirror/view";
import { debounce } from "lodash";

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

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

// Meta data regarding a request
Expand Down Expand Up @@ -192,6 +195,7 @@ export const CodeAutocompleteField = ({
height,
readOnly,
outerDivAttributes,
intent,
}: CodeAutocompleteFieldProps) => {
const value = React.useRef<string>(initialValue);
const cursorPosition = React.useRef(0);
Expand Down Expand Up @@ -630,6 +634,12 @@ export const CodeAutocompleteField = ({
[]
);

const hasError = !!value.current && !pathIsValid && !pathValidationPending;
const effectiveIntent = hasError ? "danger" : intent;
const blueprintIntent =
effectiveIntent && !["info", "accent", "neutral"].includes(effectiveIntent) ? effectiveIntent : undefined;
const inputIntentClass = effectiveIntent ? ` ${eccgui}-intent--${effectiveIntent}` : "";

const codeEditor = React.useMemo(() => {
return (
<ExtendedCodeEditor
Expand Down Expand Up @@ -661,9 +671,8 @@ export const CodeAutocompleteField = ({
multiline,
handleInputMouseDown,
readOnly,
effectiveIntent,
]);

const hasError = !!value.current && !pathIsValid && !pathValidationPending;
const autoSuggestionInput = (
<div
id={id}
Expand All @@ -674,7 +683,7 @@ export const CodeAutocompleteField = ({
<div
className={` ${eccgui}-autosuggestion__inputfield ${BlueprintClassNames.INPUT_GROUP} ${
BlueprintClassNames.FILL
} ${hasError ? BlueprintClassNames.INTENT_DANGER : ""}`}
} ${blueprintIntent ? BlueprintClassNames.intentClass(blueprintIntent as any) : ""}${inputIntentClass}`}
>
<ContextOverlay
minimal
Expand Down Expand Up @@ -734,13 +743,11 @@ export const CodeAutocompleteField = ({
<>
{label}
&nbsp;
{(pathValidationPending || suggestionsPending) && (
<Spinner size="tiny" position="inline" />
)}
{(pathValidationPending || suggestionsPending) && <Spinner size="tiny" position="inline" />}
</>
),
}}
intent={hasError ? "danger" : undefined}
intent={effectiveIntent}
messageText={hasError ? validationErrorText : undefined}
>
{withRightElement}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ import { OverlaysProvider } from "@blueprintjs/core";
import { Meta, StoryFn } from "@storybook/react";
import { fn } from "@storybook/test";

import { helpersArgTypes } from "../../../.storybook/helpers";
import { CodeAutocompleteField, CodeAutocompleteFieldProps } from "../../../index";
import { CodeAutocompleteFieldPartialAutoCompleteResult } from "../AutoSuggestion/AutoSuggestion";

export default {
title: "Forms/CodeAutocompleteField",
component: CodeAutocompleteField,
argTypes: {},
argTypes: {
intent: {
...helpersArgTypes.exampleIntent,
options: ["UNDEFINED", "primary", "accent", "success", "warning", "danger"],
},
},
args: {
onInputChecked: fn(),
},
Expand Down
1 change: 1 addition & 0 deletions src/components/Icon/canonicalIconNames.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const canonicalIcons = {
"artefact-task-sendemail": icons.Email,
"artefact-dataset-csv": icons.Csv,
"artefact-dataset-eccencadataplatform": icons.DataVis_1,
"artefact-dataset-inmemory": icons.DataVis_1,
"artefact-dataset-excel": icons.Xls,
"artefact-dataset-file": icons.DataVis_1,
"artefact-dataset": icons.Data_2,
Expand Down
32 changes: 32 additions & 0 deletions src/components/Pagination/Stories/Pagination.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ export default {

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

const ContainerQueriesExample = (args) => (
<>
<Pagination {...args} style={{ maxWidth: "100%" }} />
<Pagination {...args} style={{ maxWidth: "32rem" }} />
<Pagination {...args} style={{ maxWidth: "26rem" }} />
</>
);

export const Default: StoryFn<typeof Pagination> = PaginationExample.bind({});
Default.args = {
pageSizes: [10, 20, 50, 100],
Expand All @@ -28,3 +36,27 @@ ExtendedPagesizeSelection.args = {
{ text: "Large page with 100 items", value: "100" },
],
};

/**
* This story demonstrates a minimal pagination and is a check that elements are always hidden.
*/
export const MinimalPagination: StoryFn<typeof Pagination> = PaginationExample.bind({});
MinimalPagination.args = {
...Default.args,
hidePageSizeConfiguration: true,
hidePageSelect: true,
hideInfoText: true,
hideNavigationArrows: false,
hideBorders: false,
};

/**
* Demonstrates the breakpoints of the container queries.
* If the container gets too small, some elements are removed automatically.
* First, page selector disappears, then the page size selector.
* Info text and navigation arrow are never hidden automatically.
*/
export const ContainerQueries: StoryFn<typeof Pagination> = ContainerQueriesExample.bind({});
ContainerQueries.args = {
...Default.args,
};
58 changes: 54 additions & 4 deletions src/components/Pagination/pagination.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ $eccgui-size-typo-pagination: $eccgui-size-typo-caption !default;
$eccgui-size-pagination-height-medium: $pt-button-height !default;
$eccgui-size-pagination-height-small: $pt-button-height-small !default;
$eccgui-size-pagination-height-large: $pt-button-height-large !default;
$eccgui-size-pagination-breakpoint-wide: 32rem !default;
$eccgui-size-pagination-breakpoint-small: 26rem !default;

.#{$prefix}--pagination {
min-block-size: $eccgui-size-pagination-height-medium;
Expand Down Expand Up @@ -38,7 +40,7 @@ span.#{$prefix}--pagination__text {
padding-left: 0;

& > *:not(:last-child) {
display: none;
display: none !important;
}
}
}
Expand All @@ -56,7 +58,7 @@ span.#{$prefix}--pagination__text {

.#{$eccgui}-pagination--hideinfotext {
.#{$prefix}--pagination__left > .#{$prefix}--pagination__text:last-child {
display: none;
display: none !important;
}

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

.#{$eccgui}-pagination--hidepageselect {
.#{$prefix}--pagination__right > *:not(.#{$prefix}--pagination__control-buttons) {
display: none;
display: none !important;
}
}

.#{$eccgui}-pagination--hidenavigation {
.#{$prefix}--pagination__right > .#{$prefix}--pagination__control-buttons {
display: none;
display: none !important;
}
}

Expand Down Expand Up @@ -137,3 +139,51 @@ span.#{$prefix}--pagination__text {
line-height: $eccgui-size-pagination-height-large;
}
}

// fix breakpoints for container queries
// Carbon does not provide the option to configure that breakpoint
@container pagination (min-width: #{$eccgui-size-pagination-breakpoint-small}) {
.#{$prefix}--pagination.#{$eccgui}-pagination {
.#{$prefix}--pagination__control-buttons {
display: flex;
}
.#{$prefix}--pagination__left > * {
display: inherit;
}
}
}

@container pagination (min-width: #{$eccgui-size-pagination-breakpoint-wide}) {
.#{$prefix}--pagination.#{$eccgui}-pagination {
.#{$prefix}--pagination__right > * {
display: inherit;
}
}
}

@container pagination (max-width: #{$eccgui-size-pagination-breakpoint-small}) {
.#{$prefix}--pagination.#{$eccgui}-pagination {
.#{$prefix}--pagination__left > * {
display: none;
}
.#{$prefix}--pagination__items-count {
margin-left: 0;
}
}
}

@container pagination (max-width: #{$eccgui-size-pagination-breakpoint-wide}) {
.#{$prefix}--pagination.#{$eccgui}-pagination {
.#{$prefix}--pagination__right > * {
display: none;
}

.#{$prefix}--pagination__items-count {
display: initial;
}

.#{$prefix}--pagination__control-buttons {
display: flex;
}
}
}
24 changes: 20 additions & 4 deletions src/extensions/codemirror/CodeMirror.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,20 @@ export const CodeEditor = ({
];
}

const syncIntentClass = React.useCallback((editorView: EditorView | undefined, nextIntent?: CodeEditorProps["intent"]) => {
if (!editorView?.dom) {
return;
}

Array.from(editorView.dom.classList)
.filter((className) => className.startsWith(`${eccgui}-intent--`))
.forEach((className) => editorView.dom.classList.remove(className));

if (nextIntent) {
editorView.dom.classList.add(`${eccgui}-intent--${nextIntent}`);
}
}, []);

React.useEffect(() => {
const domEventHandlers = {
...addHandlersFor(!!onScroll, "scroll", onScroll),
Expand Down Expand Up @@ -360,7 +374,7 @@ export const CodeEditor = ({
onSelection(v.state.selection.ranges.filter((r) => !r.empty).map(({ from, to }) => ({ from, to })));

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

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

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

if (autoFocus) {
view.focus();
Expand Down Expand Up @@ -472,6 +484,10 @@ export const CodeEditor = ({
}
}, [disabled])

React.useEffect(() => {
syncIntentClass(view, intent);
}, [intent, view, syncIntentClass]);

React.useEffect(() => {
setEditorAppearance({
...editorAppearance,
Expand Down
Loading
Loading