Skip to content

Commit

Permalink
Merge pull request #166 from eccenca/release/v23.7.0
Browse files Browse the repository at this point in the history
Release v23.7.0 into main branch
  • Loading branch information
haschek authored Jun 26, 2024
2 parents 874813e + 91463a7 commit 575bece
Show file tree
Hide file tree
Showing 54 changed files with 2,011 additions and 555 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
]
}
],
"@typescript-eslint/ban-ts-comment": ["error", { "ts-ignore": "allow-with-description" }]
"@typescript-eslint/ban-ts-comment": ["error", { "ts-ignore": "allow-with-description" }],
"no-console": "error"
}
}
55 changes: 55 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,61 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

## [Unreleased]

### Added

- `<ReactFlow/>`, `<StickyNoteModal/>`, `<EdgeDefault/>`, `<EdgeLabel/>`, `<HandleContent/>`, `<HandleTools/>`, `<MiniMap/>`
- all react flow components are now be able to process test ids as data attributes, e.g. `data-test-id` and `data-testid`, sometimes as direct property, in other cases as part of properties routed to the wrapper elements
- storybook documentation was enhanced by demonstration the usage of test ids
- `<Markdown />`
- Do syntax highlighting when a class name is set in the form `language-<LANGUAGE_NAME>`.
- `<StickyTarget/>`
- Element wraps the content that need to be displayed sticky.
- `utils`
- `getScrollParent`: method to find the scroll parent of an element
- `<AutoCompleteField />`
- Support loading more results when scrolling to the end of the result list.
- `<TextArea />`
- `intent` property to set the state, formerly used `hasStatePrimary`, `hasStateSuccess`, `hasStateWarning` and `hasStateDanger` properties are now deprecated
- `leftIcon`: set the left aligned icon
- `rightElement`: renders on right side
- `<Depiction />`
- `disabled` property could be used if the element is used inside a disabled interactive element or form control but the state is not adapted automatically to the depiction
- new icons: `navigation-extern`, `toggler-list`, `toggler-table`, `data-boolean`

### Fixed

- `<MultiSuggestField />`
- Updated the interface with the ability to use either `selectedItems` or `prePopulateWithItems` properties, which is more logical.
- Fixed deferred `selectedItems` setting.
- `<StickyNoteModal/>`
- static test id `data-test-id="sticky-note-modal"` will be removed with next major version
- `<BreadcrumbsList />`
- `onItemClick` handler is only executed if breadcrumb has `href` set because this is one callback parameter and the handler would not have any information otherwise
- `<Depiction />`
- position fixed when element is used as icon in `<Button />`
- `<Tooltip />`
- fix font sizes and background colors
- `<NodeContent />`
- node introduction is only processed one time even if a node update still provides a `introductionTime` property

### Changed

- `<BreadcrumbsList />`
- `onItemClick` handler is only executed when the breadcrumb has no own `onClick` handler defined
- `<Card />`
- `elevation` allows now `-1` as value, the card is borderless then
- `<MultiSuggestField />`
- use "Search for item, or enter term to create new one..." as default `placeholder` if `createNewItemFromQuery` is given
- `<SilkActivityControl />`
- interface of `initialStatus` property has been updated with the so far missing `lastUpdateTime` property. If you run in problems because of that you could use `Date.now()` as fix. Or consider to use `<ActivityControlWidget />` directly, what is probably even better.
- `<Depiction />`
- opcaity is reduced automatically when element is used as icon in a disabled `<Button />`

### Deprecated

- `<TextArea />`
- `hasStatePrimary`, `hasStateSuccess`, `hasStateWarning` and `hasStateDanger` properties: use the `intent` property instead.

## [23.6.0] - 2024-04-17

### Added
Expand Down
14 changes: 9 additions & 5 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": "23.6.0",
"version": "23.7.0-rc.5",
"license": "Apache-2.0",
"homepage": "https://github.com/eccenca/gui-elements",
"bugs": "https://github.com/eccenca/gui-elements/issues",
Expand Down Expand Up @@ -65,9 +65,9 @@
"autolint:all": "yarn autolint:scripts && yarn autolint:styles && yarn autolint:prettier"
},
"dependencies": {
"@blueprintjs/colors": "^5.1.0",
"@blueprintjs/core": "^5.9.1",
"@blueprintjs/select": "^5.1.1",
"@blueprintjs/colors": "^5.1.1",
"@blueprintjs/core": "^5.10.3",
"@blueprintjs/select": "^5.1.5",
"@carbon/icons": "^11.19.0",
"@carbon/icons-react": "11.19.0",
"@carbon/styles": "1.32.0",
Expand All @@ -85,6 +85,7 @@
"react-flow-renderer-lts": "npm:react-flow-renderer@^10.3.17",
"react-inlinesvg": "^3.0.3",
"react-markdown": "^8.0.7",
"react-syntax-highlighter": "15.5.0",
"rehype-raw": "^6.1.1",
"remark-definition-list": "^1.2.0",
"remark-gfm": "^3.0.1",
Expand Down Expand Up @@ -117,6 +118,7 @@
"@types/color": "^3.0.6",
"@types/jest": "^29.5.12",
"@types/lodash": "^4.14.202",
"@types/react-syntax-highlighter": "15.5.11",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"babel-jest": "^29.7.0",
Expand Down Expand Up @@ -162,7 +164,9 @@
"**/jackspeak": "2.1.1",
"node-sass-package-importer/**/postcss": "^8.4.31",
"**/word-wrap": "^1.2.4",
"**/webpack-dev-middleware": "^6.1.2"
"**/webpack-dev-middleware": "^6.1.2",
"**/braces": "^3.0.3",
"**/ws": "^8.17.1"
},
"husky": {
"hooks": {
Expand Down
2 changes: 2 additions & 0 deletions src/cmem/ActivityControl/ActivityControlTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export interface IActivityStatus {
statusName: "Waiting" | "Finished" | "Idle" | "Running" | "Canceling";
// A number between 0 and 100
progress: number;
// timestamp for last update
lastUpdateTime: number;
// More information corresponding to the status
message: string;
// If the activity has been cancelled
Expand Down
9 changes: 8 additions & 1 deletion src/cmem/markdown/Markdown.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from "react";
import { Blockquote } from "@blueprintjs/core";
import { ComponentMeta, ComponentStory } from "@storybook/react";

import { Markdown } from "./../../../index";
Expand Down Expand Up @@ -44,11 +45,17 @@ This is a paragraph with a [text link](http://example.com/) and a footnote refer
##### Headline level 5
###### Headline level 6
This is a code block.
This is a code block.
\`\`\`
another code block
{{templateVar}}
\`\`\`
> This is a block quote.
>
> With 2 paragraphs.
> And some code like \`{{showThisNotItsValue}}\`
A line with some <strong>HTML code</strong> inside.
Expand Down
23 changes: 22 additions & 1 deletion src/cmem/markdown/Markdown.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from "react";
import ReactMarkdown from "react-markdown";
import { PluggableList } from "react-markdown/lib/react-markdown";
//@ts-ignore
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { materialLight } from "react-syntax-highlighter/dist/esm/styles/prism";
// @ts-ignore: No declaration file for module (TODO: should be @ts-expect-error but GUI elements is used inside project with `noImplicitAny=false`)
import remarkTypograf from "@mavrin/remark-typograf";
import rehypeRaw from "rehype-raw";
import { remarkDefinitionList } from "remark-definition-list";
Expand Down Expand Up @@ -132,6 +134,25 @@ export const Markdown = ({
return linkTarget as React.HTMLAttributeAnchorTarget;
}
: undefined,
components: {
code(props: any) {
const { children, className, node, ...rest } = props;
const match = /language-(\w+)/.exec(className || "");
return match ? (
<SyntaxHighlighter
{...rest}
PreTag="div"
children={String(children).replace(/\n$/, "")}
language={match[1]}
style={materialLight}
/>
) : (
<code {...rest} className={className}>
{children}
</code>
);
},
},
};
allowedElements && (reactMarkdownProperties.allowedElements = allowedElements);
reHypePlugins &&
Expand Down
14 changes: 10 additions & 4 deletions src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FC, useCallback, useEffect, useState } from "react";
import { Elements, FlowElement } from "react-flow-renderer";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";

import { EdgeTools, NodeTools, ReactFlow } from "./../../../index";
import { ReactFlowProps } from "./ReactFlow";
Expand Down Expand Up @@ -361,7 +361,7 @@ export default {
options: Object.keys(nodeExamples),
},
},
} as ComponentMeta<typeof ReactFlow>;
} as Meta<typeof ReactFlow>;

const ReactFlowExample: FC<ReactFlowProps> = (args) => {
const [reactflowInstance, setReactflowInstance] = useState(null);
Expand Down Expand Up @@ -402,10 +402,13 @@ const ReactFlowExample: FC<ReactFlowProps> = (args) => {
[reactflowInstance]
);

const { configuration, ...otherArgs } = args;

return (
<>
<ReactFlow
configuration={args.configuration}
{...otherArgs}
configuration={configuration}
elements={elements}
style={{ height: "400px" }}
onLoad={onLoad}
Expand All @@ -418,9 +421,12 @@ const ReactFlowExample: FC<ReactFlowProps> = (args) => {
);
};

const Template: ComponentStory<typeof ReactFlow> = (args) => <ReactFlowExample {...args} />;
const Template: StoryFn<typeof ReactFlow> = (args) => <ReactFlowExample {...args} />;

export const Default = Template.bind({});
Default.args = {
configuration: "unspecified",
"data-test-id": "reactflow-test-id",
"data-testid": "reactflow-testid",
};
Default.nodeExamples = nodeExamples;
11 changes: 8 additions & 3 deletions src/cmem/react-flow/StickyNoteModal/StickyNoteModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import getColorConfiguration from "../../../common/utils/getColorConfiguration";
import { CodeEditor } from "../../../extensions";
import { ReactFlowHotkeyContext } from "../extensions/ReactFlowHotkeyContext";

import { Button, FieldItem, Icon, SimpleDialog, Tag, TagList } from "./../../../index";
import { Button, FieldItem, Icon, SimpleDialog, SimpleDialogProps, Tag, TagList } from "./../../../index";

export type StickyNoteModalTranslationKeys = "modalTitle" | "noteLabel" | "colorLabel" | "saveButton" | "cancelButton";

Expand All @@ -28,10 +28,14 @@ export interface StickyNoteModalProps {
* translation utility for language compatibility
*/
translate: (key: StickyNoteModalTranslationKeys) => string;
/**
* Forward other properties to the `SimpleModal` element that is used for this dialog.
*/
simpleDialogProps?: Omit<SimpleDialogProps, "size" | "title" | "hasBorder" | "isOpen" | "onClose" | "actions">;
}

export const StickyNoteModal: React.FC<StickyNoteModalProps> = React.memo(
({ metaData, onClose, onSubmit, translate }) => {
({ metaData, onClose, onSubmit, translate, simpleDialogProps }) => {
const refNote = React.useRef<string>(metaData?.note ?? "");
const [color, setSelectedColor] = React.useState<string>(metaData?.color ?? "");
const noteColors: [string, string][] = Object.entries(getColorConfiguration("stickynotes")).map(
Expand Down Expand Up @@ -79,7 +83,6 @@ export const StickyNoteModal: React.FC<StickyNoteModalProps> = React.memo(

return (
<SimpleDialog
data-test-id={"sticky-note-modal"}
size="small"
title={translate("modalTitle")}
hasBorder
Expand All @@ -101,6 +104,8 @@ export const StickyNoteModal: React.FC<StickyNoteModalProps> = React.memo(
{translate("cancelButton")}
</Button>,
]}
{...simpleDialogProps}
data-test-id={(simpleDialogProps ?? {})["data-test-id"] ?? "sticky-note-modal"} // @deprecated we remove this automatically set testid with the next major release
>
<FieldItem
key="note"
Expand Down
3 changes: 3 additions & 0 deletions src/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { invisibleZeroWidthCharacters } from "./utils/characters";
import decideContrastColorValue from "./utils/colorDecideContrastvalue";
import getColorConfiguration from "./utils/getColorConfiguration";
import { getScrollParent } from "./utils/getScrollParent";
import { getGlobalVar, setGlobalVar } from "./utils/globalVars";
import { openInNewTab } from "./utils/openInNewTab";

Expand All @@ -11,6 +12,8 @@ export const utils = {
invisibleZeroWidthCharacters,
getGlobalVar,
setGlobalVar,
getScrollParent,
};

// @deprecated use `utils`
export const Utilities = utils;
20 changes: 20 additions & 0 deletions src/common/utils/getScrollParent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Find the scroll parent of an element, returns `false` if it cannot be found.
* In case of a `false` return the very probably `document.documentElement` is the parent.
* In this case `window` object should be used for scroll event listeners.
* See `src/components/Sticky/StickyTarget.tsx` for an usage example.
* @param element
* @returns HTMLElement | false
*/
export const getScrollParent = (element: Element): HTMLElement | false => {
let scrollParent = element.parentElement;
while (scrollParent) {
const { overflow } = window.getComputedStyle(scrollParent);
if (overflow.split(" ").every((value) => value === "auto" || value === "scroll")) {
return scrollParent;
}
scrollParent = scrollParent.parentElement;
}

return false;
};
1 change: 0 additions & 1 deletion src/components/Application/application.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// @import 'config';
@import "~@carbon/styles/scss/components/ui-shell/functions";
@import "header";
@import "toolbar";

Expand Down
28 changes: 28 additions & 0 deletions src/components/AutocompleteField/AutoCompleteField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ export interface AutoCompleteFieldProps<T, UPDATE_VALUE> {
* Use the full available width of the parent container.
*/
fill?: boolean;
/** Utility that fetches more options when clicked*/
loadMoreResults?: () => Promise<T[] | undefined>;
}

export type IAutoCompleteFieldProps<T, UPDATE_VALUE> = AutoCompleteFieldProps<T, UPDATE_VALUE>;
Expand Down Expand Up @@ -195,6 +197,7 @@ export function AutoCompleteField<T, UPDATE_VALUE>(props: AutoCompleteFieldProps
requestErrorPrefix,
hasBackDrop,
fill,
loadMoreResults,
...otherProps
} = props;
const [selectedItem, setSelectedItem] = useState<T | undefined>(initialValue);
Expand Down Expand Up @@ -334,6 +337,7 @@ export function AutoCompleteField<T, UPDATE_VALUE>(props: AutoCompleteFieldProps
disabled: modifiers.disabled,
highlightingEnabled: highlightingEnabled,
};

const renderedItem = itemRenderer(item, query, relevantModifiers, handleClick);
if (typeof renderedItem === "string") {
return (
Expand Down Expand Up @@ -442,6 +446,26 @@ export function AutoCompleteField<T, UPDATE_VALUE>(props: AutoCompleteFieldProps
createNewItemPosition,
}
: {};

const handleMenuScroll = React.useCallback(
async (event: any) => {
const menu = event.target;
const { scrollTop, scrollHeight, clientHeight } = menu;
// Check if scrolled to the bottom of the list
if (Math.round(scrollTop + clientHeight) >= scrollHeight && loadMoreResults) {
const results = await loadMoreResults();
if (results) {
setFiltered((prev) => [...prev, ...results]);
setTimeout(() => {
menu.scrollTop = scrollTop; //safari adaptation
menu.scrollTo({ left: 0, top: scrollTop, behavior: "auto" });
});
}
}
},
[loadMoreResults]
);

return (
<BlueprintSuggest<T>
className={`${eccgui}-autocompletefield__input` + (className ? ` ${className}` : "")}
Expand All @@ -455,7 +479,11 @@ export function AutoCompleteField<T, UPDATE_VALUE>(props: AutoCompleteFieldProps
noResults={<MenuItem disabled={true} text={noResultText} />}
onItemSelect={onSelectionChange}
onQueryChange={(q) => setQuery(q)}
resetOnQuery={false}
closeOnSelect={true}
menuProps={{
onScroll: handleMenuScroll,
}}
query={query}
// This leads to odd compile errors without "as any"
popoverProps={updatedContextOverlayProps as any}
Expand Down
2 changes: 1 addition & 1 deletion src/components/AutocompleteField/autocompletefield.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.#{$eccgui}-autocompletefield__options {
.#{$ns}-popover2-content {
.#{$ns}-popover-content {
.#{$ns}-menu {
max-height: 45vh;
overflow: auto;
Expand Down
Loading

0 comments on commit 575bece

Please sign in to comment.