diff --git a/.github/workflows/deployment-storybook.yml b/.github/workflows/deployment-storybook.yml
index c94a35109..9c5c2105f 100644
--- a/.github/workflows/deployment-storybook.yml
+++ b/.github/workflows/deployment-storybook.yml
@@ -24,6 +24,13 @@ jobs:
- uses: actions/checkout@main
with:
fetch-depth: 0
+ - name: Workflow git state
+ run: |
+ echo github.ref: ${{ github.ref }}
+ echo github.event_name: ${{ github.event_name }}
+ echo github.actor: ${{ github.actor }}
+ git status
+ git log --oneline -1
- uses: actions/setup-node@main
with:
node-version: "18"
@@ -32,7 +39,7 @@ jobs:
- name: Create jest results
run: yarn test:generate-output
- name: Publish to Chromatic
- uses: chromaui/action@v11
+ uses: chromaui/action@main
with:
token: ${{ secrets.GITHUB_TOKEN }}
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
diff --git a/.storybook/main.js b/.storybook/main.js
index 48794d304..fb5986c91 100644
--- a/.storybook/main.js
+++ b/.storybook/main.js
@@ -64,7 +64,12 @@ module.exports = {
},
webpackFinal: async (config, { configType }) => {
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
-
+ if (configType === "PRODUCTION") {
+ // remove source maps from production storybook
+ // this may lead to errors when it is created via github workers
+ // reason is currently not known
+ config.devtool = false;
+ }
config.module.rules = [
{
test: /\.(png|jpg|gif|svg)(\\?.*)?$/,
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1a3bc4d0d..3bbaef6d6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
## [Unreleased]
+## [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.
+
+### 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
+- in case you set your own colors before importing GUI elements you need to update your configuration to the new color palette structure, see `README.md`
+- change `intent="primary"` to `intent="accent"` for ` `, ` ` and ` `, if supported you may check if it is better to use `affirmative={true}` or `elevated={true}` instead of `intent`
+
### Added
- ` `
@@ -20,6 +30,115 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- reduces HTML to simple text and can display it as one ellipsed line
- ` `
- prove useage of `usePlaceholder` by jest test coverage
+- ` `
+ - it's basically ` ` without any special configs
+- ` `
+ - only supported for v12, in v9 as straight edge is used
+ - use `curvature` property in the edge `data` object to define the bezier layout (0..1, default: 0.25)
+- ` `
+ - the `data` object provides `markerAppearance` to set and remove the edge arrows
+- ` `
+ - introduced the new `arrowDirection` property, including support for bidirectional edges - supported only for ` `
+- ` `
+ - component for React Flow v12, displaying new connection lines
+- ` `
+ - component to display a visual tour multi-step tour of the current view
+- ` `
+ - `accent` value for `intent` was added to align property with other components
+- ` `
+ - `accent` value for `intent` was added to align property with other components
+ - `elevated` property can be used to highlight the spinner, currently the `intent="accent"` display is used
+- ` `:
+ - Add `ModalContext` to track open/close state of all used application modals.
+ - Add `modalId` property to give a modal a unique ID for tracking purposes.
+ - `preventReactFlowEvents`: adds 'nopan', 'nowheel' and 'nodrag' classes to overlay classes in order to prevent react-flow to react to drag and pan actions in modals.
+ - new `utils` methods
+ - `colorCalculateDistance()`: calculates the difference between 2 colors using the simple CIE76 formula
+ - `textToColorHash()`: calculates a color from a text string
+ - `reduceToText`: shrinks HTML content and React elements to plain text, used for ` `
+ - `decodeHtmlEntities`: decode a string of HTML text, map HTML entities back to UTF-8 chars
+- SCSS color functions
+ - `eccgui-color-var`: returns a var of a custom property used for palette color
+ - `eccgui-color-mix`: mix 2 colors in `srgb`, works with all types of color values and CSS custom properties
+ - `eccgui-color-rgba`: like `rgba()` but it works also for CSS custom properties
+- Color palette: includes 4 sections with 20+ color tints in 5 weights each
+ - indentity, semantic, layout, extra
+ - managed via CSS custom properties
+ - see `README.md` for more information about usage
+- New icons
+ - `artefact-task-sqlupdatequeryoperator`
+ - `artefact-task-customsqlexecution`
+ - `item-legend`
+ - `operation-tour`
+ - `toggler-carettop`
+ - `toggler-caretleft`
+ - `toggler-micon`
+ - `toggler-micoff`
+ - `toggler-radio`
+ - `toggler-radio-checked`
+ - `state-flagged`
+ - `state-progress`
+ - `state-progress-error`
+ - `state-progress-warning`
+ - more icons for build tasks
+
+### Removed
+
+- support for React Flow v10 was completely removed
+- removed direct replacements for legacy components (imported via `@eccenca/gui-elements/src/legacy-replacements` or `LegacyReplacements`)
+ - ` `, ` `, ` `, ` `, ` `, ` `, ` `, ` `
+- ` `, ` `, `
`, ` `
+ - removed support for old state properties `hasStatePrimary`, `hasStateSuccess`, `hasStateWarning` and `hasStateDanger`
+- ` `
+ - removed support for old state properties `neutral`, `success`, `warning` and `danger`
+- ` `
+ - removed `description` and `iconTitle` properties
+- ` `
+ - `densityHigh` property was removed
+- ` `
+ - static fallback for test id `codemirror-wrapper` was removed, add `data-test-id` (or your test id data attribute) always directly to `CodeEditor`.
+- ` `
+ - removed `inversePath` property, can be replaced with `arrowDirection: "inversed"` property
+- ` `
+ - `description` property was removed because it was defined but not implemented for a very long time, but we plan to add that type of caption later
+- `nodeTypes` and `edgeTypes` exports were removed
+ - use ` ` with `configuration`, or define it yourself
+- SCSS variables `$eccgui-color-application-text` and `$eccgui-color-application-background` were removed
+ - use `$eccgui-color-workspace-text` and `$eccgui-color-workspace-background`
+- Removed `remark-typograf` plugin from ` ` rendering to maintain display expectation
+
+### Fixed
+
+- ` `:
+ - In multiline mode, validation errors might be highlighted incorrectly (relative line offset added).
+
+### Changed
+
+- ` ` and ` `
+ - support now v9 and v12 of react flow
+- ` `
+ - use ` ` by default for new connection lines, you can overwrite it by setting `connectionLineComponent` to `undefined`
+- ` `
+ - `color` property does not accept `intent` values anymore
+- ` `
+ - beside explicitly specified properties it allows only basic HTML element properties and testing IDs
+- overrite the native SCSS `rgba()` function, so it now works for SCSS color values and CSS custom properties
+- ` `
+ - Always add class 'nodrag' to popover content element to always prevent dragging of react-flow and dnd-kit elements when interacting with the component.
+- `utils.getColorConfiguration()` works with CSS custom properties
+- property names returned by `getColorConfiguration` were changed to kebab case because they are originally defined via CSS custom properties
+ - e.g. `graphNode` is now `eccgui-graph-node` and `graphNodeBright` is `eccgui-graph-node-bright`
+- ` ` and ` `
+ - `intent` display was aligned with other components, `intent="primary"` is now `intent="accent"`, in most cases it may be better to use `affirmative={true}` or `elevated={true}` instead of primary/accent intent
+- ` `
+ - `intent` display was aligned with other components, `intent="primary"` is now `intent="accent"`, in most cases it may be better to use `elevated={true}` instead of using intent
+- icons: arrow directions for `list-sortasc` and `list-sortdesc` were switched, up arrow is now used for ascending sort
+
+### Deprecated
+
+- support for React Flow v9 will be removed in v26
+- ` `
+ - use ` ` or build it on single ` `
## [24.4.1] - 2025-08-25
@@ -129,6 +248,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
### Changed
+- `eslint` libraries were upgraded to v9, so `node` v18.18 or higher is required
+- react flow integration by renaming their resources from `legacy` and `next` to more precise `v9` and `v10`:
+ - `HandleProps`: renamed to `HandleV9Props`
+ - `HandleNextProps`: renamed to `HandleV10Props`
+ - if provided then the `flowVersion` property do not accept `legacy` and `next` as values anymore, use `v9` and `v10`
- some more interfaces are exposed:
- `IntentBlueprint`: BlueprintJS intent types, also available by `DefinitionsBlueprint`
- `TableDataContainerProps`, `TableSimpleContainerProps`, `TableHeadProps`, `TableBodyProps`, `TableExpandedRowProps`, `TableHeaderProps` and `DataTableRenderProps` as interfaces for diverse table components
@@ -151,6 +275,18 @@ Old bundlers like webpack4 do not support the `exports` field from `package.json
If you use Jest then you can use the same aliases for the `moduleNameMapper` config, if necessary.
+### Deprecated
+
+- `HandleV9Props` and `HandleV10Props` export will be removed, use only `HandleDefaultProps`
+- ` `
+ - `businessDate`: will be removed because it is already not used
+- ` `: use ` `
+
+### 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 v24.\* changelogs.
+ - we changed the integration of the supported react flow versions, formerly names `legacy` and `next` resources were renamed to more precise `v9` and `v10`, please see all info in the section about changes
+
## [24.1.0] - 2025-04-16
### Added
@@ -223,6 +359,8 @@ If you use Jest then you can use the same aliases for the `moduleNameMapper` con
- use always ` ` component for `label` value
- ` `
- Refactored data structure position and dimension (breaking change)
+- ` `
+ - component supports now React Flow v9 and v12
### Deprecated
@@ -422,8 +560,6 @@ This is a major release, and it might be not compatible with your current usage
- ` `
- Updated the interface with the ability to use either `selectedItems` or `prePopulateWithItems` properties, which is more logical.
- Fixed deferred `selectedItems` setting.
-- ` `
- - static test id `data-test-id="sticky-note-modal"` will be removed with next major version
- ` `
- `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
- ` `
@@ -450,6 +586,8 @@ This is a major release, and it might be not compatible with your current usage
- ``
- `hasStatePrimary`, `hasStateSuccess`, `hasStateWarning` and `hasStateDanger` properties: use the `intent` property instead.
+- ` `
+ - static test id `data-test-id="sticky-note-modal"` will be removed with next major version
## [23.6.0] - 2024-04-17
diff --git a/README.md b/README.md
index 67e791760..c7f87a6ba 100644
--- a/README.md
+++ b/README.md
@@ -28,22 +28,69 @@ yarn add --dev @types/carbon-components-react
### Configuration
-All [configuration variables](https://github.com/eccenca/gui-elements/blob/develop/src/configuration/_variables.scss) can be set before importing the full library or the default configuration but for the main changes you should need to change only a few parameters:
-
-- Basic colors
- - `$eccgui-color-primary`: color for very important buttons and switches
- - `$eccgui-color-primary-contrast`: readable text color used on primary color areas
- - `$eccgui-color-accent`: color for most conformation buttons, links, etc
- - `$eccgui-color-accent-contrast`: readable text color used on accent color areas
- - `$eccgui-color-applicationheader-text`
- - `$eccgui-color-applicationheader-background`
- - `$eccgui-color-workspace-text`
- - `$eccgui-color-workspace-background`
-- Basic sizes
- - `$eccgui-size-typo-base`: size including absolute unit, currently only `px` is supported
- - `$eccgui-size-typo-base-lineheight`: only ratio to font size, no unit!
- - `$eccgui-size-type-levelratio`: ratio without unit! used to calculate different text sizes based on `$eccgui-size-typo-base`
- - `$eccgui-size-block-whitespace`: white space between block level elements, currently only `px` is supported
+All [configuration variables](https://github.com/eccenca/gui-elements/blob/develop/src/configuration/_variables.scss) can be set before importing the full library or the default configuration but for the main properties you should need to change only a few parameters
+
+#### Colors
+
+Since v25 we use a color palette as basic foundation for color configurations. The palette is defined in 4 sections containing various color tints, each tint includes 5 different weights from 100 (light color) to 900 (dark color).
+
+The default palette can be overwritten if it is defined before the configuration or full library is imported to your Sass styles. The palette need to be defined entirely, we currently don't support overwriting it partly.
+
+```
+$eccgui-color-palette-light: (
+ "identity": (
+ "brand": #fae1cc #f8cd99 #f6b966 #f4a533 #f29100,
+ "accent": #e5f4fb #aecfe3 #77abca #4186b2 #0a6199,
+ "text": #f8f8f8 #bcbcbc #818181 #434343 #090909,
+ "background": #fff #e8e8e8 #d6d6d6 #d4d4d4 #d3d3d3,
+ ),
+ "semantic": (
+ "info": #e5f4fb #aecfe3 #77aaca #4086b2 #096199,
+ "success": #e8f5e9 #b2c6b4 #7c967e #466749 #103713,
+ "warning": #fff3e0 #fad2b3 #f5b287 #f0915a #eb702d,
+ "danger": #fff5f6 #edbfc0 #db8989 #c95253 #b71c1c,
+ ),
+ "layout": (
+ "yellow": #fff6d5 #f1ecb5 #e3db79 #d4c93c #c1a500,
+ "purple": #f4ddf3 #c8a2d1 #9d6eb8 #71378f #480e75,
+ "magenta": #ffd8e8 #f5a6c3 #e276a4 #be4c80 #59122d,
+ "pink": #fde4f1 #e6b4ce #d08aae #bb5f8e #711c4d,
+ "violet": #f4e3f4 #d8b0d8 #b377b3 #904490 #570057,
+ "indigo": #efe4fb #b89ee0 #8f72c5 #6547aa #3b1e8f,
+ "cyan": #dff9fc #86d6e5 #5abfd4 #2da9c4 #0092b3,
+ "teal": #d4f2ec #a3ddd3 #6dc0b2 #479d8d #104c42,
+ "lime": #cde0d6 #bce3c2 #9dcd99 #7ba66c #87b347,
+ "amber": #ffe7b8 #ffe9c4 #f9cd8d #eeb757 #ef8f00,
+ "vermilion": #ffd8cc #e4c4ba #b27a6b #8c4b3a #651c09,
+ "grey": #f5f6f7 #b7b7b7 #808080 #484848 #1c2329,
+ ),
+ "extra": (
+ "gold": #fff7d5 #ebd893 #dfc670 #d3b44e #c7a22b,
+ "silver": #f0f0f0 #dedede #ccc #bababa #a8a8a8,
+ "bronze": #fbe9db #f2d6bc #eac29d #e1af7e #d89b5f,
+ ),
+);
+```
+
+All palette colors will be transformed into CSS custom properties automatically and can be referenced by name scheme `--eccgui-color-palette-{groupname}-{colortint}-{colorweight}`, e.g. `--eccgui-color-palette-identity-brand-100`.
+
+All other colors are based on the palette but it is still possible to set them before the default values are used by importing the configuration or the full library.
+
+- `$eccgui-color-primary`: color for very important buttons and switches
+- `$eccgui-color-primary-contrast`: readable text color used on primary color areas
+- `$eccgui-color-accent`: color for most conformation buttons, links, etc
+- `$eccgui-color-accent-contrast`: readable text color used on accent color areas
+- `$eccgui-color-applicationheader-text`
+- `$eccgui-color-applicationheader-background`
+- `$eccgui-color-workspace-text`
+- `$eccgui-color-workspace-background`
+
+#### Sizes
+
+- `$eccgui-size-typo-base`: size including absolute unit, currently only `px` is supported
+- `$eccgui-size-typo-base-lineheight`: only ratio to font size, no unit!
+- `$eccgui-size-type-levelratio`: ratio without unit! used to calculate different text sizes based on `$eccgui-size-typo-base`
+- `$eccgui-size-block-whitespace`: white space between block level elements, currently only `px` is supported
## Development
diff --git a/package.json b/package.json
index a93daa1b5..1a671be96 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@eccenca/gui-elements",
"description": "GUI elements based on other libraries, usable in React application, written in Typescript.",
- "version": "24.4.1",
+ "version": "25.0.0",
"license": "Apache-2.0",
"homepage": "https://github.com/eccenca/gui-elements",
"bugs": "https://github.com/eccenca/gui-elements/issues",
@@ -73,6 +73,7 @@
"@blueprintjs/select": "^5.3.19",
"@carbon/icons": "^11.58.0",
"@carbon/react": "^1.80.1",
+ "@codemirror/lang-html": "^6.4.9",
"@codemirror/lang-javascript": "^6.2.3",
"@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-markdown": "^6.3.2",
@@ -86,6 +87,7 @@
"codemirror": "^6.0.1",
"color": "^4.2.3",
"compute-scroll-into-view": "^3.1.1",
+ "he": "^1.2.0",
"jshint": "^2.13.6",
"lodash": "^4.17.21",
"n3": "^1.25.1",
@@ -93,11 +95,9 @@
"react": "^16.13.1",
"react-dom": "^16.14.0",
"react-flow-renderer": "9.7.4",
- "react-flow-renderer-lts": "npm:react-flow-renderer@^10.3.17",
"react-inlinesvg": "^3.0.3",
"react-is": "^16.13.1",
"react-markdown": "^10.1.0",
- "react-markdown-deprecated": "npm:react-markdown@^8.0.7",
"react-syntax-highlighter": "^15.6.1",
"rehype-external-links": "^3.0.0",
"rehype-raw": "^7.0.0",
@@ -135,6 +135,7 @@
"@testing-library/react": "^12.1.5",
"@types/codemirror": "^5.60.15",
"@types/color": "^3.0.6",
+ "@types/he": "^1.2.3",
"@types/jest": "^29.5.14",
"@types/jshint": "^2.12.4",
"@types/lodash": "^4.17.16",
@@ -151,8 +152,8 @@
"eslint-plugin-simple-import-sort": "^12.1.1",
"husky": "4",
"identity-obj-proxy": "^3.0.0",
- "jest": "^30.0.5",
- "jest-environment-jsdom": "^30.0.5",
+ "jest": "^30.2.0",
+ "jest-environment-jsdom": "^30.2.0",
"jest-pnp-resolver": "^1.2.3",
"lint-staged": "^15.5.1",
"node-sass-package-importer": "^5.3.3",
diff --git a/src/_shame.scss b/src/_shame.scss
index e808a65f0..cc2509725 100644
--- a/src/_shame.scss
+++ b/src/_shame.scss
@@ -51,6 +51,6 @@ textarea:focus-visible {
}
:focus-visible {
- outline: rgba($eccgui-color-accent, $eccgui-opacity-muted) solid 2px;
+ outline: eccgui-color-rgba($eccgui-color-accent, $eccgui-opacity-muted) solid 2px;
outline-offset: 1px;
}
diff --git a/src/cmem/ContentBlobToggler/StringPreviewContentBlobToggler.tsx b/src/cmem/ContentBlobToggler/StringPreviewContentBlobToggler.tsx
index f9c081265..bb219663c 100644
--- a/src/cmem/ContentBlobToggler/StringPreviewContentBlobToggler.tsx
+++ b/src/cmem/ContentBlobToggler/StringPreviewContentBlobToggler.tsx
@@ -83,4 +83,4 @@ function firstNonEmptyLine(preview: string) {
export const stringPreviewContentBlobTogglerUtils = {
firstNonEmptyLine,
-};
+};
\ No newline at end of file
diff --git a/src/cmem/markdown/Markdown.stories.tsx b/src/cmem/markdown/Markdown.stories.tsx
index d067e7912..2754e20cf 100644
--- a/src/cmem/markdown/Markdown.stories.tsx
+++ b/src/cmem/markdown/Markdown.stories.tsx
@@ -1,5 +1,4 @@
import React from "react";
-import { Blockquote } from "@blueprintjs/core";
import { Meta, StoryFn } from "@storybook/react";
import { Markdown } from "./../../../index";
diff --git a/src/cmem/markdown/Markdown.tsx b/src/cmem/markdown/Markdown.tsx
index 8f0b0282c..7544d8f95 100644
--- a/src/cmem/markdown/Markdown.tsx
+++ b/src/cmem/markdown/Markdown.tsx
@@ -1,21 +1,15 @@
import React from "react";
import ReactMarkdown from "react-markdown";
-/**
- * Recreate the old type to provide support until next major
- */
-import { PluggableList as PluggableListDeprecated } from "react-markdown-deprecated/lib/react-markdown";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
// @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 rehypeExternalLinks from "rehype-external-links";
import rehypeRaw from "rehype-raw";
import { remarkDefinitionList } from "remark-definition-list";
import remarkGfm from "remark-gfm";
-import { PluggableList as PluggableListUnified } from "unified";
+import { PluggableList } from "unified";
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
import { HtmlContentBlock, HtmlContentBlockProps, TestableComponent } from "../../index";
-type PluggableList = PluggableListUnified | PluggableListDeprecated;
export interface MarkdownProps extends TestableComponent {
children: string;
@@ -41,7 +35,6 @@ export interface MarkdownProps extends TestableComponent {
/**
* Additional reHype plugins to execute.
* @see https://github.com/remarkjs/react-markdown#architecture
- * @deprecated (v25) this property won't support `PluggableList` from "react-markdown/lib/react-markdown" with the next major version, only the one from `unified` will be supported then.
*/
reHypePlugins?: PluggableList;
/**
@@ -61,9 +54,9 @@ const configDefault = {
@see https://github.com/remarkjs/react-markdown#api
*/
// @see https://github.com/remarkjs/remark/blob/main/doc/plugins.md#list-of-plugins
- remarkPlugins: [remarkGfm, remarkTypograf, remarkDefinitionList] as PluggableListUnified,
+ remarkPlugins: [remarkGfm, remarkDefinitionList] as PluggableList,
// @see https://github.com/rehypejs/rehype/blob/main/doc/plugins.md#list-of-plugins
- rehypePlugins: [] as PluggableListUnified,
+ rehypePlugins: [] as PluggableList,
allowedElements: [
// default markdown
"a",
@@ -173,9 +166,7 @@ export const Markdown = ({
};
if (reHypePlugins) {
- reactMarkdownProperties.rehypePlugins = reactMarkdownProperties.rehypePlugins.concat(
- reHypePlugins as PluggableListUnified
- );
+ reactMarkdownProperties.rehypePlugins = reactMarkdownProperties.rehypePlugins.concat(reHypePlugins);
}
const markdownDisplay = ;
diff --git a/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx b/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx
index 147dc9d6e..8abe52313 100644
--- a/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx
+++ b/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx
@@ -1,375 +1,431 @@
import React, { FC, useCallback, useEffect, useState } from "react";
-import { Elements, FlowElement } from "react-flow-renderer";
+import {
+ Background as BackgroundV9,
+ BackgroundVariant as BackgroundVariantV9,
+ Elements,
+ FlowElement,
+ Position,
+} from "react-flow-renderer";
import { Meta, StoryFn } from "@storybook/react";
+import { fn } from "@storybook/test";
+import {
+ Background as BackgroundV12,
+ BackgroundVariant as BackgroundVariantV12,
+ Edge as Edge12,
+ Node as Node12,
+ useEdgesState as useEdgesState12,
+ useNodesState as useNodesState12,
+} from "@xyflow/react";
-import { EdgeTools, NodeTools, ReactFlow } from "./../../../index";
-import { ReactFlowProps } from "./ReactFlow";
+import {
+ ApplicationContainer,
+ EdgeTools,
+ MiniMap,
+ NodeTools,
+ ReactFlowExtended,
+ ReactFlowExtendedProps,
+} from "./../../../index";
const nodeExamples = {
- unspecified: [
- {
- id: "unspecified-1",
- type: "default",
- data: {
- label: "Default ",
- content: "Example content.",
- minimalShape: "none",
- menuButtons: Pass your menu here. ,
- },
- position: { x: 200, y: 50 },
- },
- {
- id: "unspecified-2",
- type: "default",
- data: {
- label: "Default ",
- content: "Example content.",
- minimalShape: "none",
- handles: [
- { type: "source", position: "left" },
- { type: "target", position: "right" },
- ],
- },
- position: { x: 200, y: 300 },
- },
- {
- id: "unspecified-e1",
- type: "straight",
- label: "straight edge",
- arrowHeadType: "arrowclosed",
- source: "unspecified-1",
- target: "unspecified-2",
- },
- {
- id: "unspecified-e2",
- type: "step",
- label: "step edge",
- arrowHeadType: "arrowclosed",
- source: "unspecified-2",
- target: "unspecified-1",
- },
- ],
- linking: [
- {
- id: "linking-1",
- type: "sourcepath",
- data: {
- label: "Source path",
- content: "Example content.",
- minimalShape: "none",
- menuButtons: Pass your menu here. ,
- },
- position: { x: 100, y: 50 },
- },
- {
- id: "linking-2",
- type: "targetpath",
- data: {
- label: "Target path",
- content: "Example content.",
- minimalShape: "none",
- },
- position: { x: 400, y: 200 },
- },
- {
- id: "linking-3",
- type: "transformation",
- data: {
- label: "Transformation",
- content: "Example content.",
- minimalShape: "none",
- },
- position: { x: 700, y: 50 },
- },
- {
- id: "linking-4",
- type: "comparator",
- data: {
- label: "Comparation",
- content: "Example content.",
- minimalShape: "none",
- handles: [
- { type: "source", position: "left" },
- { type: "target", position: "right" },
- ],
- },
- position: { x: 750, y: 300 },
- },
- {
- id: "linking-5",
- type: "aggregator",
- data: {
- label: "Aggregation",
- content: "Example content.",
- minimalShape: "none",
- handles: [
- { type: "source", position: "left" },
- { type: "target", position: "right" },
- ],
- },
- position: { x: 50, y: 300 },
- },
- {
- id: "linking-e1",
- type: "value",
- label: "value edge",
- arrowHeadType: "arrowclosed",
- source: "linking-1",
- target: "linking-2",
- },
- {
- id: "linking-e2",
- type: "score",
- label: "score edge",
- arrowHeadType: "arrowclosed",
- source: "linking-2",
- target: "linking-3",
- },
- {
- id: "linking-e3",
- type: "success",
- label: "success edge",
- arrowHeadType: "arrowclosed",
- source: "linking-3",
- target: "linking-4",
- },
- {
- id: "linking-e4",
- type: "warning",
- label: "warning edge",
- arrowHeadType: "arrowclosed",
- source: "linking-4",
- target: "linking-5",
- },
- {
- id: "linking-e5",
- type: "danger",
- label: "danger edge",
- arrowHeadType: "arrowclosed",
- source: "linking-5",
- target: "linking-1",
- },
- ],
- workflow: [
- {
- id: "workflow-1",
- type: "dataset",
- data: {
- label: "Dataset",
- content: "Example content.",
- minimalShape: "none",
- menuButtons: Pass your menu here. ,
- },
- position: { x: 100, y: 50 },
- },
- {
- id: "workflow-2",
- type: "linking",
- data: {
- label: "Linking",
- content: "Example content.",
- minimalShape: "none",
- },
- position: { x: 400, y: 200 },
- },
- {
- id: "workflow-3",
- type: "transform",
- data: {
- label: "Transform",
- content: "Example content.",
- minimalShape: "none",
- },
- position: { x: 700, y: 50 },
- },
- {
- id: "workflow-4",
- type: "task",
- data: {
- label: "Task",
- content: "Example content.",
- minimalShape: "none",
- handles: [
- { type: "source", position: "left" },
- { type: "target", position: "right" },
- ],
- },
- position: { x: 750, y: 300 },
- },
- {
- id: "workflow-5",
- type: "workflow",
- data: {
- label: "Workflow",
- content: "Example content.",
- minimalShape: "none",
- handles: [
- { type: "source", position: "left" },
- { type: "target", position: "right" },
- ],
- },
- position: { x: 50, y: 300 },
- },
- {
- id: "workflow-e1",
- label: "default",
- arrowHeadType: "arrowclosed",
- source: "workflow-1",
- target: "workflow-2",
- },
- {
- id: "workflow-e2",
- label: "default",
- arrowHeadType: "arrowclosed",
- source: "workflow-2",
- target: "workflow-3",
- },
- {
- id: "workflow-e3",
- type: "success",
- label: "success edge",
- arrowHeadType: "arrowclosed",
- source: "workflow-3",
- target: "workflow-4",
- },
- {
- id: "workflow-e4",
- type: "warning",
- label: "warning edge",
- arrowHeadType: "arrowclosed",
- source: "workflow-4",
- target: "workflow-5",
- },
- {
- id: "workflow-e5",
- type: "danger",
- label: "danger edge",
- arrowHeadType: "arrowclosed",
- source: "workflow-5",
- target: "workflow-1",
- },
- ],
- graph: [
- {
- id: "graph-1",
- type: "default",
- data: {
- label: "Default ",
- content: "Example content.",
- minimalShape: "none",
- menuButtons: Pass your menu here. ,
- },
- position: { x: 100, y: 50 },
- },
- {
- id: "graph-2",
- type: "graph",
- data: {
- label: "Graph",
- content: "Example content.",
- minimalShape: "none",
- },
- position: { x: 400, y: 200 },
- },
- {
- id: "graph-3",
- type: "class",
- data: {
- label: "Class",
- content: "Example content.",
- minimalShape: "none",
- },
- position: { x: 700, y: 50 },
- },
- {
- id: "graph-4",
- type: "instance",
- data: {
- label: "Instance",
- content: "Example content.",
- minimalShape: "none",
- handles: [
- { type: "source", position: "left" },
- { type: "target", position: "right" },
- ],
- },
- position: { x: 750, y: 300 },
- },
- {
- id: "graph-5",
- type: "property",
- data: {
- label: "Property",
- content: "Example content.",
- minimalShape: "none",
- handles: [
- { type: "source", position: "left" },
- { type: "target", position: "right" },
- ],
- },
- position: { x: 50, y: 300 },
- },
- {
- id: "graph-e1",
- type: "implicit",
- label: "implicit edge",
- arrowHeadType: "arrowclosed",
- source: "graph-1",
- target: "graph-2",
- },
- {
- id: "graph-e2",
- type: "import",
- label: "import edge",
- arrowHeadType: "arrowclosed",
- source: "graph-2",
- target: "graph-3",
- },
- {
- id: "graph-e3",
- type: "subclass",
- label: "subclass edge",
- arrowHeadType: "arrowclosed",
- source: "graph-3",
- target: "graph-4",
- },
- {
- id: "graph-e4",
- type: "subproperty",
- label: "subproperty edge",
- arrowHeadType: "arrowclosed",
- source: "graph-4",
- target: "graph-5",
- },
- {
- id: "graph-e5",
- type: "rdftype",
- label: "rdftype edge",
- arrowHeadType: "arrowclosed",
- source: "graph-5",
- target: "graph-1",
- },
- ],
+ unspecified: {
+ nodes: [
+ {
+ id: "unspecified-1",
+ type: "default",
+ data: {
+ label: "Default ",
+ content: "Example content.",
+ minimalShape: "none",
+ menuButtons: Pass your menu here. ,
+ },
+ position: { x: 200, y: 50 },
+ },
+ {
+ id: "unspecified-2",
+ type: "default",
+ targetPosition: Position.Right,
+ sourcePosition: Position.Left,
+ data: {
+ label: "Default ",
+ content: "Example content.",
+ minimalShape: "none",
+ handles: [
+ { type: "source", position: "left" },
+ { type: "target", position: "right" },
+ ],
+ },
+ position: { x: 200, y: 300 },
+ },
+ ],
+ edges: [
+ {
+ id: "unspecified-e1",
+ type: "straight",
+ label: "straight edge",
+ arrowHeadType: "arrowclosed",
+ source: "unspecified-1",
+ target: "unspecified-2",
+ },
+ {
+ id: "unspecified-e2",
+ type: "step",
+ label: "step edge",
+ arrowHeadType: "arrowclosed",
+ source: "unspecified-2",
+ target: "unspecified-1",
+ },
+ ],
+ },
+ linking: {
+ nodes: [
+ {
+ id: "linking-1",
+ type: "sourcepath",
+ data: {
+ label: "Source path",
+ content: "Example content.",
+ minimalShape: "none",
+ menuButtons: Pass your menu here. ,
+ },
+ position: { x: 100, y: 50 },
+ },
+ {
+ id: "linking-2",
+ type: "targetpath",
+ data: {
+ label: "Target path",
+ content: "Example content.",
+ minimalShape: "none",
+ },
+ position: { x: 400, y: 200 },
+ },
+ {
+ id: "linking-3",
+ type: "transformation",
+ data: {
+ label: "Transformation",
+ content: "Example content.",
+ minimalShape: "none",
+ },
+ position: { x: 700, y: 50 },
+ },
+ {
+ id: "linking-4",
+ type: "comparator",
+ targetPosition: Position.Right,
+ sourcePosition: Position.Left,
+ data: {
+ label: "Comparation",
+ content: "Example content.",
+ minimalShape: "none",
+ handles: [
+ { type: "source", position: "left" },
+ { type: "target", position: "right" },
+ ],
+ },
+ position: { x: 750, y: 300 },
+ },
+ {
+ id: "linking-5",
+ type: "aggregator",
+ targetPosition: Position.Right,
+ sourcePosition: Position.Left,
+ data: {
+ label: "Aggregation",
+ content: "Example content.",
+ minimalShape: "none",
+ handles: [
+ { type: "source", position: "left" },
+ { type: "target", position: "right" },
+ ],
+ },
+ position: { x: 50, y: 300 },
+ },
+ ],
+ edges: [
+ {
+ id: "linking-e1",
+ type: "value",
+ label: "value edge",
+ arrowHeadType: "arrowclosed",
+ source: "linking-1",
+ target: "linking-2",
+ },
+ {
+ id: "linking-e2",
+ type: "score",
+ label: "score edge",
+ arrowHeadType: "arrowclosed",
+ source: "linking-2",
+ target: "linking-3",
+ },
+ {
+ id: "linking-e3",
+ type: "success",
+ label: "success edge",
+ arrowHeadType: "arrowclosed",
+ source: "linking-3",
+ target: "linking-4",
+ },
+ {
+ id: "linking-e4",
+ type: "warning",
+ label: "warning edge",
+ arrowHeadType: "arrowclosed",
+ source: "linking-4",
+ target: "linking-5",
+ },
+ {
+ id: "linking-e5",
+ type: "danger",
+ label: "danger edge",
+ arrowHeadType: "arrowclosed",
+ source: "linking-5",
+ target: "linking-1",
+ },
+ ],
+ },
+ workflow: {
+ nodes: [
+ {
+ id: "workflow-1",
+ type: "dataset",
+ data: {
+ label: "Dataset",
+ content: "Example content.",
+ minimalShape: "none",
+ menuButtons: Pass your menu here. ,
+ },
+ position: { x: 100, y: 50 },
+ },
+ {
+ id: "workflow-2",
+ type: "linking",
+ data: {
+ label: "Linking",
+ content: "Example content.",
+ minimalShape: "none",
+ },
+ position: { x: 400, y: 200 },
+ },
+ {
+ id: "workflow-3",
+ type: "transform",
+ data: {
+ label: "Transform",
+ content: "Example content.",
+ minimalShape: "none",
+ },
+ position: { x: 700, y: 50 },
+ },
+ {
+ id: "workflow-4",
+ type: "task",
+ targetPosition: Position.Right,
+ sourcePosition: Position.Left,
+ data: {
+ label: "Task",
+ content: "Example content.",
+ minimalShape: "none",
+ handles: [
+ { type: "source", position: "left" },
+ { type: "target", position: "right" },
+ ],
+ },
+ position: { x: 750, y: 300 },
+ },
+ {
+ id: "workflow-5",
+ type: "workflow",
+ targetPosition: Position.Right,
+ sourcePosition: Position.Left,
+ data: {
+ label: "Workflow",
+ content: "Example content.",
+ minimalShape: "none",
+ handles: [
+ { type: "source", position: "left" },
+ { type: "target", position: "right" },
+ ],
+ },
+ position: { x: 50, y: 300 },
+ },
+ ],
+ edges: [
+ {
+ id: "workflow-e1",
+ label: "default",
+ arrowHeadType: "arrowclosed",
+ source: "workflow-1",
+ target: "workflow-2",
+ },
+ {
+ id: "workflow-e2",
+ label: "default",
+ arrowHeadType: "arrowclosed",
+ source: "workflow-2",
+ target: "workflow-3",
+ },
+ {
+ id: "workflow-e3",
+ type: "success",
+ label: "success edge",
+ arrowHeadType: "arrowclosed",
+ source: "workflow-3",
+ target: "workflow-4",
+ },
+ {
+ id: "workflow-e4",
+ type: "warning",
+ label: "warning edge",
+ arrowHeadType: "arrowclosed",
+ source: "workflow-4",
+ target: "workflow-5",
+ },
+ {
+ id: "workflow-e5",
+ type: "danger",
+ label: "danger edge",
+ arrowHeadType: "arrowclosed",
+ source: "workflow-5",
+ target: "workflow-1",
+ },
+ ],
+ },
+ graph: {
+ nodes: [
+ {
+ id: "graph-1",
+ type: "default",
+ data: {
+ label: "Default ",
+ content: "Example content.",
+ minimalShape: "none",
+ menuButtons: Pass your menu here. ,
+ },
+ position: { x: 100, y: 50 },
+ },
+ {
+ id: "graph-2",
+ type: "graph",
+ data: {
+ label: "Graph",
+ content: "Example content.",
+ minimalShape: "none",
+ },
+ position: { x: 400, y: 200 },
+ },
+ {
+ id: "graph-3",
+ type: "class",
+ data: {
+ label: "Class",
+ content: "Example content.",
+ minimalShape: "none",
+ },
+ position: { x: 700, y: 50 },
+ },
+ {
+ id: "graph-4",
+ type: "instance",
+ targetPosition: Position.Right,
+ sourcePosition: Position.Left,
+ data: {
+ label: "Instance",
+ content: "Example content.",
+ minimalShape: "none",
+ handles: [
+ { type: "source", position: "left" },
+ { type: "target", position: "right" },
+ ],
+ },
+ position: { x: 750, y: 300 },
+ },
+ {
+ id: "graph-5",
+ type: "property",
+ targetPosition: Position.Right,
+ sourcePosition: Position.Left,
+ data: {
+ label: "Property",
+ content: "Example content.",
+ minimalShape: "none",
+ handles: [
+ { type: "source", position: "left" },
+ { type: "target", position: "right" },
+ ],
+ },
+ position: { x: 50, y: 300 },
+ },
+ ],
+ edges: [
+ {
+ id: "graph-e1",
+ type: "implicit",
+ label: "implicit edge",
+ arrowHeadType: "arrowclosed",
+ source: "graph-1",
+ target: "graph-2",
+ },
+ {
+ id: "graph-e2",
+ type: "import",
+ label: "import edge",
+ arrowHeadType: "arrowclosed",
+ source: "graph-2",
+ target: "graph-3",
+ },
+ {
+ id: "graph-e3",
+ type: "subclass",
+ label: "subclass edge",
+ arrowHeadType: "arrowclosed",
+ source: "graph-3",
+ target: "graph-4",
+ },
+ {
+ id: "graph-e4",
+ type: "subproperty",
+ label: "subproperty edge",
+ arrowHeadType: "arrowclosed",
+ source: "graph-4",
+ target: "graph-5",
+ },
+ {
+ id: "graph-e5",
+ type: "rdftype",
+ label: "rdftype edge",
+ arrowHeadType: "arrowclosed",
+ source: "graph-5",
+ target: "graph-1",
+ },
+ ],
+ },
};
export default {
title: "CMEM/React Flow/Configurations",
- component: ReactFlow,
+ component: ReactFlowExtended,
argTypes: {
configuration: {
control: "select",
options: Object.keys(nodeExamples),
},
+ flowVersion: {
+ control: "select",
+ options: [undefined, "v9", "v12"],
+ },
},
-} as Meta;
+} as Meta;
-const ReactFlowExample: FC = (args) => {
- const [reactflowInstance, setReactflowInstance] = useState(null);
+const ReactFlowExampleV9: FC = (args) => {
+ const [reactflowInstance, setReactflowInstance] = useState(undefined);
const [elements, setElements] = useState([] as Elements);
const [edgeTools, setEdgeTools] = useState(<>>);
useEffect(() => {
- setElements(nodeExamples[args.configuration ?? "unspecified"] as Elements);
+ const examples = nodeExamples[args.configuration ?? "unspecified"];
+ setElements([...examples.nodes, ...examples.edges] as Elements);
}, [args]);
// Helper methods for nodes and edges
@@ -402,31 +458,81 @@ const ReactFlowExample: FC = (args) => {
[reactflowInstance]
);
- const { configuration, ...otherArgs } = args;
+ const { style, ...otherProps } = args;
+ const { height, width, ...otherStyles } = style ?? {};
+
+ const reactFlowExtendedProps = {
+ ...otherProps,
+ style: otherStyles,
+ defaultZoom: 1,
+ elements,
+ onLoad,
+ onElementClick,
+ onEdgeContextMenu: onElementClick,
+ };
return (
- <>
-
+
+
+
+
+
+
+
{edgeTools}
- >
+
+ );
+};
+
+const ReactFlowExampleV12: FC = (args) => {
+ const [nodes, ,] = useNodesState12(nodeExamples[args.configuration ?? "unspecified"].nodes as Node12[]);
+ const [edges, ,] = useEdgesState12(nodeExamples[args.configuration ?? "unspecified"].edges as Edge12[]);
+
+ const { style, ...otherProps } = args;
+ const { height, width, ...otherStyles } = style ?? {};
+
+ const reactFlowExtendedProps = {
+ ...otherProps,
+ style: otherStyles,
+ defaultViewport: { x: 0, y: 0, zoom: 1 },
+ nodes,
+ edges,
+ };
+
+ return (
+
+
+
+
+
+
+
+
);
};
-const Template: StoryFn = (args) => ;
+const ReactFlowExample: FC = (args) => {
+ switch (args.flowVersion) {
+ case undefined:
+ case "v9":
+ return ;
+ case "v12":
+ return ;
+ default:
+ return <>>;
+ }
+};
+
+let forcedUpdateKey = 0; // @see https://github.com/storybookjs/storybook/issues/13375#issuecomment-1291011856
+const Template: StoryFn = (args) => ;
export const Default = Template.bind({});
Default.args = {
configuration: "unspecified",
+ dropzoneFor: ["Files"],
"data-test-id": "reactflow-test-id",
"data-testid": "reactflow-testid",
+ style: { height: "400px" },
+ onSelectionChange: fn(),
};
Default.nodeExamples = nodeExamples;
diff --git a/src/cmem/react-flow/ReactFlow/ReactFlow.tsx b/src/cmem/react-flow/ReactFlow/ReactFlow.tsx
index 01aa61cd4..17d56e096 100644
--- a/src/cmem/react-flow/ReactFlow/ReactFlow.tsx
+++ b/src/cmem/react-flow/ReactFlow/ReactFlow.tsx
@@ -1,17 +1,21 @@
-import React from "react";
-import { default as ReactFlowOriginal, ReactFlowProps as ReactFlowOriginalProps } from "react-flow-renderer";
+import React, { ReactElement, Ref } from "react";
+import { KeyCode as KeyCodeV9 } from "react-flow-renderer";
+import { KeyCode as KeyCodeV12 } from "@xyflow/react";
import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
import { ReactFlowMarkers } from "../../../extensions/react-flow/markers/ReactFlowMarkers";
+import { ReactFlowVersions } from "../../../extensions/react-flow/versionsupport";
import { ReactFlowHotkeyContext } from "../extensions/ReactFlowHotkeyContext";
-import { useReactFlowScrollOnDrag } from "../extensions/scrollOnDragHook";
+import { useReactFlowScrollOnDragV9 } from "../extensions/scrollOnDragHook";
import * as graphConfig from "./../configuration/graph";
import * as linkingConfig from "./../configuration/linking";
import * as unspecifiedConfig from "./../configuration/unspecified";
import * as workflowConfig from "./../configuration/workflow";
+import { ReactFlowV9Container, ReactFlowV9ContainerProps } from "./ReactFlowV9";
+import { ReactFlowV12Container, ReactFlowV12ContainerProps } from "./ReactFlowV12";
-export interface ReactFlowProps extends ReactFlowOriginalProps {
+export interface ReactFlowExtendedExtraProps {
/**
* Load `ReactFlow` component with pre-configured values for `nodeTypes` and `edgeTypes`
*/
@@ -21,7 +25,9 @@ export interface ReactFlowProps extends ReactFlowOriginalProps {
* Types data transfers that can be dragged in and dropped on the canvas.
*/
dropzoneFor?: string[];
+}
+export interface ReactFlowExtendedScrollProps {
/** If defined the canvas scrolls on all drag operations (node, selection, edge connect)
* when the mouse pointer comes near the canvas borders or goes beyond them.
* The `id` property of the ReactFlow component must be set in order for this to work.
@@ -38,76 +44,174 @@ export interface ReactFlowProps extends ReactFlowOriginalProps {
};
}
+interface ReactFlowExtendedVersion9SupportProps {
+ /**
+ * Set version of `ReactFlow` that is used internally.
+ * If not set then v9 is used.
+ */
+ flowVersion?: ReactFlowVersions.V9;
+}
+
+interface ReactFlowExtendedVersion12SupportProps {
+ /**
+ * Set version of `ReactFlow` that is used internally.
+ */
+ flowVersion: ReactFlowVersions.V12;
+ /**
+ * Extra scroll on drag (pan on drag) support from our side should not be necessary anymore with v12.
+ */
+ scrollOnDrag?: never;
+}
+
+export type ReactFlowExtendedPropsV9 = ReactFlowExtendedVersion9SupportProps &
+ ReactFlowV9ContainerProps &
+ ReactFlowExtendedExtraProps &
+ ReactFlowExtendedScrollProps;
+export type ReactFlowExtendedPropsV12 = ReactFlowExtendedVersion12SupportProps &
+ ReactFlowV12ContainerProps &
+ ReactFlowExtendedExtraProps;
+
+export type ReactFlowExtendedProps = ReactFlowExtendedPropsV9 | ReactFlowExtendedPropsV12;
+
/**
* `ReactFlow` container extension that includes pre-configured nodes and edges for
* Corporate Memory tools.
+ *
+ * @param T The concrete type of the corresponding version, i.e. either one of ReactFlowExtendedPropsV9 or ReactFlowExtendedPropsV12
*/
-export const ReactFlow = React.forwardRef(
- ({ configuration = "unspecified", scrollOnDrag, dropzoneFor, children, className, ...originalProps }, outerRef) => {
- const innerRef = React.useRef(null);
- React.useImperativeHandle(outerRef, () => innerRef.current!, []);
-
- React.useEffect(() => {
- const reactflowContainer = innerRef?.current;
-
- if (reactflowContainer && dropzoneFor) {
- const addDragover = (event: DragEvent) => {
- reactflowContainer.classList.add(`${eccgui}-graphviz__canvas--draghover`);
- event.preventDefault();
- };
-
- const removeDragover = (event: DragEvent) => {
- if (reactflowContainer === event.target) {
- reactflowContainer.classList.remove(`${eccgui}-graphviz__canvas--draghover`);
- }
- };
-
- reactflowContainer.addEventListener("dragover", addDragover);
- reactflowContainer.addEventListener("dragleave", removeDragover);
- reactflowContainer.addEventListener("drop", removeDragover);
- return () => {
- reactflowContainer.removeEventListener("dragover", addDragover);
- reactflowContainer.removeEventListener("dragleave", removeDragover);
- reactflowContainer.removeEventListener("drop", removeDragover);
- };
- }
- return;
- }, [innerRef, dropzoneFor]);
-
- /** If the hot keys should be disabled. By default, they are always disabled. */
- const { hotKeysDisabled } = React.useContext(ReactFlowHotkeyContext);
-
- const scrollOnDragFunctions = useReactFlowScrollOnDrag({
- reactFlowProps: originalProps,
- scrollOnDrag,
- });
-
- const { selectionKeyCode, multiSelectionKeyCode, deleteKeyCode, zoomActivationKeyCode } = originalProps;
-
- const configReactFlow = {
- unspecified: unspecifiedConfig,
- graph: graphConfig,
- workflow: workflowConfig,
- linking: linkingConfig,
- };
-
- return (
-
- {children}
-
-
- );
+const ReactFlowExtendedPlain = (
+ {
+ configuration = "unspecified",
+ flowVersion = ReactFlowVersions.V9,
+ dropzoneFor,
+ scrollOnDrag,
+ children,
+ className,
+ selectionKeyCode,
+ multiSelectionKeyCode,
+ deleteKeyCode,
+ zoomActivationKeyCode,
+ ...originalProps
+ }: T,
+ outerRef: Ref
+) => {
+ const innerRef = React.useRef(null);
+ React.useImperativeHandle(outerRef, () => innerRef.current!, []);
+
+ React.useEffect(() => {
+ const reactflowContainer = innerRef?.current;
+
+ if (reactflowContainer && dropzoneFor) {
+ const addDragover = (event: DragEvent) => {
+ reactflowContainer.classList.add(`${eccgui}-graphviz__canvas--draghover`);
+ event.preventDefault();
+ };
+
+ const removeDragover = (event: DragEvent) => {
+ if (reactflowContainer === event.target) {
+ reactflowContainer.classList.remove(`${eccgui}-graphviz__canvas--draghover`);
+ }
+ };
+
+ reactflowContainer.addEventListener("dragover", addDragover);
+ reactflowContainer.addEventListener("dragleave", removeDragover);
+ reactflowContainer.addEventListener("drop", removeDragover);
+ return () => {
+ reactflowContainer.removeEventListener("dragover", addDragover);
+ reactflowContainer.removeEventListener("dragleave", removeDragover);
+ reactflowContainer.removeEventListener("drop", removeDragover);
+ };
+ }
+ return;
+ }, [innerRef, dropzoneFor]);
+
+ /** If the hot keys should be disabled. By default, they are always disabled. */
+ const { hotKeysDisabled } = React.useContext(ReactFlowHotkeyContext);
+
+ const configReactFlow = {
+ unspecified: unspecifiedConfig,
+ graph: graphConfig,
+ workflow: workflowConfig,
+ linking: linkingConfig,
+ };
+
+ const sharedProperties = {
+ className:
+ `${eccgui}-graphviz__canvas` +
+ ` ${eccgui}-configuration--colors__react-flow-${configuration}` +
+ (className ? ` ${className}` : ""),
+ nodeTypes: configReactFlow[configuration].nodeTypes,
+ edgeTypes: configReactFlow[configuration].edgeTypes,
+ "data-dropzone-for": dropzoneFor ? dropzoneFor.join(" ") : undefined,
+ };
+
+ let keyCodeConfig = {};
+ switch (flowVersion) {
+ case "v9":
+ keyCodeConfig = {
+ selectionKeyCode: hotKeysDisabled ? undefined : (selectionKeyCode as KeyCodeV9),
+ deleteKeyCode: hotKeysDisabled ? undefined : (deleteKeyCode as KeyCodeV9),
+ multiSelectionKeyCode: hotKeysDisabled ? undefined : (multiSelectionKeyCode as KeyCodeV9),
+ zoomActivationKeyCode: hotKeysDisabled ? undefined : (zoomActivationKeyCode as KeyCodeV9),
+ };
+ break;
+ case "v12":
+ keyCodeConfig = {
+ selectionKeyCode: hotKeysDisabled ? null : (selectionKeyCode as KeyCodeV12),
+ deleteKeyCode: hotKeysDisabled ? null : (deleteKeyCode as KeyCodeV12),
+ multiSelectionKeyCode: hotKeysDisabled ? null : (multiSelectionKeyCode as KeyCodeV12),
+ zoomActivationKeyCode: hotKeysDisabled ? null : (zoomActivationKeyCode as KeyCodeV12),
+ };
+ break;
+ }
+
+ let scrollOnDragFunctions = {};
+ switch (flowVersion) {
+ case "v9":
+ scrollOnDragFunctions = useReactFlowScrollOnDragV9({
+ reactFlowProps: originalProps as unknown as ReactFlowV9ContainerProps,
+ scrollOnDrag,
+ });
+ break;
+ // should not be necessary for v12
}
-);
+
+ const containerConfig = {
+ ...sharedProperties,
+ ...keyCodeConfig,
+ ...originalProps,
+ ...scrollOnDragFunctions,
+ };
+
+ switch (flowVersion) {
+ case "v9":
+ return (
+
+ {children}
+
+
+ );
+ case "v12":
+ return (
+
+ {children}
+
+
+ );
+ default:
+ return
;
+ }
+};
+
+/** Hack to make the Type Parameter work with the forward ref. */
+export const ReactFlowExtended = React.forwardRef(ReactFlowExtendedPlain) as (
+ p: T & { ref?: Ref }
+) => ReactElement;
+
+/**
+ * @deprecated (v26) use `ReactFlowExtended`
+ */
+export const ReactFlow = ReactFlowExtended;
+
+/** Classes that when set for an element, prevent that they trigger react-flow dragging, wheel and panning actions. */
+export const preventReactFlowActionsClasses = "nodrag nopan nowheel";
diff --git a/src/cmem/react-flow/ReactFlow/ReactFlowV12.tsx b/src/cmem/react-flow/ReactFlow/ReactFlowV12.tsx
new file mode 100644
index 000000000..23b22e2fb
--- /dev/null
+++ b/src/cmem/react-flow/ReactFlow/ReactFlowV12.tsx
@@ -0,0 +1,56 @@
+import React from "react";
+import {
+ Edge,
+ Node,
+ ReactFlow as ReactFlowV12,
+ ReactFlowProps as ReactFlowV12Props,
+ useEdgesState,
+ useNodesState,
+} from "@xyflow/react";
+
+import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
+import { EdgeNew } from "./../../../extensions/react-flow/edges/EdgeNew";
+
+export type ReactFlowV12ContainerProps = ReactFlowV12Props;
+
+/**
+ * Our own `ReactFlow` v12 container.
+ */
+export const ReactFlowV12Container = React.forwardRef(
+ ({ children, className, ...originalProps }, outerRef) => {
+ const innerRef = React.useRef(null);
+ React.useImperativeHandle(outerRef, () => innerRef.current!, []);
+
+ const [nodesFallback, , onNodesChangeFallback] = useNodesState(originalProps.nodes || ([] as Node[]));
+ const [edgesFallback, , onEdgesChangeFallback] = useEdgesState(originalProps.edges || ([] as Edge[]));
+
+ const missingNodesChangeCallback =
+ !!originalProps.nodes && !originalProps.onNodesChange
+ ? {
+ nodes: nodesFallback,
+ onNodesChange: onNodesChangeFallback,
+ }
+ : {};
+
+ const missingEdgesChangeCallback =
+ !!originalProps.edges && !originalProps.onEdgesChange
+ ? {
+ edges: edgesFallback,
+ onEdgesChange: onEdgesChangeFallback,
+ }
+ : {};
+
+ return (
+
+ {children}
+
+ );
+ }
+);
diff --git a/src/cmem/react-flow/ReactFlow/ReactFlowV9.tsx b/src/cmem/react-flow/ReactFlow/ReactFlowV9.tsx
new file mode 100644
index 000000000..247a72899
--- /dev/null
+++ b/src/cmem/react-flow/ReactFlow/ReactFlowV9.tsx
@@ -0,0 +1,29 @@
+import React from "react";
+import {
+ default as ReactFlowV9,
+ ReactFlowProps as ReactFlowV9Props
+} from "react-flow-renderer";
+
+import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
+
+export type ReactFlowV9ContainerProps = ReactFlowV9Props;
+
+/**
+ * Our own `ReactFlow` v9 container.
+ */
+export const ReactFlowV9Container = React.forwardRef(
+ ({ children, className, ...originalProps }, outerRef) => {
+ const innerRef = React.useRef(null);
+ React.useImperativeHandle(outerRef, () => innerRef.current!, []);
+
+ return (
+
+ {children}
+
+ );
+ }
+);
diff --git a/src/cmem/react-flow/StickyNoteModal/StickyNoteModal.tsx b/src/cmem/react-flow/StickyNoteModal/StickyNoteModal.tsx
index 561cd2dfb..924cb7e51 100644
--- a/src/cmem/react-flow/StickyNoteModal/StickyNoteModal.tsx
+++ b/src/cmem/react-flow/StickyNoteModal/StickyNoteModal.tsx
@@ -40,7 +40,7 @@ export interface StickyNoteModalProps {
/**
* Forward other properties to the `SimpleModal` element that is used for this dialog.
*/
- simpleDialogProps?: Omit;
+ simpleDialogProps?: Omit;
/**
* Code editor props
*/
@@ -118,7 +118,6 @@ export const StickyNoteModal: React.FC = React.memo(
,
]}
{...simpleDialogProps}
- data-test-id={(simpleDialogProps ?? {})["data-test-id"] ?? "sticky-note-modal"} // @deprecated (v25) we remove this automatically set testid
>
* {
diff --git a/src/cmem/react-flow/_edges.scss b/src/cmem/react-flow/_edges.scss
index 3ba6db29e..731ca3939 100644
--- a/src/cmem/react-flow/_edges.scss
+++ b/src/cmem/react-flow/_edges.scss
@@ -1,24 +1,24 @@
-@mixin edgetypestyles($type, $color) {
+@mixin edgetypestyles($type) {
.react-flow__edge-#{$type} {
- @include edgecoloring($color);
+ @include edgecoloring($type);
}
}
-@mixin edgecoloring($color) {
- --#{$eccgui}-reactflow-node-color-default: #{$color};
- --#{$eccgui}-reactflow-node-color-hover: #{$color};
- --#{$eccgui}-reactflow-node-color-selected: #{$color};
+@mixin edgecoloring($type) {
+ --#{$eccgui}-reactflow-node-color-default: var(--#{$eccgui}-#{$type}-edge);
+ --#{$eccgui}-reactflow-node-color-hover: var(--#{$eccgui}-#{$type}-edge);
+ --#{$eccgui}-reactflow-node-color-selected: var(--#{$eccgui}-#{$type}-edge);
}
// Graph edge types
-@include edgetypestyles("implicit", $reactflow-color-implicit-edge);
-@include edgetypestyles("import", $reactflow-color-import-edge);
-@include edgetypestyles("subclass", $reactflow-color-subclass-edge);
-@include edgetypestyles("subproperty", $reactflow-color-subproperty-edge);
-@include edgetypestyles("rdftype", $reactflow-color-rdftype-edge);
+@include edgetypestyles("implicit");
+@include edgetypestyles("import");
+@include edgetypestyles("subclass");
+@include edgetypestyles("subproperty");
+@include edgetypestyles("rdftype");
// Linking edge types
-@include edgetypestyles("value", $reactflow-color-value-edge);
-@include edgetypestyles("score", $reactflow-color-score-edge);
+@include edgetypestyles("value");
+@include edgetypestyles("score");
diff --git a/src/cmem/react-flow/_handles.scss b/src/cmem/react-flow/_handles.scss
index 5d1f07e7d..a753b7458 100644
--- a/src/cmem/react-flow/_handles.scss
+++ b/src/cmem/react-flow/_handles.scss
@@ -1,34 +1,34 @@
-@mixin handletypestyles($type, $color) {
+@mixin handletypestyles($type) {
.react-flow__node-#{$type} {
- @include handlecoloring($color);
+ @include handlecoloring($type);
}
}
-@mixin handlecoloring($color) {
+@mixin handlecoloring($type) {
.react-flow__handle {
- color: $color;
+ color: var(--#{$eccgui}-#{$type}-node);
}
}
// Graph handle types
-@include handletypestyles("graph", $reactflow-color-graph-node);
-@include handletypestyles("class", $reactflow-color-class-node);
-@include handletypestyles("instance", $reactflow-color-instance-node);
-@include handletypestyles("property", $reactflow-color-property-node);
+@include handletypestyles("graph");
+@include handletypestyles("class");
+@include handletypestyles("instance");
+@include handletypestyles("property");
// Workflow handle types
-@include handletypestyles("dataset", $reactflow-color-dataset-node);
-@include handletypestyles("linking", $reactflow-color-linking-node);
-@include handletypestyles("transform", $reactflow-color-transform-node);
-@include handletypestyles("task", $reactflow-color-task-node);
-@include handletypestyles("workflow", $reactflow-color-workflow-node);
+@include handletypestyles("dataset");
+@include handletypestyles("linking");
+@include handletypestyles("transform");
+@include handletypestyles("task");
+@include handletypestyles("workflow");
// Linking handle types
-@include handletypestyles("sourcepath", $reactflow-color-sourcepath-node);
-@include handletypestyles("targetpath", $reactflow-color-targetpath-node);
-@include handletypestyles("transformation", $reactflow-color-transformation-node);
-@include handletypestyles("comparator", $reactflow-color-comparator-node);
-@include handletypestyles("aggregator", $reactflow-color-aggregator-node);
+@include handletypestyles("sourcepath");
+@include handletypestyles("targetpath");
+@include handletypestyles("transformation");
+@include handletypestyles("comparator");
+@include handletypestyles("aggregator");
diff --git a/src/cmem/react-flow/_minimap.scss b/src/cmem/react-flow/_minimap.scss
index 4ba99c3ab..864d932b8 100644
--- a/src/cmem/react-flow/_minimap.scss
+++ b/src/cmem/react-flow/_minimap.scss
@@ -1,38 +1,48 @@
-@mixin mapnodestyles($type, $color) {
+.#{$eccgui}-graphviz__minimap__node--default {
+ &:not([fill]) {
+ fill: $reactflow-node-border-color;
+ }
+
+ &:not([stroke]) {
+ stroke: $reactflow-node-border-color;
+ }
+}
+
+@mixin mapnodestyles($type) {
.#{$eccgui}-graphviz__minimap__node--#{$type} {
- @include mapcoloring($color);
+ @include mapcoloring($type);
}
}
-@mixin mapcoloring($color) {
+@mixin mapcoloring($type) {
&:not([fill]) {
- fill: $color;
+ fill: var(--#{$eccgui}-#{$type}-node);
}
&:not([stroke]) {
- stroke: $color;
+ stroke: var(--#{$eccgui}-#{$type}-node);
}
}
// Graph node type
-@include mapnodestyles("graph", $reactflow-color-graph-node);
-@include mapnodestyles("class", $reactflow-color-class-node);
-@include mapnodestyles("instance", $reactflow-color-instance-node);
-@include mapnodestyles("property", $reactflow-color-property-node);
+@include mapnodestyles("graph");
+@include mapnodestyles("class");
+@include mapnodestyles("instance");
+@include mapnodestyles("property");
// Workflow node types
-@include mapnodestyles("dataset", $reactflow-color-dataset-node);
-@include mapnodestyles("linking", $reactflow-color-linking-node);
-@include mapnodestyles("transform", $reactflow-color-transform-node);
-@include mapnodestyles("task", $reactflow-color-task-node);
-@include mapnodestyles("workflow", $reactflow-color-workflow-node);
+@include mapnodestyles("dataset");
+@include mapnodestyles("linking");
+@include mapnodestyles("transform");
+@include mapnodestyles("task");
+@include mapnodestyles("workflow");
// Linking node types
-@include mapnodestyles("sourcepath", $reactflow-color-sourcepath-node);
-@include mapnodestyles("targetpath", $reactflow-color-targetpath-node);
-@include mapnodestyles("transformation", $reactflow-color-transformation-node);
-@include mapnodestyles("comparator", $reactflow-color-comparator-node);
-@include mapnodestyles("aggregator", $reactflow-color-aggregator-node);
+@include mapnodestyles("sourcepath");
+@include mapnodestyles("targetpath");
+@include mapnodestyles("transformation");
+@include mapnodestyles("comparator");
+@include mapnodestyles("aggregator");
diff --git a/src/cmem/react-flow/configuration/_colors-graph.scss b/src/cmem/react-flow/configuration/_colors-graph.scss
index 96816cba5..01693c8c7 100644
--- a/src/cmem/react-flow/configuration/_colors-graph.scss
+++ b/src/cmem/react-flow/configuration/_colors-graph.scss
@@ -1,37 +1,20 @@
-$reactflow-color-graph-node: #745a85 !default;
-$reactflow-color-class-node: #3a7896 !default;
-$reactflow-color-instance-node: #0097a7 !default;
-$reactflow-color-property-node: #40a691 !default;
-$reactflow-color-implicit-edge: #ae3c74 !default;
-$reactflow-color-import-edge: $reactflow-color-graph-node !default;
-$reactflow-color-subclass-edge: $reactflow-color-class-node !default;
-$reactflow-color-subproperty-edge: $reactflow-color-property-node !default;
-$reactflow-color-rdftype-edge: $reactflow-color-instance-node !default;
-
-@function bright($color) {
- @return mix($color, #fff, 24%);
-}
-
-.#{eccgui}-configuration--colors__react-flow-graph {
- /* stylelint-disable custom-property-pattern */
- // TODO: we should correct custom property names later but atm this would lead to broken consumer apps
- --graphNode: #{$reactflow-color-graph-node};
- --classNode: #{$reactflow-color-class-node};
- --instanceNode: #{$reactflow-color-instance-node};
- --propertyNode: #{$reactflow-color-property-node};
- --implicitEdge: #{$reactflow-color-implicit-edge};
- --importEdge: #{$reactflow-color-import-edge};
- --subclassEdge: #{$reactflow-color-subclass-edge};
- --subpropertyEdge: #{$reactflow-color-subproperty-edge};
- --rdftypeEdge: #{$reactflow-color-rdftype-edge};
- --graphNodeBright: #{bright($reactflow-color-graph-node)};
- --classNodeBright: #{bright($reactflow-color-class-node)};
- --instanceNodeBright: #{bright($reactflow-color-instance-node)};
- --propertyNodeBright: #{bright($reactflow-color-property-node)};
- --implicitEdgeBright: #{bright($reactflow-color-implicit-edge)};
- --importEdgeBright: #{bright($reactflow-color-import-edge)};
- --subclassEdgeBright: #{bright($reactflow-color-subclass-edge)};
- --subpropertyEdgeBright: #{bright($reactflow-color-subproperty-edge)};
- --rdftypeEdgeBright: #{bright($reactflow-color-rdftype-edge)};
- /* stylelint-enable custom-property-pattern */
+.#{$eccgui}-configuration--colors__react-flow-graph {
+ --#{$eccgui}-graph-node: #{eccgui-color-var("layout", "magenta", 900)};
+ --#{$eccgui}-graph-node-bright: #{eccgui-color-var("layout", "magenta", 100)};
+ --#{$eccgui}-class-node: #{eccgui-color-var("layout", "purple", 700)};
+ --#{$eccgui}-class-node-bright: #{eccgui-color-var("layout", "purple", 100)};
+ --#{$eccgui}-instance-node: #{eccgui-color-var("layout", "purple", 500)};
+ --#{$eccgui}-instance-node-bright: #{eccgui-color-var("layout", "purple", 100)};
+ --#{$eccgui}-property-node: #{eccgui-color-var("layout", "teal", 700)};
+ --#{$eccgui}-property-node-bright: #{eccgui-color-var("layout", "teal", 100)};
+ --#{$eccgui}-implicit-edge: #{eccgui-color-var("identity", "text", 700)};
+ --#{$eccgui}-implicit-edge-bright: #{eccgui-color-var("identity", "text", 100)};
+ --#{$eccgui}-import-edge: #{eccgui-color-var("layout", "magenta", 900)};
+ --#{$eccgui}-import-edge-bright: #{eccgui-color-var("layout", "magenta", 100)};
+ --#{$eccgui}-subclass-edge: #{eccgui-color-var("layout", "purple", 700)};
+ --#{$eccgui}-subclass-edge-bright: #{eccgui-color-var("layout", "purple", 100)};
+ --#{$eccgui}-subproperty-edge: #{eccgui-color-var("layout", "teal", 700)};
+ --#{$eccgui}-subproperty-edge-bright: #{eccgui-color-var("layout", "teal", 100)};
+ --#{$eccgui}-rdftype-edge: #{eccgui-color-var("layout", "purple", 500)};
+ --#{$eccgui}-rdftype-edge-bright: #{eccgui-color-var("layout", "purple", 100)};
}
diff --git a/src/cmem/react-flow/configuration/_colors-linking.scss b/src/cmem/react-flow/configuration/_colors-linking.scss
index bc2e119e6..c9e47d428 100644
--- a/src/cmem/react-flow/configuration/_colors-linking.scss
+++ b/src/cmem/react-flow/configuration/_colors-linking.scss
@@ -1,28 +1,16 @@
-$reactflow-color-sourcepath-node: #745a85 !default;
-$reactflow-color-targetpath-node: #3a7896 !default;
-$reactflow-color-transformation-node: #ae3c74 !default;
-$reactflow-color-comparator-node: #40a691 !default;
-$reactflow-color-aggregator-node: #0097a7 !default;
-$reactflow-color-value-edge: #222 !default;
-$reactflow-color-score-edge: $reactflow-color-aggregator-node !default;
-
-@function bright($color) {
- @return mix($color, #fff, 24%);
-}
-
.#{eccgui}-configuration--colors__react-flow-linking {
- --sourcepathNode: #{$reactflow-color-sourcepath-node};
- --targetpathNode: #{$reactflow-color-targetpath-node};
- --transformationNode: #{$reactflow-color-transformation-node};
- --comparatorNode: #{$reactflow-color-comparator-node};
- --aggregatorNode: #{$reactflow-color-aggregator-node};
- --valueEdge: #{$reactflow-color-value-edge};
- --scoreEdge: #{$reactflow-color-score-edge};
- --sourcepathNodeBright: #{bright($reactflow-color-sourcepath-node)};
- --targetpathNodeBright: #{bright($reactflow-color-targetpath-node)};
- --transformationNodeBright: #{bright($reactflow-color-transformation-node)};
- --comparatorNodeBright: #{bright($reactflow-color-comparator-node)};
- --aggregatorNodeBright: #{bright($reactflow-color-aggregator-node)};
- --valueEdgeBright: #{bright($reactflow-color-value-edge)};
- --scoreEdgeBright: #{bright($reactflow-color-score-edge)};
+ --#{$eccgui}-sourcepath-node: #{eccgui-color-var("layout", "purple", 700)};
+ --#{$eccgui}-sourcepath-node-bright: #{eccgui-color-var("layout", "purple", 300)};
+ --#{$eccgui}-targetpath-node: #{eccgui-color-var("layout", "petrol", 700)};
+ --#{$eccgui}-targetpath-node-bright: #{eccgui-color-var("layout", "petrol", 300)};
+ --#{$eccgui}-transformation-node: #{eccgui-color-var("layout", "pink", 700)};
+ --#{$eccgui}-transformation-node-bright: #{eccgui-color-var("layout", "pink", 300)};
+ --#{$eccgui}-comparator-node: #{eccgui-color-var("layout", "teal", 700)};
+ --#{$eccgui}-comparator-node-bright: #{eccgui-color-var("layout", "teal", 300)};
+ --#{$eccgui}-aggregator-node: #{eccgui-color-var("layout", "cyan", 700)};
+ --#{$eccgui}-aggregator-node-bright: #{eccgui-color-var("layout", "cyan", 100)};
+ --#{$eccgui}-value-edge: #{eccgui-color-var("layout", "grey", 700)};
+ --#{$eccgui}-value-edge-bright: #{eccgui-color-var("layout", "grey", 300)};
+ --#{$eccgui}-score-edge: #{eccgui-color-var("layout", "cyan", 900)};
+ --#{$eccgui}-score-edge-bright: #{eccgui-color-var("layout", "cyan", 300)};
}
diff --git a/src/cmem/react-flow/configuration/_colors-workflow.scss b/src/cmem/react-flow/configuration/_colors-workflow.scss
index 7ef9ac1d9..52965349e 100644
--- a/src/cmem/react-flow/configuration/_colors-workflow.scss
+++ b/src/cmem/react-flow/configuration/_colors-workflow.scss
@@ -1,28 +1,16 @@
-$reactflow-color-project-node: #A5356E !default; // Cannot be part of a workflow but we have no other place atm to configure it
-$reactflow-color-dataset-node: #3a7896 !default;
-$reactflow-color-linking-node: #0097a7 !default;
-$reactflow-color-transform-node: #40a691 !default;
-$reactflow-color-task-node: #80b67b !default;
-$reactflow-color-workflow-node: #745a85 !default;
-$reactflow-color-replaceable-input: #faa854 !default;
-
-@function bright($color) {
- @return mix($color, #fff, 24%);
-}
-
-.#{eccgui}-configuration--colors__react-flow-workflow {
- --projectNode: #{$reactflow-color-project-node};
- --datasetNode: #{$reactflow-color-dataset-node};
- --linkingNode: #{$reactflow-color-linking-node};
- --transformNode: #{$reactflow-color-transform-node};
- --taskNode: #{$reactflow-color-task-node};
- --workflowNode: #{$reactflow-color-workflow-node};
- --replaceableInput: #{$reactflow-color-replaceable-input};
- --projectNodeBright: #{bright($reactflow-color-project-node)};
- --datasetNodeBright: #{bright($reactflow-color-dataset-node)};
- --linkingNodeBright: #{bright($reactflow-color-linking-node)};
- --transformNodeBright: #{bright($reactflow-color-transform-node)};
- --taskNodeBright: #{bright($reactflow-color-task-node)};
- --workflowNodeBright: #{bright($reactflow-color-workflow-node)};
- --replaceableInputBright: #{bright($reactflow-color-replaceable-input)};
+.#{$eccgui}-configuration--colors__react-flow-workflow {
+ --#{$eccgui}-project-node: #{eccgui-color-var("layout", "magenta", 700)};
+ --#{$eccgui}-project-node-bright: #{eccgui-color-var("layout", "magenta", 300)};
+ --#{$eccgui}-dataset-node: #{eccgui-color-var("layout", "petrol", 700)};
+ --#{$eccgui}-dataset-node-bright: #{eccgui-color-var("layout", "petrol", 300)};
+ --#{$eccgui}-linking-node: #{eccgui-color-var("layout", "cyan", 700)};
+ --#{$eccgui}-linking-node-bright: #{eccgui-color-var("layout", "cyan", 300)};
+ --#{$eccgui}-transform-node: #{eccgui-color-var("layout", "teal", 700)};
+ --#{$eccgui}-transform-node-bright: #{eccgui-color-var("layout", "teal", 300)};
+ --#{$eccgui}-task-node: #{eccgui-color-var("layout", "lime", 700)};
+ --#{$eccgui}-task-node-bright: #{eccgui-color-var("layout", "lime", 300)};
+ --#{$eccgui}-workflow-node: #{eccgui-color-var("layout", "purple", 700)};
+ --#{$eccgui}-workflow-node-bright: #{eccgui-color-var("layout", "purple", 300)};
+ --#{$eccgui}-replaceable-input: #{eccgui-color-var("layout", "amber", 700)};
+ --#{$eccgui}-replaceable-input-bright: #{eccgui-color-var("layout", "amber", 300)};
}
diff --git a/src/cmem/react-flow/configuration/graph.ts b/src/cmem/react-flow/configuration/graph.ts
index 47c5a9b02..e7abf6028 100644
--- a/src/cmem/react-flow/configuration/graph.ts
+++ b/src/cmem/react-flow/configuration/graph.ts
@@ -1,20 +1,22 @@
-import { EdgeDefault } from "./../../../extensions/react-flow/edges/EdgeDefault";
+import { EdgeBezier } from "./../../../extensions/react-flow/edges/EdgeBezier";
import { NodeDefault } from "./../../../extensions/react-flow/nodes/NodeDefault";
import { GRAPH_NODE_TYPES } from "./typing";
+//import {ComponentType} from "react";
+//import {NodeProps} from "react-flow-renderer-lts";
const edgeTypes = {
- default: EdgeDefault,
- implicit: EdgeDefault,
- import: EdgeDefault,
- subclass: EdgeDefault,
- subproperty: EdgeDefault,
- rdftype: EdgeDefault,
- success: EdgeDefault,
- warning: EdgeDefault,
- danger: EdgeDefault,
+ default: EdgeBezier,
+ implicit: EdgeBezier,
+ import: EdgeBezier,
+ subclass: EdgeBezier,
+ subproperty: EdgeBezier,
+ rdftype: EdgeBezier,
+ success: EdgeBezier,
+ warning: EdgeBezier,
+ danger: EdgeBezier,
};
-const nodeTypes: Record = {
+const nodeTypes: Record*/> = {
default: NodeDefault,
graph: NodeDefault,
class: NodeDefault,
diff --git a/src/cmem/react-flow/configuration/linking.ts b/src/cmem/react-flow/configuration/linking.ts
index 0f29571b8..4a8326a78 100644
--- a/src/cmem/react-flow/configuration/linking.ts
+++ b/src/cmem/react-flow/configuration/linking.ts
@@ -2,6 +2,8 @@ import { EdgeStep } from "./../../../extensions/react-flow/edges/EdgeStep";
import { NodeDefault } from "./../../../extensions/react-flow/nodes/NodeDefault";
import { StickyNoteNode } from "./../nodes/StickyNoteNode";
import { LINKING_NODE_TYPES } from "./typing";
+//import {ComponentType} from "react";
+//import {NodeProps} from "react-flow-renderer-lts";
const edgeTypes = {
default: EdgeStep,
@@ -12,7 +14,7 @@ const edgeTypes = {
danger: EdgeStep,
};
-const nodeTypes: Record = {
+const nodeTypes: Record*/> = {
default: NodeDefault,
sourcepath: NodeDefault,
targetpath: NodeDefault,
diff --git a/src/cmem/react-flow/configuration/unspecified.ts b/src/cmem/react-flow/configuration/unspecified.ts
index 28ae0c019..0d7774937 100644
--- a/src/cmem/react-flow/configuration/unspecified.ts
+++ b/src/cmem/react-flow/configuration/unspecified.ts
@@ -1,10 +1,11 @@
import { EdgeDefault } from "./../../../extensions/react-flow/edges/EdgeDefault";
import { EdgeStep } from "./../../../extensions/react-flow/edges/EdgeStep";
+import { EdgeStraight } from "./../../../extensions/react-flow/edges/EdgeStraight";
import { NodeDefault } from "./../../../extensions/react-flow/nodes/NodeDefault";
export const edgeTypes = {
default: EdgeDefault,
- straight: EdgeDefault,
+ straight: EdgeStraight,
step: EdgeStep,
};
diff --git a/src/cmem/react-flow/configuration/workflow.ts b/src/cmem/react-flow/configuration/workflow.ts
index 946376290..5a8621a89 100644
--- a/src/cmem/react-flow/configuration/workflow.ts
+++ b/src/cmem/react-flow/configuration/workflow.ts
@@ -2,6 +2,8 @@ import { EdgeStep } from "./../../../extensions/react-flow/edges/EdgeStep";
import { NodeDefault } from "./../../../extensions/react-flow/nodes/NodeDefault";
import { StickyNoteNode } from "./../nodes/StickyNoteNode";
import { WORKFLOW_NODE_TYPES } from "./typing";
+//import {ComponentType} from "react";
+//import {NodeProps} from "react-flow-renderer-lts";
const edgeTypes = {
default: EdgeStep,
@@ -10,7 +12,7 @@ const edgeTypes = {
danger: EdgeStep,
};
-const nodeTypes: Record = {
+const nodeTypes: Record*/> = {
default: NodeDefault,
dataset: NodeDefault,
linking: NodeDefault,
diff --git a/src/cmem/react-flow/extensions/scrollOnDragHook.ts b/src/cmem/react-flow/extensions/scrollOnDragHook.ts
index 9bbb01cf0..60ccedfd5 100644
--- a/src/cmem/react-flow/extensions/scrollOnDragHook.ts
+++ b/src/cmem/react-flow/extensions/scrollOnDragHook.ts
@@ -9,29 +9,15 @@ import {
Transform,
} from "react-flow-renderer/dist/types";
-import { ReactFlowProps } from "../ReactFlow/ReactFlow";
+import { ReactFlowExtendedScrollProps } from "../ReactFlow/ReactFlow";
+import { ReactFlowV9ContainerProps } from "../ReactFlow/ReactFlowV9";
-interface IProps {
+interface IProps extends ReactFlowExtendedScrollProps {
/** The original react-flow props. */
- reactFlowProps: ReactFlowProps;
- /** If defined the canvas scrolls on all drag operations (node, selection, edge connect)
- * when the mouse pointer comes near the canvas borders or goes beyond them.
- * The `id` property of the ReactFlow component must be set in order for this to work. */
- scrollOnDrag?: {
- /** Time in milliseconds to wait before the canvas scrolls the next step. */
- scrollInterval: number;
-
- /**
- * The size of each scroll step.
- * This should be a number between 0.0 - 1.0.
- * E.g. a value of 0.25 will lead to a scroll step size of a quarter of the visible canvas. */
- scrollStepSize: number;
- };
+ reactFlowProps: ReactFlowV9ContainerProps;
}
-interface ScrollState {
- // The react-flow instance
- reactFlowInstance?: OnLoadParams;
+export interface ScrollStateShared {
// The current x position of the react-flow view
currentX: number;
// The current y position of the react-flow view
@@ -50,8 +36,13 @@ interface ScrollState {
draggingOperationActive: boolean;
}
+interface ScrollState extends ScrollStateShared {
+ // The react-flow instance
+ reactFlowInstance?: OnLoadParams;
+}
+
type ReturnType = Pick<
- ReactFlowProps,
+ ReactFlowV9ContainerProps,
| "onLoad"
| "onNodeDragStart"
| "onNodeDragStop"
@@ -65,7 +56,7 @@ type ReturnType = Pick<
/** Handles the scrolling of the react-flow canvas on all drag operations when the mouse pointer gets near or over the borders.
* The return value contains the wrapped react-flow callback functions that need to be handed over to the react-flow component. */
-export const useReactFlowScrollOnDrag = ({ reactFlowProps, scrollOnDrag }: IProps): ReturnType => {
+export const useReactFlowScrollOnDragV9 = ({ reactFlowProps, scrollOnDrag }: IProps): ReturnType => {
/** Tracks the zoom on drag to border functionality. */
const scrollState = React.useRef({
reactFlowInstance: undefined,
@@ -83,6 +74,7 @@ export const useReactFlowScrollOnDrag = ({ reactFlowProps, scrollOnDrag }: IProp
return useStoreState((state) => state.transform);
} catch (ex) {
if (reactFlowProps.id && scrollOnDrag) {
+ // eslint-disable-next-line no-console
console.warn("Scroll on drag is not correctly working. Reason: " + ex);
}
return [0, 0, 1];
@@ -139,6 +131,7 @@ export const useReactFlowScrollOnDrag = ({ reactFlowProps, scrollOnDrag }: IProp
const canvasElement = document.getElementById(reactFlowInstanceId);
if (!canvasElement) {
if (!state.loggedWarning) {
+ // eslint-disable-next-line no-console
console.warn("No element found with ID " + reactFlowInstanceId);
state.loggedWarning = true;
}
@@ -286,3 +279,8 @@ export const useReactFlowScrollOnDrag = ({ reactFlowProps, scrollOnDrag }: IProp
};
}
};
+
+/**
+ * @deprecated (v26) Currently it ony supports ReactFlow v9. Better to `useReactFlowScrollOnDragV9` for now.
+ */
+export const useReactFlowScrollOnDrag = useReactFlowScrollOnDragV9;
diff --git a/src/cmem/react-flow/index.ts b/src/cmem/react-flow/index.ts
index 21ebd12f6..67eeb1b91 100644
--- a/src/cmem/react-flow/index.ts
+++ b/src/cmem/react-flow/index.ts
@@ -1,3 +1,4 @@
export * from "./ReactFlow/ReactFlow";
export * from "./StickyNoteModal/StickyNoteModal";
-export * from "./extensions/scrollOnDragHook";
+export { useReactFlowScrollOnDragV9, useReactFlowScrollOnDrag } from "./extensions/scrollOnDragHook";
+export * from "./extensions/ReactFlowHotkeyContext";
diff --git a/src/cmem/react-flow/nodes/_colors.scss b/src/cmem/react-flow/nodes/_colors.scss
index 60a1f5c07..e5d1950f6 100644
--- a/src/cmem/react-flow/nodes/_colors.scss
+++ b/src/cmem/react-flow/nodes/_colors.scss
@@ -1,17 +1,17 @@
-@mixin nodetypestyles($type, $color) {
+@mixin nodetypestyles($type) {
.react-flow__node-#{$type} {
- @include nodecoloring($color);
+ @include nodecoloring($type);
}
}
-@mixin nodecoloring($color) {
+@mixin nodecoloring($type) {
.#{$eccgui}-graphviz__node {
- background-color: mix($color, #fff, 24%);
- border-color: $color;
+ background-color: var(--#{$eccgui}-#{$type}-node-bright);
+ border-color: var(--#{$eccgui}-#{$type}-node);
}
.#{$eccgui}-graphviz__node__extension--expanded {
&.#{$eccgui}-graphviz__node__extension--slideout {
- border-color: $color;
+ border-color: var(--#{$eccgui}-#{$type}-node);
}
}
}
@@ -19,7 +19,7 @@
// Graph node types
.react-flow__node-graph {
- @include nodecoloring($reactflow-color-graph-node);
+ @include nodecoloring("graph");
.#{$eccgui}-graphviz__node {
border-style: double;
border-width: 3 * $reactflow-node-border-width;
@@ -34,11 +34,11 @@
}
}
-@include nodetypestyles("class", $reactflow-color-class-node);
-@include nodetypestyles("instance", $reactflow-color-instance-node);
+@include nodetypestyles("class");
+@include nodetypestyles("instance");
.react-flow__node-property {
- @include nodecoloring($reactflow-color-property-node);
+ @include nodecoloring("property");
.#{$eccgui}-graphviz__node {
border-style: dashed;
}
@@ -51,16 +51,16 @@
// Workflow node types
-@include nodetypestyles("dataset", $reactflow-color-dataset-node);
-@include nodetypestyles("linking", $reactflow-color-linking-node);
-@include nodetypestyles("transform", $reactflow-color-transform-node);
-@include nodetypestyles("task", $reactflow-color-task-node);
-@include nodetypestyles("workflow", $reactflow-color-workflow-node);
+@include nodetypestyles("dataset");
+@include nodetypestyles("linking");
+@include nodetypestyles("transform");
+@include nodetypestyles("task");
+@include nodetypestyles("workflow");
// Linking node types
-@include nodetypestyles("sourcepath", $reactflow-color-sourcepath-node);
-@include nodetypestyles("targetpath", $reactflow-color-targetpath-node);
-@include nodetypestyles("transformation", $reactflow-color-transformation-node);
-@include nodetypestyles("comparator", $reactflow-color-comparator-node);
-@include nodetypestyles("aggregator", $reactflow-color-aggregator-node);
+@include nodetypestyles("sourcepath");
+@include nodetypestyles("targetpath");
+@include nodetypestyles("transformation");
+@include nodetypestyles("comparator");
+@include nodetypestyles("aggregator");
diff --git a/src/common/index.ts b/src/common/index.ts
index 39f8af464..ab989fa3a 100644
--- a/src/common/index.ts
+++ b/src/common/index.ts
@@ -1,17 +1,28 @@
+import { decode } from "he";
+
import { invisibleZeroWidthCharacters } from "./utils/characters";
+import { colorCalculateDistance } from "./utils/colorCalculateDistance";
import decideContrastColorValue from "./utils/colorDecideContrastvalue";
+import { getEnabledColorsFromPalette, textToColorHash } from "./utils/colorHash";
import getColorConfiguration from "./utils/getColorConfiguration";
import { getScrollParent } from "./utils/getScrollParent";
import { getGlobalVar, setGlobalVar } from "./utils/globalVars";
import { openInNewTab } from "./utils/openInNewTab";
+import { reduceToText } from "./utils/reduceToText";
+export type { DecodeOptions as DecodeHtmlEntitiesOptions } from "he";
export type { IntentTypes as IntentBaseTypes } from "./Intent";
export const utils = {
openInNewTab,
decideContrastColorValue,
+ colorCalculateDistance,
getColorConfiguration,
invisibleZeroWidthCharacters,
getGlobalVar,
setGlobalVar,
getScrollParent,
+ getEnabledColorsFromPalette,
+ textToColorHash,
+ reduceToText,
+ decodeHtmlEntities: decode,
};
diff --git a/src/common/scss/_color-functions.scss b/src/common/scss/_color-functions.scss
new file mode 100644
index 000000000..e4d088092
--- /dev/null
+++ b/src/common/scss/_color-functions.scss
@@ -0,0 +1,144 @@
+@use "sass:list";
+@use "sass:color";
+@use "sass:math";
+@use "sass:meta";
+
+/**
+ * Always provide a list of 5 color tints.
+ * If the list do not provide 5 colors then create them based on the first and last color in the list.
+ */
+@function eccgui-create-color-tints($colorset) {
+ $colorset-steps: 5; // number of tints
+ $count-colors: list.length($colorset);
+
+ @if $count-colors == $colorset-steps {
+ @return $colorset;
+ }
+
+ @if $count-colors < 1 {
+ @error "Need at least 1 color to create color tints.";
+ }
+
+ // we asume that it correct to give only start and end of tint weights
+ // only echo debug message if we have a 1, 3 or 4 color values
+ @if $count-colors != 2 {
+ @debug "Got only #{$count-colors} tints: #{$colorset}";
+ }
+
+ $color-tint-start: rgb(
+ color.red(list.nth($colorset, 1)),
+ color.green(list.nth($colorset, 1)),
+ color.blue(list.nth($colorset, 1))
+ );
+ $color-tint-end: rgb(
+ color.red(list.nth($colorset, -1)),
+ color.green(list.nth($colorset, -1)),
+ color.blue(list.nth($colorset, -1))
+ );
+ $colorset-fallback: $color-tint-start;
+
+ @for $i from 2 to $colorset-steps {
+ $tint-step: color.mix($color-tint-end, $color-tint-start, 100% * math.div($i - 1, $colorset-steps - 1));
+ $colorset-fallback: list.append(
+ $colorset-fallback,
+ rgb(color.red($tint-step), color.green($tint-step), color.blue($tint-step))
+ );
+
+ // @debug("mix #{$color-tint-start} with #{$color-tint-end} by #{math.div($i - 1, $colorset-steps - 1)} -> #{rgb(color.red($tint-step), color.green($tint-step), color.blue($tint-step))}")
+ }
+
+ $colorset-fallback: list.append($colorset-fallback, $color-tint-end);
+
+ @if $count-colors != 2 {
+ @debug "Create fallback with #{$colorset-steps} tints: #{$colorset-fallback}";
+ }
+
+ @return $colorset-fallback;
+}
+
+/**
+ * Create name for custom property.
+ */
+@function eccgui-color-name($group_or_name, $tint: null, $weight: null) {
+ @if $group_or_name and $tint and $weight {
+ @return "--#{$eccgui}-color-palette-#{$group_or_name}-#{$tint}-#{$weight}";
+ } @else {
+ @return "--#{$eccgui}-color-#{$group_or_name}";
+ }
+}
+
+/**
+ * Create custom property for palette color.
+ */
+@function eccgui-color-var($group_or_name, $tint: null, $weight: null) {
+ @return var(#{eccgui-color-name($group_or_name, $tint, $weight)});
+}
+
+/**
+ * Wraps the CSS color-mix function to control the color space on only one place.
+ */
+@function eccgui-color-mix($color1, $color2) {
+ @return color-mix(in srgb, $color1, $color2);
+}
+
+/**
+ * Similar to SCSS function rgba($color, $alpha).
+ * Created to replace them easily for CSS custom properties.
+ */
+@function eccgui-color-rgba($color, $alpha) {
+ @if meta.type-of($alpha) != "number" {
+ // in case it is for example a CSS custom property
+ @return eccgui-color-mix($color $alpha, transparent);
+ }
+
+ @if $alpha > 0 {
+ @return eccgui-color-mix($color 100% * $alpha, transparent);
+ } @else {
+ // workaround: we need to prevent `0%` because it will reduced to `0` by some CSS minifiers and leads to invalid color-mix values
+ @return eccgui-color-mix($color, transparent 100%);
+ }
+}
+
+$debug-rgba-values: "yes";
+
+/**
+ * Split between rgba(red, green, blue, alpha) and rgba(color, alpha).
+ */
+@function rgba($r, $g, $b: "undefined", $a: 1) {
+ // check if old notation is used
+ @if meta.variable-exists("r") and meta.variable-exists("g") and $b == "undefined" {
+ // rgba(color, alpha) was used
+ // forward to our color check splitter
+ @return rgba-extended($r, $g);
+ } @else {
+ // rgba(r, g, b, a) is used -> rgb(r g b / a)
+ // @see https://developer.mozilla.org/de/docs/Web/CSS/color_value/rgb
+ $color-new-notation: rgb(#{$r} #{$g} #{$b} / #{$a});
+
+ @return $color-new-notation;
+ }
+}
+
+/**
+ * Overwrite SCSS built-in rgba function to support colors by custom properties and CSS color methods.
+ * TODO: we need to check if this is future proof, maybe this bahaviour is not planned by Dart Sass library.
+ */
+@function rgba-extended($color, $alpha) {
+ @if meta.type-of($color) == "color" {
+ // value is SASS color value, we use SASS color functionality
+ $alphacolor: color.change($color, $alpha: $alpha);
+
+ @if $color == transparent {
+ $alphacolor: transparent;
+ }
+
+ @if $debug-rgba-values == "yes" {
+ @warn "Color value $color is not defined by CSS custom property: rgba(#{$color}, #{$alpha}) -> #{$alphacolor}";
+ }
+
+ @return $alphacolor;
+ } @else {
+ // value is not a SASS color value, we use CSS color method
+ @return eccgui-color-rgba($color, $alpha);
+ }
+}
diff --git a/src/common/utils/CssCustomProperties.ts b/src/common/utils/CssCustomProperties.ts
index ec9495c1d..598dda86b 100644
--- a/src/common/utils/CssCustomProperties.ts
+++ b/src/common/utils/CssCustomProperties.ts
@@ -6,13 +6,14 @@
type AllowedCSSRule = CSSStyleRule | CSSPageRule; // they have necessary `selectorText` and `style` properties
interface getLocalCssStyleRulesProps {
- cssRuleType?: "CSSStyleRule" | "CSSPageRule";
+ cssRuleType?: "CSSStyleRule";
selectorText?: string;
}
interface getLocalCssStyleRulePropertiesProps extends getLocalCssStyleRulesProps {
propertyType?: "all" | "normal" | "custom";
}
interface getCustomPropertiesProps extends getLocalCssStyleRulesProps {
+ filterName?: (name: string) => boolean;
removeDashPrefix?: boolean;
returnObject?: boolean;
}
@@ -27,7 +28,7 @@ export default class CssCustomProperties {
// Methods
- customProperties = (props: getCustomPropertiesProps = {}) => {
+ customProperties = (props: getCustomPropertiesProps = {}): string[][] | Record => {
// FIXME:
// in case of performance issues results should get saved at least into intern variables
// other cache strategies could be also tested
@@ -64,7 +65,7 @@ export default class CssCustomProperties {
.flat();
};
- static listLocalCssStyleRules = (filter: getLocalCssStyleRulesProps = {}): AllowedCSSRule[] => {
+ static listLocalCssStyleRules = (filter: getLocalCssStyleRulesProps = {}): CSSStyleRule[] => {
const { cssRuleType = "CSSStyleRule", selectorText } = filter;
const cssStyleRules = CssCustomProperties.listLocalCssRules().filter((rule) => {
const cssrule = rule as AllowedCSSRule;
@@ -80,14 +81,14 @@ export default class CssCustomProperties {
return false;
}
});
- return cssStyleRules as AllowedCSSRule[];
+ return cssStyleRules as CSSStyleRule[];
};
- static listLocalCssStyleRuleProperties = (filter: getLocalCssStyleRulePropertiesProps = {}) => {
+ static listLocalCssStyleRuleProperties = (filter: getLocalCssStyleRulePropertiesProps = {}): string[][] => {
const { propertyType = "all", ...otherFilters } = filter;
return CssCustomProperties.listLocalCssStyleRules(otherFilters)
.map((cssrule) => {
- return [...(cssrule as any).style].map((propertyname) => {
+ return [...(cssrule as CSSStyleRule).style].map((propertyname) => {
return [propertyname.trim(), (cssrule as CSSStyleRule).style.getPropertyValue(propertyname).trim()];
});
})
@@ -103,19 +104,25 @@ export default class CssCustomProperties {
});
};
- static listCustomProperties = (props: getCustomPropertiesProps = {}) => {
- const { removeDashPrefix = true, returnObject = true, ...filterProps } = props;
+ static listCustomProperties = (props: getCustomPropertiesProps = {}): string[][] | Record => {
+ const { removeDashPrefix = true, returnObject = true, filterName = () => true, ...filterProps } = props;
const customProperties = CssCustomProperties.listLocalCssStyleRuleProperties({
...filterProps,
propertyType: "custom",
- }).map((declaration) => {
- if (removeDashPrefix) {
- return [declaration[0].substr(2), declaration[1]];
- }
- return declaration;
- });
+ })
+ .filter((declaration) => {
+ return filterName(declaration[0]);
+ })
+ .map((declaration) => {
+ if (removeDashPrefix) {
+ return [declaration[0].substr(2), declaration[1]];
+ }
+ return declaration;
+ });
- return returnObject ? Object.fromEntries(customProperties) : customProperties;
+ return returnObject
+ ? (Object.fromEntries(customProperties) as Record)
+ : (customProperties as string[][]);
};
}
diff --git a/src/common/utils/colorCalculateDistance.ts b/src/common/utils/colorCalculateDistance.ts
new file mode 100644
index 000000000..2dd04df27
--- /dev/null
+++ b/src/common/utils/colorCalculateDistance.ts
@@ -0,0 +1,28 @@
+import Color from "color";
+
+export type colorValue = Color | string;
+
+export interface colorCalculateDistanceProps {
+ // Color used to calculate distance to other color.
+ color1: colorValue;
+ // Other color used to calculate distance to color.
+ color2: colorValue;
+}
+
+/**
+ * Calculates the distance between 2 colors.
+ * To keep it simple the CIE76 formula is used.
+ * @see https://en.wikipedia.org/wiki/Color_difference#CIE76
+ */
+export const colorCalculateDistance = ({ color1, color2 }: colorCalculateDistanceProps): number | null => {
+ let colorDistance: number | null = null;
+ try {
+ const lab1 = Color(color1).lab();
+ const lab2 = Color(color2).lab();
+ colorDistance = ((lab1.l() - lab2.l()) ** 2 + (lab1.a() - lab2.a()) ** 2 + (lab1.b() - lab2.b()) ** 2) ** 0.5;
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.warn("Received invalid colors", { color1, color2, error });
+ }
+ return colorDistance;
+};
diff --git a/src/common/utils/colorHash.ts b/src/common/utils/colorHash.ts
new file mode 100644
index 000000000..45dab3daa
--- /dev/null
+++ b/src/common/utils/colorHash.ts
@@ -0,0 +1,195 @@
+import Color from "color";
+
+import { CLASSPREFIX as eccgui, COLORMINDISTANCE } from "../../configuration/constants";
+
+import { colorCalculateDistance } from "./colorCalculateDistance";
+import CssCustomProperties from "./CssCustomProperties";
+
+type ColorOrFalse = Color | false;
+type ColorWeight = 100 | 300 | 500 | 700 | 900;
+type PaletteGroup = "identity" | "semantic" | "layout" | "extra";
+
+interface getEnabledColorsProps {
+ /** Specify the palette groups used to define the set of colors. */
+ includePaletteGroup?: PaletteGroup[];
+ /** Use only some weights of a color tint. */
+ includeColorWeight?: ColorWeight[];
+ /** Only keep colors in the stack with a minimal color distance to all other colors. */
+ minimalColorDistance?: number;
+ /** Extend color stack by values generated by mixing tints of the same weight, e.g. `yellow100` with `purple100`. */
+ // includeMixedColors?: boolean;
+}
+
+const getEnabledColorsFromPaletteCache = new Map();
+
+export function getEnabledColorsFromPalette({
+ includePaletteGroup = ["layout"],
+ includeColorWeight = [100, 300, 500, 700, 900],
+ // TODO (planned for later): includeMixedColors = false,
+ minimalColorDistance = COLORMINDISTANCE,
+}: getEnabledColorsProps): Color[] {
+ const configId = JSON.stringify({
+ includePaletteGroup,
+ includeColorWeight,
+ });
+
+ if (getEnabledColorsFromPaletteCache.has(configId)) {
+ return getEnabledColorsFromPaletteCache.get(configId)!;
+ }
+
+ const colorsFromPalette = new CssCustomProperties({
+ selectorText: `:root`,
+ filterName: (name: string) => {
+ if (!name.includes(`--${eccgui}-color-palette-`)) {
+ // only allow custom properties created for the palette
+ return false;
+ }
+ // test for correct group and weight of the palette color
+ const tint = name.substring(`--${eccgui}-color-palette-`.length).split("-");
+ const group = tint[0] as PaletteGroup;
+ const weight = parseInt(tint[2], 10) as ColorWeight;
+ return includePaletteGroup.includes(group) && includeColorWeight.includes(weight);
+ },
+ removeDashPrefix: false,
+ returnObject: true,
+ }).customProperties();
+
+ const colorsFromPaletteValues = Object.values(colorsFromPalette) as string[];
+
+ const colorsFromPaletteWithEnoughDistance =
+ minimalColorDistance > 0
+ ? colorsFromPaletteValues.reduce((enoughDistance: string[], color: string) => {
+ if (enoughDistance.includes(color)) {
+ return enoughDistance.filter((checkColor) => {
+ const distance = colorCalculateDistance({ color1: color, color2: checkColor });
+ return checkColor === color || (distance && minimalColorDistance <= distance);
+ });
+ } else {
+ return enoughDistance;
+ }
+ }, colorsFromPaletteValues)
+ : colorsFromPaletteValues;
+
+ getEnabledColorsFromPaletteCache.set(
+ configId,
+ colorsFromPaletteWithEnoughDistance.map((color: string) => {
+ return Color(color);
+ })
+ );
+
+ return getEnabledColorsFromPaletteCache.get(configId)!;
+}
+
+function getColorcode(text: string): ColorOrFalse {
+ try {
+ return Color(text);
+ } catch {
+ return false;
+ }
+}
+
+interface textToColorOptions {
+ /** Stack of colors that are allowed to be returned. */
+ enabledColors: Color[] | "all" | getEnabledColorsProps;
+ /** Return input text if it represents a valid color string, e.g. `#000` or `black`. */
+ returnValidColorsDirectly: boolean;
+}
+
+interface textToColorProps {
+ text: string;
+ options?: textToColorOptions;
+}
+
+/**
+ * Map a text string to a color.
+ * It always returns the same color for a text as long as the options stay the same.
+ * It returns `false` in case there are no colors defined to chose from.
+ */
+export function textToColorHash({
+ text,
+ options = {
+ enabledColors: getEnabledColorsFromPalette({}),
+ returnValidColorsDirectly: false,
+ },
+}: textToColorProps): string | false {
+ let color = getColorcode(text);
+
+ if (options.returnValidColorsDirectly && color) {
+ // return color code for text because it was a valid color string
+ return color.hex().toString();
+ }
+
+ if (!color) {
+ color = getColorcode(stringToHexColorHash(text)) as Color;
+ }
+
+ if (options.enabledColors === "all" && color) {
+ // all colors are allowed as return value
+ return color.hex().toString();
+ }
+
+ let enabledColors = [] as Color[];
+
+ if (Array.isArray(options.enabledColors)) {
+ enabledColors = options.enabledColors;
+ } else {
+ enabledColors = getEnabledColorsFromPalette(options.enabledColors as getEnabledColorsProps);
+ }
+
+ if (enabledColors.length === 0) {
+ // eslint-disable-next-line no-console
+ console.warn("textToColorHash functionaliy need enabledColors list with at least 1 color.");
+ return false;
+ }
+
+ return nearestColorNeighbour(color, enabledColors as Color[])
+ .hex()
+ .toString();
+}
+
+function stringToIntegerHash(inputString: string): number {
+ /* this function is idempotend, meaning it retrieves the same result for the same input
+ no matter how many times it's called */
+ // Convert the string to a hash code
+ let hashCode = 0;
+ for (let i = 0; i < inputString.length; i++) {
+ hashCode = (hashCode << 5) - hashCode + inputString.charCodeAt(i);
+ hashCode &= hashCode; // Convert to 32bit integer
+ }
+ return hashCode;
+}
+
+function integerToHexColor(number: number): string {
+ // Convert the hash code to a positive number (32unsigned)
+ const hash = Math.abs(number + Math.pow(31, 2));
+ // Convert the number to a hex color (excluding white)
+ const hexColor = "#" + (hash % 0xffffff).toString(16).padStart(6, "0");
+ return hexColor;
+}
+
+function stringToHexColorHash(inputString: string): string {
+ const integerHash = stringToIntegerHash(inputString);
+ return integerToHexColor(integerHash);
+}
+
+function nearestColorNeighbour(color: Color, enabledColors: Color[]): Color {
+ const nearestNeighbour = enabledColors.reduce(
+ (nearestColor, enabledColorsItem) => {
+ const distance = colorCalculateDistance({
+ color1: color,
+ color2: enabledColorsItem,
+ });
+ return distance && distance < nearestColor.distance
+ ? {
+ distance,
+ color: enabledColorsItem,
+ }
+ : nearestColor;
+ },
+ {
+ distance: Number.POSITIVE_INFINITY,
+ color: enabledColors[0],
+ }
+ );
+ return nearestNeighbour.color;
+}
diff --git a/src/common/utils/getColorConfiguration.ts b/src/common/utils/getColorConfiguration.ts
index 0642d7d38..bb446d609 100644
--- a/src/common/utils/getColorConfiguration.ts
+++ b/src/common/utils/getColorConfiguration.ts
@@ -1,3 +1,5 @@
+import Color from "color";
+
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
import CssCustomProperties from "./CssCustomProperties";
@@ -5,22 +7,58 @@ import CssCustomProperties from "./CssCustomProperties";
// Configurations can be found in `src/cmem/react-flow/configuration/_colors-*.scss`
type colorconfigs = "react-flow-graph" | "react-flow-linking" | "react-flow-workflow" | "stickynotes";
-const colorConfigurationMemo = new Map();
+const colorConfigurationMemo = new Map>();
/**
* Read and returns color values provided by CSS custom properties.
* They are defined for special CSS classes.
* Currently color configurations for the react flow editors are supported.
**/
-const getColorConfiguration = (configId: colorconfigs) => {
+const getColorConfiguration = (configId: colorconfigs): Record => {
if (!colorConfigurationMemo.has(configId)) {
+ const selectorClass = `${eccgui}-configuration--colors__${configId}`;
colorConfigurationMemo.set(
configId,
- new CssCustomProperties({
- selectorText: `.${eccgui}-configuration--colors__${configId}`,
- removeDashPrefix: true,
- returnObject: true,
- }).customProperties()
+ Object.fromEntries(
+ (
+ new CssCustomProperties({
+ selectorText: `.${selectorClass}`,
+ removeDashPrefix: true,
+ returnObject: false,
+ }).customProperties() as string[][]
+ ).map((setting) => {
+ // check if the value could be a color
+
+ let testColorValue = setting[1];
+ // check if value itself is a reference to another css custom property
+ if (testColorValue.slice(0, 3) === "var") {
+ // we currently only extract the first part and ignore any fallbacks
+ const customPropertyName = /var\(\s*(--[a-zA-Z0-9_-]+)/g.exec(testColorValue);
+ if (customPropertyName && customPropertyName[1]) {
+ let selectorElement = document.getElementsByClassName(selectorClass)[0];
+ if (!selectorElement) {
+ // we need to add an empty element that the JS API can read the value of the custom prop
+ selectorElement = document.createElement("div");
+ selectorElement.classList.add(selectorClass);
+ selectorElement.setAttribute("style", "display: none");
+ document.body.appendChild(selectorElement);
+ }
+ // only check 1 time, not recursive
+ testColorValue = getComputedStyle(selectorElement).getPropertyValue(customPropertyName[1]);
+ }
+ }
+
+ try {
+ if (Color(testColorValue)) {
+ return [setting[0], testColorValue];
+ } else {
+ return [setting[0], undefined];
+ }
+ } catch {
+ return [setting[0], undefined];
+ }
+ })
+ ) as Record
);
}
return colorConfigurationMemo.get(configId)!;
diff --git a/src/common/utils/reduceToText.tsx b/src/common/utils/reduceToText.tsx
new file mode 100644
index 000000000..d929ff410
--- /dev/null
+++ b/src/common/utils/reduceToText.tsx
@@ -0,0 +1,82 @@
+import React from "react";
+import { renderToString } from "react-dom/server";
+import * as ReactIs from "react-is";
+
+import { TextReducerProps } from "./../../components/TextReducer/TextReducer";
+import { DecodeHtmlEntitiesOptions, utils } from "./../";
+
+export interface ReduceToTextFuncType {
+ (
+ /**
+ * Component or text to reduce HTML markup content to plain text.
+ */
+ input: React.ReactNode | React.ReactNode[] | string,
+ options?: Pick
+ ): string;
+}
+
+export const reduceToText: ReduceToTextFuncType = (input, options) => {
+ const { maxNodes, maxLength, decodeHtmlEntities } = options || {};
+ const content: React.ReactNode | React.ReactNode[] = input;
+ let nodeCount = 0;
+
+ const onlyText = (nodes: React.ReactNode | React.ReactNode[]): string => {
+ if (typeof maxNodes !== "undefined" && nodeCount >= maxNodes) return "";
+
+ return React.Children.toArray(nodes)
+ .slice(0, maxNodes)
+ .map((child) => {
+ if (typeof maxNodes !== "undefined" && nodeCount >= maxNodes) return "";
+
+ if (ReactIs.isFragment(child)) return onlyText(child.props?.children);
+ if (typeof child === "string" || typeof child === "number") {
+ nodeCount++;
+ return child.toString();
+ }
+ if (ReactIs.isElement(child)) {
+ nodeCount++;
+ return renderToString({child} );
+ }
+ return "";
+ })
+ .join(" ");
+ };
+
+ let text = typeof content === "string" ? content : onlyText(content);
+
+ // Basic HTML cleanup
+ text = text.replace(/<[^\s][^>]*>/g, "").replace(/\n/g, " ");
+
+ if (decodeHtmlEntities) {
+ const decodeDefaultOptions = {
+ isAttributeValue: true,
+ strict: true,
+ } as DecodeHtmlEntitiesOptions;
+ let decodeErrors = 0;
+ // we decode in pieces to apply some error tolerance even in strict mode
+ text = text
+ .split(" ")
+ .map((value) => {
+ try {
+ return utils.decodeHtmlEntities(value, {
+ ...decodeDefaultOptions,
+ ...options?.decodeHtmlEntitiesOptions,
+ });
+ } catch {
+ decodeErrors++;
+ return value;
+ }
+ })
+ .join(" ");
+ if (decodeErrors > 0) {
+ // eslint-disable-next-line no-console
+ console.warn(`${decodeErrors} parse error(s) for decodeHtmlEntities, return un-decoded text`, text);
+ }
+ }
+
+ if (typeof maxLength === "number") {
+ text = text.slice(0, maxLength);
+ }
+
+ return text.trim();
+};
diff --git a/src/components/Accordion/accordion.scss b/src/components/Accordion/accordion.scss
index 7e399ffcf..493c35778 100644
--- a/src/components/Accordion/accordion.scss
+++ b/src/components/Accordion/accordion.scss
@@ -4,12 +4,11 @@
@include accordion.accordion;
// own vars
-$eccgui-color-accordion-background-elevated: rgba($eccgui-color-accent, 0.1) !default;
+$eccgui-color-accordion-background-elevated: eccgui-color-var("identity", "accent", "100") !default;
$eccgui-color-accordion-toggler-hover: $menu-item-color-hover !default;
-$eccgui-color-accordion-toggler-elevated-hover: color.mix(
- $eccgui-color-accordion-background-elevated,
- $eccgui-color-accordion-toggler-hover,
- 50%
+$eccgui-color-accordion-toggler-elevated-hover: eccgui-color-mix(
+ #{$eccgui-color-accordion-background-elevated},
+ #{$eccgui-color-accordion-toggler-hover}
) !default;
$eccgui-size-accordion-header-baseheight: mini-units(5) !default;
$eccgui-size-accordion-content-basespace: $eccgui-size-block-whitespace * 0.5 !default;
@@ -178,6 +177,8 @@ $eccgui-size-accordion-separation: $eccgui-size-block-whitespace * 0.5 !default;
background-color: $eccgui-color-accordion-background-elevated;
.#{$prefix}--accordion__heading {
+ &:hover,
+ &:focus,
&:hover::before,
&:focus::before {
background-color: $eccgui-color-accordion-toggler-elevated-hover;
diff --git a/src/components/Application/_colors.scss b/src/components/Application/_colors.scss
new file mode 100644
index 000000000..6cd103d11
--- /dev/null
+++ b/src/components/Application/_colors.scss
@@ -0,0 +1,15 @@
+@use "sass:map";
+@use "sass:list";
+
+:root {
+ @each $palette-group-name, $palette-group-tints in $eccgui-color-palette-light {
+ @each $palette-tint-name, $palette-tint-colors in $palette-group-tints {
+ @for $i from 1 through list.length($palette-tint-colors) {
+ $css-property-name: #{eccgui-color-name($palette-group-name, $palette-tint-name, ($i * 2 - 1) * 100)};
+ $css-property-value: #{list.nth($palette-tint-colors, $i)};
+
+ #{$css-property-name}: #{$css-property-value};
+ }
+ }
+ }
+}
diff --git a/src/components/Application/_header.scss b/src/components/Application/_header.scss
index e6775dbaa..59ec6b7fa 100644
--- a/src/components/Application/_header.scss
+++ b/src/components/Application/_header.scss
@@ -14,10 +14,10 @@ $shell-header-bg-01: var(
) !default;
/// Header menu trigger hover, Header nav link hover
-$shell-header-bg-02: color-mix(in srgb, $shell-header-bg-01, black 5%) !default;
+$shell-header-bg-02: eccgui-color-mix($shell-header-bg-01, black 5%) !default;
/// Header action active background
-$shell-header-bg-03: color-mix(in srgb, $shell-header-bg-01, black 10%) !default;
+$shell-header-bg-03: eccgui-color-mix($shell-header-bg-01, black 10%) !default;
/// Header submenu link hover
$shell-header-bg-04: $shell-header-bg-02 !default;
@@ -32,10 +32,10 @@ $shell-header-bg-06: $shell-header-bg-03 !default;
$shell-header-border-01: transparent !default;
/// Header focus
-$shell-header-focus: color.adjust($eccgui-color-applicationheader-text, $lightness: 39%) !default;
+$shell-header-focus: eccgui-color-mix($eccgui-color-applicationheader-text, white 39%) !default;
/// Primary text in header, Title text
-$shell-header-text-01: color.adjust($eccgui-color-applicationheader-text, $lightness: -5%) !default;
+$shell-header-text-01: eccgui-color-mix($eccgui-color-applicationheader-text, black 5%) !default;
/// Secondary text in header, Menu item nav text
$shell-header-text-02: $eccgui-color-applicationheader-text !default;
@@ -196,12 +196,12 @@ a.#{$prefix}--header__menu-item:active {
a.#{$prefix}--header__name:focus,
a.#{$prefix}--header__menu-item:focus {
border: none;
- outline: 1px dotted color.adjust($eccgui-color-applicationheader-text, $lightness: 39%);
+ outline: 1px dotted $shell-header-focus;
outline-offset: -1px;
box-shadow: none;
}
.#{$prefix}--header__menu-title[aria-expanded="true"] {
- color: color.adjust($eccgui-color-applicationheader-text, $lightness: 39%);
+ color: $shell-header-focus;
}
// $shell-header-text-01
@@ -214,7 +214,7 @@ a.#{$prefix}--header__menu-item:active,
a.#{$prefix}--header__menu-item:focus,
.#{$prefix}--header__menu .#{$prefix}--header__menu-item:hover,
.#{$prefix}--skip-to-content:focus {
- color: color.adjust($eccgui-color-applicationheader-text, $lightness: -5%);
+ color: $shell-header-text-01;
}
// $shell-header-text-02
diff --git a/src/components/Application/_toolbar.scss b/src/components/Application/_toolbar.scss
index 932f45482..e3c01b50d 100644
--- a/src/components/Application/_toolbar.scss
+++ b/src/components/Application/_toolbar.scss
@@ -12,25 +12,25 @@
$shell-panel-bg-01: $shell-header-bg-01 !default;
/// Panel item hover background
-$shell-panel-bg-02: color-mix(in srgb, $shell-header-bg-01, black 10%) !default;
+$shell-panel-bg-02: eccgui-color-mix($shell-header-bg-01, black 10%) !default;
/// Panel item focus and active background
-$shell-panel-bg-03: color-mix(in srgb, $shell-header-bg-01, black 5%) !default;
+$shell-panel-bg-03: eccgui-color-mix($shell-header-bg-01, black 5%) !default;
/// Panel item link selected background
-$shell-panel-bg-04: color-mix(in srgb, $shell-header-bg-01, white 5%) !default;
+$shell-panel-bg-04: eccgui-color-mix($shell-header-bg-01, white 5%) !default;
/// Panel border
$shell-panel-border: $shell-panel-bg-03 !default;
/// Header panel text
-$shell-panel-text-01: color.adjust($eccgui-color-applicationheader-text, $lightness: -5%) !default;
+$shell-panel-text-01: $shell-header-text-01 !default;
/// Header panel secondary text
$shell-panel-text-02: $eccgui-color-applicationheader-text !default;
/// Header panel focus border
-$shell-panel-focus: color.adjust($eccgui-color-applicationheader-text, $lightness: 39%) !default;
+$shell-panel-focus: $shell-header-focus !default;
@import "~@carbon/react/scss/components/ui-shell/header-panel/index";
diff --git a/src/components/Application/application.scss b/src/components/Application/application.scss
index 78d1b5d45..ea0de1677 100644
--- a/src/components/Application/application.scss
+++ b/src/components/Application/application.scss
@@ -1,4 +1,5 @@
// @import 'config';
+@import "colors";
@import "header";
@import "toolbar";
diff --git a/src/components/Application/stories/Application.stories.tsx b/src/components/Application/stories/Application.stories.tsx
index e2feb5907..7e0aa6cf4 100644
--- a/src/components/Application/stories/Application.stories.tsx
+++ b/src/components/Application/stories/Application.stories.tsx
@@ -29,11 +29,11 @@ interface ApplicationBasicExampleProps {
}
function ApplicationBasicExample(args: ApplicationBasicExampleProps) {
- return <>>;
+ return args ? <>> : <>>;
}
export default {
- title: "Components/Application",
+ title: "Components/Application/Elements",
component: ApplicationBasicExample,
subcomponents: {
ApplicationContainer,
diff --git a/src/components/Application/stories/ColorPalettes.stories.tsx b/src/components/Application/stories/ColorPalettes.stories.tsx
new file mode 100644
index 000000000..ecee1e8df
--- /dev/null
+++ b/src/components/Application/stories/ColorPalettes.stories.tsx
@@ -0,0 +1,885 @@
+import React from "react";
+import { render } from "react-dom";
+import { loremIpsum } from "react-lorem-ipsum";
+import { Meta, StoryFn } from "@storybook/react";
+import Color from "color";
+
+import CssCustomProperties from "./../../../common/utils/CssCustomProperties";
+import {
+ ApplicationContainer,
+ Badge,
+ Button,
+ Checkbox,
+ CLASSPREFIX as eccgui,
+ COLORMINCONTRAST,
+ COLORMINDISTANCE,
+ ContextMenu,
+ FieldItem,
+ FieldItemRow,
+ FieldSet,
+ FlexibleLayoutContainer,
+ FlexibleLayoutItem,
+ IconButton,
+ MenuItem,
+ Section,
+ SectionHeader,
+ Spacing,
+ Switch,
+ Tabs,
+ TabTitle,
+ Tag,
+ TagList,
+ TextField,
+ TitleSubsection,
+ utils,
+} from "./../../../index";
+
+interface ColorPaletteConfiguratorProps {
+ /** Color palette as custom CSS properties */
+ customColorProperties?: string;
+ /** Default value for minimal color distance */
+ distanceMin?: number;
+ /** Default value for minimal contrast */
+ contrastMin?: number;
+ /** Enable color checks by default */
+ enableCalculations?: boolean;
+}
+
+const ColorPaletteConfigurator = ({
+ customColorProperties,
+ distanceMin = COLORMINDISTANCE, // @see https://wisotop.de/farbabstand-farben-vergleichen.php
+ contrastMin = COLORMINCONTRAST,
+ enableCalculations = false,
+}: ColorPaletteConfiguratorProps) => {
+ const palettePrefix = `--${eccgui}-color-palette-`;
+ const userInputDelayTime = 500;
+ const correctionStep = 0.01;
+ let userInputDelay; // timeout id
+ const refConfigurator = React.useRef(null);
+ const [calculateDistanceWarnings, setCalculateDistanceWarnings] = React.useState(enableCalculations);
+ const [calculateContrastWarnings, setCalculateContrastWarnings] = React.useState(enableCalculations);
+ const [minimalDistance, setMinimalDistance] = React.useState(distanceMin);
+ const [minimalContrast, setMinimalContrast] = React.useState(contrastMin);
+ const [paletteData, setPaletteData] = React.useState(undefined);
+ const [hashtestGroups, setHashtestGroups] = React.useState(["layout"]);
+ const [hashtestWeights, setHashtestWeights] = React.useState(["100", "300", "500", "700", "900"]);
+ const userPaletteRef = React.useRef(null);
+
+ const createPaletteData = (csscustomprops: string | undefined) => {
+ const colors = (
+ csscustomprops
+ ? csscustomprops.split(";").map((rule: string) => {
+ return rule.split(":").map((rulepart: string) => {
+ return rulepart.trim();
+ });
+ })
+ : new CssCustomProperties({
+ selectorText: `:root`,
+ filterName: (name: string) => {
+ return name.includes(palettePrefix);
+ },
+ removeDashPrefix: false,
+ returnObject: false,
+ }).customProperties()
+ )
+ .filter((colorconfig: object) => {
+ if (!Array.isArray(colorconfig)) {
+ return false;
+ }
+ if (colorconfig.length !== 2) {
+ return false;
+ }
+ return true;
+ })
+ .map((colorconfig: object) => {
+ return [colorconfig[0].replace(palettePrefix, ""), Color(colorconfig[1]).rgb()];
+ });
+
+ const data = new Object();
+
+ for (const [key, value] of colors) {
+ const hierarchy = key.split("-");
+ if (!data[hierarchy[0]]) {
+ data[hierarchy[0]] = new Object();
+ }
+ if (!data[hierarchy[0]][hierarchy[1]]) {
+ data[hierarchy[0]][hierarchy[1]] = new Object();
+ }
+ if (!data[hierarchy[0]][hierarchy[1]][hierarchy[2]]) {
+ data[hierarchy[0]][hierarchy[1]][hierarchy[2]] = value;
+ }
+ }
+
+ return data;
+ };
+
+ const createSimpleColorList = (data: object, checkColorDistance: boolean) => {
+ let colorlist = [] as Color[];
+ for (const [group, tints] of Object.entries(data)) {
+ if (hashtestGroups.includes(group)) {
+ for (const [, weights] of Object.entries(tints as object)) {
+ for (const [weight, value] of Object.entries(weights)) {
+ if (hashtestWeights.includes(weight)) {
+ colorlist.push(value as Color);
+ }
+ }
+ }
+ }
+ }
+
+ if (checkColorDistance) {
+ colorlist = colorlist.reduce((enoughDistance: Color[], color: Color) => {
+ if (enoughDistance.includes(color)) {
+ return enoughDistance.filter((checkColor) => {
+ const distance = utils.colorCalculateDistance({ color1: color, color2: checkColor });
+ return checkColor === color || (distance && distanceMin <= distance);
+ });
+ } else {
+ return enoughDistance;
+ }
+ }, colorlist);
+ }
+
+ return colorlist;
+ };
+
+ const createCustomPropsSerialization = (data: object) => {
+ let serialization = "";
+ for (const [group, tints] of Object.entries(data)) {
+ for (const [tint, weights] of Object.entries(tints as object)) {
+ for (const [weight, value] of Object.entries(weights)) {
+ serialization =
+ serialization +
+ `--${eccgui}-color-palette-${group}-${tint}-${weight}: ${(value as Color).hex()};\n`;
+ }
+ }
+ }
+ return serialization.trim();
+ };
+
+ const createSassSerialization = (data: object) => {
+ const createTintData = (tint: string, weights: object) => {
+ return `\t\t"${tint}": eccgui-create-color-tints(${Object.values(weights)
+ .map((color) => color.hex().toLowerCase())
+ .join(" ")}),\n`;
+ };
+
+ const createGroupData = (group: string, tints: object) => {
+ let groupData = `\t"${group}": (\n`;
+ for (const [tint, weights] of Object.entries(tints)) {
+ groupData = groupData + createTintData(tint, weights);
+ }
+ return (groupData + `\t),\n`).replaceAll("\t", " ");
+ };
+
+ let sassData = `$eccgui-color-palette-light: (\n`;
+
+ for (const [group, tints] of Object.entries(data)) {
+ sassData = sassData + createGroupData(group, tints);
+ }
+
+ return sassData + `) !default;`;
+ };
+
+ React.useEffect(() => {
+ if (refConfigurator.current) {
+ const panelConfig = document.getElementById("bp5-tab-panel_colorconfig_editor");
+ if (panelConfig) {
+ const warnings = Array.from(panelConfig.getElementsByClassName("eccgui-badge"))
+ .map((warning: Element) => {
+ return (warning as HTMLElement).textContent;
+ })
+ .reduce((partial, value) => {
+ return partial + parseInt(value ?? "");
+ }, 0 as number);
+ const warningsTarget = document.getElementById("sumWarnings");
+ if (warningsTarget) {
+ if (warnings > 0) {
+ render({warnings} , warningsTarget);
+ } else {
+ render(<>>, warningsTarget);
+ }
+ }
+ }
+ }
+ });
+
+ React.useEffect(() => {
+ const paletteData = createPaletteData(customColorProperties);
+ setPaletteData(paletteData);
+ }, [customColorProperties]);
+
+ React.useEffect(() => {
+ if (userPaletteRef && userPaletteRef.current) {
+ userPaletteRef.current.value = createCustomPropsSerialization(paletteData || {});
+ }
+ }, [paletteData]);
+
+ const updateHashtestGroups = (group: string, active: boolean) => {
+ let updatedGroups;
+ if (active) {
+ updatedGroups = [...hashtestGroups, group];
+ } else {
+ updatedGroups = hashtestGroups.filter((value) => value !== group);
+ }
+ setHashtestGroups(updatedGroups);
+ };
+
+ const updateHashtestWeights = (weight: string, active: boolean) => {
+ let updatedWeights;
+ if (active) {
+ updatedWeights = [...hashtestWeights, weight];
+ } else {
+ updatedWeights = hashtestWeights.filter((value) => value !== weight);
+ }
+ setHashtestWeights(updatedWeights);
+ };
+
+ const fixColorByLuminosity = (
+ color: Color,
+ colorTest: Color,
+ testFn: (color1: Color, color2: Color) => boolean
+ ) => {
+ let fixedColor = color as Color;
+ let check = testFn(fixedColor, colorTest);
+ while (check === true && fixedColor.luminosity() > 0 && fixedColor.luminosity() < 1) {
+ if (fixedColor.luminosity() < (colorTest as Color).luminosity()) {
+ fixedColor = fixedColor.darken(correctionStep);
+ } else {
+ fixedColor = fixedColor.lighten(correctionStep);
+ }
+ check = testFn(fixedColor, colorTest);
+ }
+
+ return fixedColor;
+ };
+
+ const createWarnings = (id: string[], colors: object) => {
+ if (
+ (!calculateDistanceWarnings && !calculateContrastWarnings) ||
+ !colors[id[0]] ||
+ !colors[id[0]][id[1]] ||
+ !colors[id[0]][id[1]][id[2]]
+ ) {
+ return undefined;
+ }
+ const color = colors[id[0]][id[1]][id[2]];
+ const warningsDistance: React.ReactElement[] = [];
+ const warningsContrast: React.ReactElement[] = [];
+ for (const [group, tints] of Object.entries(colors)) {
+ for (const [tint, weights] of Object.entries(tints as object)) {
+ for (const [weight, value] of Object.entries(weights)) {
+ if (color.hex().toString() !== (value as Color).hex().toString()) {
+ if (calculateDistanceWarnings) {
+ // color distance
+ const distance = utils.colorCalculateDistance({ color1: color, color2: value as Color });
+ if (distance && distance < minimalDistance) {
+ warningsDistance.push(
+
+ Fix with{" "}
+ {tint + weight} (
+ {distance.toPrecision(2)})
+ >
+ }
+ >
+
+ Fix{" "}
+
+ {`${id[1]}}${id[2]}}`}
+
+ >
+ }
+ onClick={() => {
+ colors[id[0]][id[1]][id[2]] = fixColorByLuminosity(
+ color,
+ value as Color,
+ (c1, c2) => {
+ const distance =
+ utils.colorCalculateDistance({ color1: c1, color2: c2 }) ??
+ 0;
+ // eslint-disable-next-line no-console
+ console.log(`${c1.hex()} -> ${distance}`);
+ return distance < minimalDistance;
+ }
+ );
+ setPaletteData({ ...colors });
+ }}
+ />
+
+ Fix{" "}
+
+ {`${tint}${weight}`}
+
+ >
+ }
+ onClick={() => {
+ colors[group][tint][weight] = fixColorByLuminosity(
+ value as Color,
+ color,
+ (c1, c2) => {
+ const distance =
+ utils.colorCalculateDistance({ color1: c1, color2: c2 }) ??
+ 0;
+ // eslint-disable-next-line no-console
+ console.log(`${c1.hex()} -> ${distance}`);
+ return distance < minimalDistance;
+ }
+ );
+ setPaletteData({ ...colors });
+ }}
+ />
+
+ );
+ }
+ }
+ if (calculateContrastWarnings) {
+ // color contrasts
+ if (
+ // test to text/background colors in identity group
+ ((group === "identity" && (tint === "text" || tint === "background")) ||
+ // test to same color tint
+ (group === id[0] && tint === id[1])) &&
+ // test only for light and strong weights, let out 500
+ // 500 is necessary to have a good gradient but they are never good to use as text color/bg
+ id[2] !== "500" &&
+ weight !== "500"
+ ) {
+ if (
+ // only calculate light versions to dark versions b/c other usage combination would not make sense at all
+ (color.isDark() && (value as Color).isLight()) ||
+ (color.isLight() && (value as Color).isDark())
+ ) {
+ if (color.contrast(value as Color) < minimalContrast) {
+ warningsContrast.push(
+
+ Fix with{" "}
+
+ {`${tint}${weight}`} (
+ {color.contrast(value as Color).toPrecision(2)})
+
+ >
+ }
+ >
+
+ Fix{" "}
+
+ {`${id[1]}}${id[2]}}`}
+
+ >
+ }
+ onClick={() => {
+ colors[id[0]][id[1]][id[2]] = fixColorByLuminosity(
+ color,
+ value as Color,
+ (c1, c2) => {
+ const contrast = c1.contrast(c2 as Color);
+ // eslint-disable-next-line no-console
+ console.log(`${c1.hex()} -> ${contrast}`);
+ return contrast < minimalContrast;
+ }
+ );
+ setPaletteData({ ...colors });
+ }}
+ />
+
+ Fix{" "}
+
+ {`${tint}${weight}`}
+
+ >
+ }
+ onClick={() => {
+ colors[group][tint][weight] = fixColorByLuminosity(
+ value as Color,
+ color,
+ (c1, c2) => {
+ const contrast = c1.contrast(c2 as Color);
+ // eslint-disable-next-line no-console
+ console.log(`${c1.hex()} -> ${contrast}`);
+ return contrast < minimalContrast;
+ }
+ );
+ setPaletteData({ ...colors });
+ }}
+ />
+
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return warningsDistance.length + warningsContrast.length > 0 ? (
+
+ }
+ >
+ {warningsDistance.length > 0 ? Distances : <>>}
+ <>{warningsDistance}>
+ {warningsContrast.length > 0 ? Contrasts : <>>}
+ <>{warningsContrast}>
+
+ ) : undefined;
+ };
+
+ const renderColorInput = (
+ paletteData: object = {},
+ label: string,
+ id: string[],
+ updateFn: (color: string) => void
+ ) => {
+ if (!paletteData[id[0]] || !paletteData[id[0]][id[1]] || !paletteData[id[0]][id[1]][id[2]]) {
+ return <>>;
+ }
+ const color = paletteData[id[0]][id[1]][id[2]];
+ const menuWarnings = createWarnings(id, paletteData);
+ return (
+
+ {
+ if (userInputDelay) {
+ clearTimeout(userInputDelay);
+ }
+ userInputDelay = setTimeout(() => {
+ updateFn(newcolor);
+ }, userInputDelayTime);
+ }}
+ intent={menuWarnings ? "warning" : undefined}
+ rightElement={menuWarnings}
+ />
+
+ );
+ };
+
+ const editorPanel = (
+
+
+
+ {
+ if (userInputDelay) {
+ clearTimeout(userInputDelay);
+ }
+ userInputDelay = setTimeout(() => {
+ setMinimalDistance(parseInt(value, 10));
+ }, userInputDelayTime);
+ }}
+ rightElement={
+ setCalculateDistanceWarnings(!calculateDistanceWarnings)}
+ />
+ }
+ />
+
+
+ {
+ if (userInputDelay) {
+ clearTimeout(userInputDelay);
+ }
+ userInputDelay = setTimeout(() => {
+ setMinimalContrast(parseFloat(value));
+ }, userInputDelayTime);
+ }}
+ rightElement={
+ setCalculateContrastWarnings(!calculateContrastWarnings)}
+ />
+ }
+ />
+
+
+ {paletteData &&
+ Object.keys(paletteData).map((group, id) => {
+ return (
+
+
+ {group}
+
+
+ {Object.keys(paletteData[group]).map((tint, id) => {
+ return (
+
+
+
+ {Object.keys(paletteData[group][tint]).map((weight) => {
+ return renderColorInput(
+ paletteData,
+ `${tint}${weight}`,
+ [group, tint, weight],
+ (newcolor) => {
+ paletteData[group][tint][weight] = Color(newcolor).rgb();
+ setPaletteData({ ...paletteData });
+ }
+ );
+ })}
+
+
+
+ {
+ const tintValues = Object.values(
+ paletteData[group][tint]
+ ) as Color[];
+ const tintKeys = Object.keys(paletteData[group][tint]);
+ if (tintValues.length > 0) {
+ const tint100 = tintValues[0];
+ const tint900 = tintValues[tintValues.length - 1];
+ tintKeys.forEach((weight, id) => {
+ paletteData[group][tint][weight] = Color(tint100).mix(
+ Color(tint900),
+ id / (tintValues.length - 1)
+ );
+ // eslint-disable-next-line no-console
+ console.log(
+ `mix ${Color(tint100).hex()} with ${Color(
+ tint900
+ ).hex()} by ${id / (tintValues.length - 1)} -> ${
+ paletteData[group][tint][weight]
+ }`
+ );
+ });
+ }
+ setPaletteData({ ...paletteData });
+ }}
+ />
+
+
+ );
+ })}
+
+
+ );
+ })}
+
+ );
+
+ const currentLayoutColorList = createSimpleColorList(paletteData ?? {}, calculateDistanceWarnings);
+
+ return (
+
+
+
{}}
+ tabs={[
+ {
+ id: "editor",
+ panel: editorPanel,
+ title: } />,
+ },
+ {
+ id: "css",
+ panel: (
+
+
+
+ {
+ setPaletteData(createPaletteData(userPaletteRef.current?.value));
+ }}
+ />
+
+ ),
+ title: "CSS properties",
+ },
+ {
+ id: "scss",
+ panel: (
+
+
+
+ ),
+ title: "SCSS configuration",
+ },
+ {
+ id: "hashtest",
+ title: "Color hashes",
+ panel: (
+
+
+
+ {["identity", "semantic", "layout", "extra"].map((group) => (
+
+ {
+ updateHashtestGroups(
+ event.target.value,
+ event.target.checked
+ );
+ }}
+ checked={hashtestGroups.includes(group)}
+ >
+ {group}
+
+
+ ))}
+
+
+
+
+ {["100", "300", "500", "700", "900"].map((weight) => (
+
+ {
+ updateHashtestWeights(
+ event.target.value,
+ event.target.checked
+ );
+ }}
+ checked={hashtestWeights.includes(weight)}
+ >
+ {weight}
+
+
+ ))}
+
+
+ {Object.values(currentLayoutColorList).length > 0 && (
+ <>
+
+
+ Allow text as direct color hash
+
+
+
+ {"yellow purple magenta pink violet indigo cyan teal lime grey rgb(128,0,128) #00ffff no_valid_color_string"
+ .toString()
+ .split(" ")
+ .map((text, index) => (
+
+ {text}
+
+ ))}
+
+
+
+
+
+
+ Allow text as color but look for nearest palette neighbour
+
+
+
+
+ {"yellow purple magenta pink violet indigo cyan teal lime amber vermilion grey rgb(128,0,128) #00ffff no_valid_color_string"
+ .toString()
+ .split(" ")
+ .map((text, index) => (
+
+ {text}
+
+ ))}
+
+
+
+
+
+ Directly used color hash
+
+
+
+ {loremIpsum({
+ p: 1,
+ avgSentencesPerParagraph: 1,
+ avgWordsPerSentence: 40,
+ random: false,
+ })
+ .toString()
+ .split(" ")
+ .map((text, index) => (
+
+ {text}
+
+ ))}
+
+
+
+
+
+
+ Nearest layout palette neighbour of color hash
+
+
+
+
+ {loremIpsum({
+ p: 1,
+ avgSentencesPerParagraph: 1,
+ avgWordsPerSentence: 40,
+ random: false,
+ })
+ .toString()
+ .split(" ")
+ .map((text, index) => (
+
+ {text}
+
+ ))}
+
+
+ >
+ )}
+
+ ),
+ },
+ ]}
+ />
+
+
+ );
+};
+
+export default {
+ title: "Components/Application/Colors",
+ component: ColorPaletteConfigurator,
+ argTypes: {},
+} as Meta;
+
+const Template: StoryFn = (args) => ;
+
+export const Default = Template.bind({});
+
+Default.args = {
+ customColorProperties: "",
+ enableCalculations: false,
+};
diff --git a/src/components/AutoSuggestion/AutoSuggestion.tsx b/src/components/AutoSuggestion/AutoSuggestion.tsx
index 3649db899..057164e29 100644
--- a/src/components/AutoSuggestion/AutoSuggestion.tsx
+++ b/src/components/AutoSuggestion/AutoSuggestion.tsx
@@ -34,9 +34,6 @@ export interface CodeAutocompleteFieldSuggestionBase {
description?: string;
}
-/** @deprecated (v25) use CodeAutocompleteFieldSuggestionBase */
-export type ISuggestionBase = CodeAutocompleteFieldSuggestionBase;
-
/** Same as CodeAutocompleteFieldSuggestionBase, but with the query that was used to fetch this suggestion. */
export interface CodeAutocompleteFieldSuggestionWithReplacementInfo extends CodeAutocompleteFieldSuggestionBase {
// The query this result was filtered by
@@ -47,9 +44,6 @@ export interface CodeAutocompleteFieldSuggestionWithReplacementInfo extends Code
length: number;
}
-/** @deprecated (v25) use CodeAutocompleteFieldSuggestionWithReplacementInfo */
-export type ISuggestionWithReplacementInfo = CodeAutocompleteFieldSuggestionWithReplacementInfo;
-
/** The suggestions for a specific substring of the given input string. */
export interface CodeAutocompleteFieldReplacementResult {
// The range of the input string that should be replaced
@@ -63,9 +57,6 @@ export interface CodeAutocompleteFieldReplacementResult {
replacements: CodeAutocompleteFieldSuggestionBase[];
}
-/** @deprecated (v25) use CodeAutocompleteFieldReplacementResult */
-export type IReplacementResult = CodeAutocompleteFieldReplacementResult;
-
export interface CodeAutocompleteFieldPartialAutoCompleteResult {
// Repeats the input string from the corresponding request
inputString: string;
@@ -74,9 +65,6 @@ export interface CodeAutocompleteFieldPartialAutoCompleteResult {
replacementResults: CodeAutocompleteFieldReplacementResult[];
}
-/** @deprecated (v25) use CodeAutocompleteFieldPartialAutoCompleteResult */
-export type IPartialAutoCompleteResult = CodeAutocompleteFieldPartialAutoCompleteResult;
-
/** Validation result */
export interface CodeAutocompleteFieldValidationResult {
// If the input value is valid or not
@@ -91,13 +79,7 @@ export interface CodeAutocompleteFieldValidationResult {
};
}
-/** @deprecated (v25) use CodeAutocompleteFieldValidationResult */
-export type IValidationResult = CodeAutocompleteFieldValidationResult;
-
-/**
- * @deprecated (v25) use `CodeAutocompleteFieldProps` instead.
- */
-export interface AutoSuggestionProps {
+export interface CodeAutocompleteFieldProps {
/** Additional class name.
*/
className?: string;
@@ -180,9 +162,12 @@ interface RequestMetaData {
}
/**
- * @deprecated (support already removed) use `CodeAutocompleteField` as replacement.
+ * Input component that allows partial, fine-grained auto-completion, i.e. of sub-strings of the input string.
+ * This is comparable to a one line code editor.
+ *
+ * Example usage: input of a path string offering auto-completion for each single part of the path.
*/
-const AutoSuggestion = ({
+export const CodeAutocompleteField = ({
className,
label,
initialValue,
@@ -206,8 +191,8 @@ const AutoSuggestion = ({
reInitOnInitialValueChange = false,
height,
readOnly,
- outerDivAttributes
-}: AutoSuggestionProps) => {
+ outerDivAttributes,
+}: CodeAutocompleteFieldProps) => {
const value = React.useRef(initialValue);
const cursorPosition = React.useRef(0);
const dropdownXYoffset = React.useRef<{ x: number; y: number }>({ x: 0, y: 0 });
@@ -317,12 +302,11 @@ const AutoSuggestion = ({
};
if (parseError) {
const { message, start, end } = parseError;
- const { toOffset, fromOffset } = getOffsetRange(cm, start, end);
clearCurrentErrorMarker();
const { from, to } = markText({
view: cm,
- from: fromOffset,
- to: toOffset,
+ from: start,
+ to: end,
className: `${eccgui}-autosuggestion__text--highlighted-error`,
title: message,
});
@@ -626,7 +610,7 @@ const AutoSuggestion = ({
handleEscapePressed();
break;
default:
- //do nothing
+ //do nothing
closeDropDown();
}
}
@@ -676,7 +660,7 @@ const AutoSuggestion = ({
showScrollBar,
multiline,
handleInputMouseDown,
- readOnly
+ readOnly,
]);
const hasError = !!value.current && !pathIsValid && !pathValidationPending;
@@ -684,7 +668,7 @@ const AutoSuggestion = ({
+
)}
>
),
}}
- hasStateDanger={hasError}
+ intent={hasError ? "danger" : undefined}
messageText={hasError ? validationErrorText : undefined}
>
{withRightElement}
@@ -766,4 +750,4 @@ const AutoSuggestion = ({
);
};
-export default AutoSuggestion;
+export default CodeAutocompleteField;
diff --git a/src/components/AutoSuggestion/AutoSuggestionList.tsx b/src/components/AutoSuggestion/AutoSuggestionList.tsx
index aa1c2169c..ff524fad3 100644
--- a/src/components/AutoSuggestion/AutoSuggestionList.tsx
+++ b/src/components/AutoSuggestion/AutoSuggestionList.tsx
@@ -15,13 +15,13 @@ import {
Spinner,
Tooltip,
} from "./../../";
-import { ISuggestionWithReplacementInfo } from "./AutoSuggestion";
+import { CodeAutocompleteFieldSuggestionWithReplacementInfo } from "./AutoSuggestion";
export interface AutoSuggestionListProps extends Omit
, "children"> {
// The options of the drop down
- options: Array;
+ options: Array;
// Called when an item has been selected from the drop down
- onItemSelectionChange: (item: ISuggestionWithReplacementInfo) => any;
+ onItemSelectionChange: (item: CodeAutocompleteFieldSuggestionWithReplacementInfo) => any;
// If the drop down is visible
isOpen: boolean;
// If the drop down should show a loading state
@@ -29,7 +29,7 @@ export interface AutoSuggestionListProps extends Omit any;
+ itemToHighlight: (item: CodeAutocompleteFieldSuggestionWithReplacementInfo | undefined) => any;
/** horizontal and vertical offset values in relation to the cursor */
offsetValues?: { x: number; y: number };
}
@@ -43,6 +43,13 @@ const ListItem = ({ item }: any, ref: any) => {
+ {item.label ? (
+
+
+
+
+
+ ) : null}
{item.description ? (
@@ -79,7 +86,7 @@ export const AutoSuggestionList = ({
offsetValues,
...otherDivProps
}: AutoSuggestionListProps) => {
- const [hoveredItem, setHoveredItem] = React.useState(undefined);
+ const [hoveredItem, setHoveredItem] = React.useState(undefined);
// Refs of list items
const [refs] = React.useState[]>([]);
const dropdownRef = React.useRef(null);
@@ -116,7 +123,7 @@ export const AutoSuggestionList = ({
Fetching suggestions
-
+
);
diff --git a/src/components/AutoSuggestion/ExtendedCodeEditor.tsx b/src/components/AutoSuggestion/ExtendedCodeEditor.tsx
index 179681eaf..4dc9e3a3a 100644
--- a/src/components/AutoSuggestion/ExtendedCodeEditor.tsx
+++ b/src/components/AutoSuggestion/ExtendedCodeEditor.tsx
@@ -67,8 +67,6 @@ export interface ExtendedCodeEditorProps {
readOnly?: boolean;
}
-export type IEditorProps = ExtendedCodeEditorProps;
-
/** Supports single-line and multiline editing. */
export const ExtendedCodeEditor = ({
multiline = false,
@@ -113,11 +111,7 @@ export const ExtendedCodeEditor = ({
name=""
enableTab={enableTab}
additionalExtensions={[...multilineExtensions]}
- outerDivAttributes={{
- className: `${eccgui}-${
- multiline ? "codeeditor" : `singlelinecodeeditor ${BlueprintClassNames.INPUT}`
- }`,
- }}
+ className={multiline ? undefined : `${eccgui}-singlelinecodeeditor ${BlueprintClassNames.INPUT}`}
{...codeEditorProps}
/>
);
diff --git a/src/components/AutoSuggestion/index.ts b/src/components/AutoSuggestion/index.ts
deleted file mode 100644
index 2261d0c02..000000000
--- a/src/components/AutoSuggestion/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { AutoSuggestionProps } from "./AutoSuggestion";
-import { AutoSuggestionList, AutoSuggestionListProps } from "./AutoSuggestionList";
-import { ExtendedCodeEditor, ExtendedCodeEditorProps } from "./ExtendedCodeEditor";
-
-export { AutoSuggestionList, ExtendedCodeEditor };
-
-export type { AutoSuggestionProps, AutoSuggestionListProps, ExtendedCodeEditorProps };
diff --git a/src/components/AutocompleteField/AutoCompleteField.stories.tsx b/src/components/AutocompleteField/AutoCompleteField.stories.tsx
deleted file mode 100644
index 937f5a794..000000000
--- a/src/components/AutocompleteField/AutoCompleteField.stories.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Meta } from "@storybook/react";
-
-import { AutoCompleteField } from "./../../../index";
-export { Default } from "../SuggestField/SuggestField.stories";
-
-export default {
- title: "Forms/AutoCompleteField",
- component: AutoCompleteField,
- parameters: {
- controls: {
- exclude: /.*/g,
- },
- },
-} as Meta;
diff --git a/src/components/AutocompleteField/AutoCompleteField.tsx b/src/components/AutocompleteField/AutoCompleteField.tsx
index f51aca4d5..02f6a5613 100644
--- a/src/components/AutocompleteField/AutoCompleteField.tsx
+++ b/src/components/AutocompleteField/AutoCompleteField.tsx
@@ -23,9 +23,11 @@ type SearchFunction = (value: string) => T[];
type AsyncSearchFunction = (value: string) => Promise;
/**
- * @deprecated (v25) replaced by SuggestFieldProps
+ * Parameters for the auto-complete field parameterized by T and U.
+ * @param T is the input data structure/type of the items that can be selected.
+ * @param UPDATE_VALUE The value type that will be pushed into the onChange callback.
*/
-export interface AutoCompleteFieldProps {
+export interface SuggestFieldProps {
/**
* Additional class names.
*/
@@ -158,12 +160,7 @@ export interface AutoCompleteFieldProps {
loadMoreResults?: () => Promise;
}
-/**
- * @deprecated (v25) replaced by SuggestFieldProps
- */
-export type IAutoCompleteFieldProps = AutoCompleteFieldProps;
-
-AutoCompleteField.defaultProps = {
+SuggestField.defaultProps = {
autoFocus: false,
disabled: false,
onlyDropdownWithQuery: false, // FIXME: this should be `true` by default, otherwise similarity to ` ` is very close
@@ -173,9 +170,19 @@ AutoCompleteField.defaultProps = {
};
/**
- * @deprecated (support already removed) use `SuggestField` as replacement.
+ * A component with the appearance of an input field that allows to select and optionally create new items.
+ * It shows suggestions for the entered text from which the user can select any option.
+ *
+ * It has the following fixed behavior:
+ *
+ * - When not focused, a different representation of the item value can be shown, e.g. the label of the value.
+ * - When changing an existing item the input text is set to the original value in order to be able to edit the original value.
+ * - When for a specific input text, the only item returned is the currently set item itself, all items are shown below it, to make
+ * clear that there are still other items to choose from.
+ * - The suggestions are fetched with a short delay, so not too many unnecessary requests are fired.
+ * - Items where itemRenderer returns a string have a default representation, i.e. highlighting of search words, active flag etc.
*/
-function AutoCompleteField(props: AutoCompleteFieldProps) {
+export function SuggestField(props: SuggestFieldProps) {
const {
className,
reset,
@@ -368,7 +375,7 @@ function AutoCompleteField(props: AutoCompleteFieldProps {
- return ;
+ return ;
};
// Optional clear button to reset the selected value
const clearButton =
@@ -468,7 +475,7 @@ function AutoCompleteField(props: AutoCompleteFieldProps
- className={`${eccgui}-autocompletefield__input` + (className ? ` ${className}` : "")}
+ className={`${eccgui}-suggestfield ${eccgui}-autocompletefield__input` + (className ? ` ${className}` : "")}
disabled={disabled}
// Need to display error messages in list
items={requestError ? [requestError as unknown as T] : filtered}
@@ -487,6 +494,7 @@ function AutoCompleteField(props: AutoCompleteFieldProps(props: AutoCompleteFieldProps
) => {
// Return custom render function
- return (query: string, modifiers: IRenderModifiers, handleClick: React.MouseEventHandler) => {
+ return (query: string, modifiers: SuggestFieldItemRendererModifierProps, handleClick: React.MouseEventHandler) => {
let textElement = itemTextRenderer(query);
if (typeof textElement === "string") {
textElement = (
diff --git a/src/components/AutocompleteField/index.ts b/src/components/AutocompleteField/index.ts
deleted file mode 100644
index 344488100..000000000
--- a/src/components/AutocompleteField/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { createNewItemRendererFactory } from "./autoCompleteFieldUtils";
-export * from "./AutoCompleteField";
-export * from "./interfaces";
-export const autoCompleteFieldUtils = {
- createNewItemRendererFactory,
-};
diff --git a/src/components/AutocompleteField/interfaces.ts b/src/components/AutocompleteField/interfaces.ts
index 2c40ad3c3..97ef84428 100644
--- a/src/components/AutocompleteField/interfaces.ts
+++ b/src/components/AutocompleteField/interfaces.ts
@@ -6,11 +6,7 @@ export interface SuggestFieldItemRendererModifierProps {
highlightingEnabled: boolean;
}
-/** @deprecated (v25) use `SuggestFieldItemRendererModifierProps` */
-export type IRenderModifiers = SuggestFieldItemRendererModifierProps;
-
-/** @deprecated (v25) use `SuggestFieldItemRendererModifierProps["styleWidth"]` */
-export interface IElementWidth {
+interface IElementWidth {
minWidth: string;
maxWidth: string;
}
diff --git a/src/components/Button/Button.stories.tsx b/src/components/Button/Button.stories.tsx
index d2899b5ae..11862224a 100644
--- a/src/components/Button/Button.stories.tsx
+++ b/src/components/Button/Button.stories.tsx
@@ -20,7 +20,7 @@ export default {
},
intent: {
...helpersArgTypes.exampleIntent,
- options: ["UNDEFINED", "primary", "success", "warning", "danger"],
+ options: ["UNDEFINED", "primary", "accent", "success", "warning", "danger"],
},
},
} as Meta;
@@ -33,10 +33,6 @@ const TemplateFull: StoryFn = (args) => (
export const FullExample = TemplateFull.bind({});
FullExample.args = {
- hasStatePrimary: false,
- hasStateSuccess: false,
- hasStateWarning: false,
- hasStateDanger: false,
elevated: false,
affirmative: false,
disruptive: false,
@@ -66,6 +62,8 @@ const TemplateSemantic: StoryFn = (args) => (
+
+
);
export const ButtonSemantics = TemplateSemantic.bind({});
@@ -78,6 +76,10 @@ const TemplateIntent: StoryFn = (args) => (
+
+
+
+
);
export const ButtonIntent = TemplateIntent.bind({});
diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx
index 9f7563ae1..7110d1c33 100644
--- a/src/components/Button/Button.tsx
+++ b/src/components/Button/Button.tsx
@@ -17,39 +17,23 @@ import Tooltip, { TooltipProps } from "./../Tooltip/Tooltip";
interface AdditionalButtonProps {
/**
* Always use this when the button triggers an affirmative action, e.g. confirm a process.
- * The button is displayed with primary color scheme.
+ * The button is displayed with accent color intent.
*/
affirmative?: boolean;
/**
* Always use this when the button triggers an disruptive action, e.g. delete or remove.
- * The button is displayed with primary color scheme.
+ * The button is displayed with danger color intent.
*/
disruptive?: boolean;
/**
* Use this when a button is important enough to highlight it in a set of other buttons.
- * The button is displayed with primary color scheme.
+ * The button is displayed with accent color intent.
*/
elevated?: boolean;
/**
- * The button is displayed with primary color scheme.
- * @deprecated (v25) use `intent="primary"` instead.
+ * Intent state visualized by color.
*/
- hasStatePrimary?: boolean;
- /**
- * The button is displayed with success (some type of green) color scheme.
- * @deprecated (v25) use `intent="success"` instead.
- */
- hasStateSuccess?: boolean;
- /**
- * The button is displayed with warning (some type of orange) color scheme.
- * @deprecated (v25) use `intent="warning"` instead.
- */
- hasStateWarning?: boolean;
- /**
- * The button is displayed with danger (some type of red) color scheme.
- * @deprecated (v25) use `intent="danger"` instead.
- */
- hasStateDanger?: boolean;
+ intent?: BlueprintIntent | "accent";
/**
* Content displayed in a badge that is attached to the button.
* By default it is displayed `{ size: "small", position: "top-right", maxLength: 2 }` and with the same intent state of the button.
@@ -69,18 +53,21 @@ interface AdditionalButtonProps {
*/
tooltipProps?: Partial>;
/**
- * If an URL is set then the button is included as HTML anchor element instead of a button form element.
+ * Icon displayed on button start.
*/
- //href?: string;
icon?: ValidIconName | JSX.Element;
+ /**
+ * Icon displayed on button end.
+ */
rightIcon?: ValidIconName | JSX.Element;
- //target?: string;
}
-interface ExtendedButtonProps extends AdditionalButtonProps, Omit {}
+interface ExtendedButtonProps
+ extends AdditionalButtonProps,
+ Omit {}
interface ExtendedAnchorButtonProps
extends AdditionalButtonProps,
- Omit {}
+ Omit {}
export type ButtonProps = ExtendedButtonProps & ExtendedAnchorButtonProps;
@@ -94,10 +81,6 @@ export const Button = ({
affirmative = false,
disruptive = false,
elevated = false,
- hasStatePrimary = false,
- hasStateSuccess = false,
- hasStateWarning = false,
- hasStateDanger = false,
icon,
rightIcon,
tooltip = null,
@@ -107,19 +90,13 @@ export const Button = ({
intent,
...restProps
}: ButtonProps) => {
- let intention;
+ let intentByFunction;
switch (true) {
- case affirmative || elevated || hasStatePrimary:
- intention = BlueprintIntent.PRIMARY;
- break;
- case hasStateSuccess:
- intention = BlueprintIntent.SUCCESS;
- break;
- case hasStateWarning:
- intention = BlueprintIntent.WARNING;
+ case affirmative || elevated:
+ intentByFunction = "accent";
break;
- case disruptive || hasStateDanger:
- intention = BlueprintIntent.DANGER;
+ case disruptive:
+ intentByFunction = BlueprintIntent.DANGER;
break;
default:
break;
@@ -131,7 +108,7 @@ export const Button = ({
: icon}
rightIcon={typeof rightIcon === "string" ? : rightIcon}
>
@@ -140,10 +117,7 @@ export const Button = ({
,
+ extends Pick,
Pick {}
-const constructBadgeProperties = ({
- hasStatePrimary,
- hasStateSuccess,
- hasStateWarning,
- hasStateDanger,
- minimal,
- outlined,
- badgeProps = {},
-}: constructBadgePropertiesProps) => {
+const constructBadgeProperties = ({ intent, minimal, outlined, badgeProps = {} }: constructBadgePropertiesProps) => {
if (badgeProps.intent) return badgeProps;
- if (hasStatePrimary) badgeProps["intent"] = "accent";
- if (hasStateSuccess) badgeProps["intent"] = "success";
- if (hasStateWarning) badgeProps["intent"] = "warning";
- if (hasStateDanger) badgeProps["intent"] = "danger";
+ if (intent) badgeProps["intent"] = intent;
if (!badgeProps.tagProps || typeof badgeProps.tagProps.minimal === "undefined") {
if (!minimal && !outlined) {
badgeProps["tagProps"] = { ...badgeProps.tagProps, minimal: true };
diff --git a/src/components/Button/button.scss b/src/components/Button/button.scss
index bdfd9cb9f..766fd4a12 100644
--- a/src/components/Button/button.scss
+++ b/src/components/Button/button.scss
@@ -1,5 +1,6 @@
@use "sass:color";
@use "sass:map";
+@use "sass:list";
$button-height: $pt-button-height;
$button-border-width: 1px; // !default;
@@ -20,9 +21,9 @@ $button-border-radius: $pt-border-radius;
// $dark-button-box-shadow-active: 0 0 0 $button-border-width rgba($black, 0.6), inset 0 1px 2px rgba($black, 0.2) !default;
// $dark-button-intent-box-shadow: 0 0 0 $button-border-width rgba($black, 0.4) !default;
// $dark-button-intent-box-shadow-active: 0 0 0 $button-border-width rgba($black, 0.4), inset 0 1px 2px rgba($black, 0.2) !default;
-$button-gradient: none; // !default; // linear-gradient(to bottom, rgba($white, 0.8), rgba($white, 0)) !default;
-$button-intent-gradient: $button-gradient; // !default; // linear-gradient(to bottom, rgba($white, 0.1), rgba($white, 0)) !default;
-$dark-button-gradient: $button-gradient; // !default; // linear-gradient(to bottom, rgba($white, 0.05), rgba($white, 0)) !default;
+$button-gradient: none; // !default;
+$button-intent-gradient: $button-gradient; // !default;
+$dark-button-gradient: $button-gradient; // !default;
// $button-color-disabled: $pt-text-color-disabled !default;
// $button-background-color: $light-gray5 !default;
// $button-background-color-hover: $light-gray4 !default;
@@ -49,64 +50,125 @@ $dark-button-gradient: $button-gradient; // !default; // linear-gradient(to bott
// $button-outlined-border-disabled-intent-opacity: 0.2 !default;
$button-intents: (
- "primary": (
- $eccgui-color-accent,
- color.scale($eccgui-color-accent, $lightness: -20%),
- color.scale($eccgui-color-accent, $lightness: -40%),
+ // default - hover - active
+ "primary":
+ (
+ eccgui-color-var("identity", "brand", "900"),
+ eccgui-color-mix(
+ eccgui-color-var("identity", "brand", "900"),
+ eccgui-color-var("identity", "text", "900") 10%
+ ),
+ eccgui-color-mix(
+ eccgui-color-var("identity", "brand", "900"),
+ eccgui-color-var("identity", "text", "900") 20%
+ )
+ ),
+ "accent": (
+ eccgui-color-var("identity", "accent", "900"),
+ eccgui-color-mix(
+ eccgui-color-var("identity", "accent", "900"),
+ eccgui-color-var("identity", "text", "900") 10%
+ ),
+ eccgui-color-mix(eccgui-color-var("identity", "accent", "900"), eccgui-color-var("identity", "text", "900") 20%)
),
"success": (
- $eccgui-color-success-text,
- color.scale($eccgui-color-success-text, $lightness: -20%),
- color.scale($eccgui-color-success-text, $lightness: -40%),
+ eccgui-color-var("semantic", "success", "900"),
+ eccgui-color-mix(
+ eccgui-color-var("semantic", "success", "900"),
+ eccgui-color-var("identity", "text", "900") 10%
+ ),
+ eccgui-color-mix(
+ eccgui-color-var("semantic", "success", "900"),
+ eccgui-color-var("identity", "text", "900") 20%
+ )
),
"warning": (
- $eccgui-color-warning-text,
- color.scale($eccgui-color-warning-text, $lightness: -20%),
- color.scale($eccgui-color-warning-text, $lightness: -40%),
+ eccgui-color-var("semantic", "warning", "900"),
+ eccgui-color-mix(
+ eccgui-color-var("semantic", "warning", "900"),
+ eccgui-color-var("identity", "text", "900") 10%
+ ),
+ eccgui-color-mix(
+ eccgui-color-var("semantic", "warning", "900"),
+ eccgui-color-var("identity", "text", "900") 20%
+ )
),
"danger": (
- $eccgui-color-danger-text,
- color.scale($eccgui-color-danger-text, $lightness: -20%),
- color.scale($eccgui-color-danger-text, $lightness: -40%),
- ),
+ eccgui-color-var("semantic", "danger", "900"),
+ eccgui-color-mix(
+ eccgui-color-var("semantic", "danger", "900"),
+ eccgui-color-var("identity", "text", "900") 10%
+ ),
+ eccgui-color-mix(eccgui-color-var("semantic", "danger", "900"), eccgui-color-var("identity", "text", "900") 20%)
+ )
);
@import "~@blueprintjs/core/src/components/button/button";
-.#{$ns}-button {
- position: relative;
-
- .#{$ns}-large {
- min-height: mini-units(6);
- }
-
- // special case override: blueprint do not use configured colors here
- &.#{$ns}-intent-warning {
- @include pt-button-intent(map.get($button-intents, "warning")...);
+@mixin eccgui-enhance-blueprint-button-intent($intentvalue) {
+ &.#{$ns}-intent-#{$intentvalue} {
+ @include pt-button-intent(map.get($button-intents, $intentvalue)...);
&:not(.#{$ns}-disabled).#{$ns}-icon > svg {
- fill: rgba($white, 0.7);
+ fill: eccgui-color-rgba($white, 0.7);
}
&:not(.#{$ns}-disabled):not(.#{$ns}-minimal):not(.#{$ns}-outlined) {
- @include pt-button-intent(map.get($button-intents, "warning")...);
+ @include pt-button-intent(map.get($button-intents, $intentvalue)...);
}
&.#{$ns}-minimal,
&.#{$ns}-outlined {
- color: $eccgui-color-warning-text;
+ color: list.nth(map.get($button-intents, $intentvalue), 1);
background: none;
- border-color: $eccgui-color-warning-text;
+ border-color: list.nth(map.get($button-intents, $intentvalue), 1);
box-shadow: none;
&:disabled,
&.#{$ns}-disabled {
- color: rgba($eccgui-color-warning-text, 0.39);
+ color: eccgui-color-rgba(list.nth(map.get($button-intents, $intentvalue), 1), $eccgui-opacity-disabled);
+ border-color: eccgui-color-rgba(
+ list.nth(map.get($button-intents, $intentvalue), 1),
+ $eccgui-opacity-disabled
+ );
+ }
+
+ &:active:not(:disabled):not(.#{$ns}-disabled),
+ &.#{$ns}-active:not(:disabled):not(.#{$ns}-disabled) {
+ color: list.nth(map.get($button-intents, $intentvalue), 3);
+ background-color: eccgui-color-rgba(
+ list.nth(map.get($button-intents, $intentvalue), 3),
+ $eccgui-opacity-ghostly
+ );
+ border-color: list.nth(map.get($button-intents, $intentvalue), 3);
+ }
+
+ &:focus:not(:disabled):not(.#{$ns}-disabled),
+ &:hover:not(:disabled):not(.#{$ns}-disabled) {
+ color: list.nth(map.get($button-intents, $intentvalue), 2);
+ background-color: eccgui-color-rgba(
+ list.nth(map.get($button-intents, $intentvalue), 2),
+ 0.5 * $eccgui-opacity-ghostly
+ );
+ border-color: list.nth(map.get($button-intents, $intentvalue), 2);
}
}
}
}
+.#{$ns}-button {
+ position: relative;
+
+ .#{$ns}-large {
+ min-height: mini-units(6);
+ }
+
+ // special case override: blueprint do not use configured colors here
+ @include eccgui-enhance-blueprint-button-intent("primary");
+ @include eccgui-enhance-blueprint-button-intent("accent");
+ @include eccgui-enhance-blueprint-button-intent("warning");
+}
+
.#{$ns}-button-text {
min-width: 0;
}
diff --git a/src/components/Card/card.scss b/src/components/Card/card.scss
index ebfdcb563..a551cbcf8 100644
--- a/src/components/Card/card.scss
+++ b/src/components/Card/card.scss
@@ -1,8 +1,8 @@
@use "sass:color";
$card-padding: 0 !default;
-$card-background-color: $white !default;
-$card-selected-background-color: rgba($blue3, 0.1);
+$card-background-color: #{eccgui-color-var("identity", "background", "100")} !default;
+$card-selected-background-color: eccgui-color-rgba($blue3, 0.1);
$eccgui-size-card-spacing: $eccgui-size-typo-base !default;
@import "~@blueprintjs/core/src/components/card/card";
@@ -14,22 +14,22 @@ $eccgui-size-card-spacing: $eccgui-size-typo-base !default;
justify-content: flex-start;
&.#{$eccgui}-intent--primary {
- background-color: color.mix($eccgui-color-primary, $card-background-color, 5%);
+ background-color: eccgui-color-var("identity", "brand", "100");
}
&.#{$eccgui}-intent--accent {
- background-color: color.mix($eccgui-color-accent, $card-background-color, 10%);
+ background-color: eccgui-color-var("identity", "accent", "100");
}
&.#{$eccgui}-intent--success {
- background-color: $eccgui-color-success-background;
+ background-color: eccgui-color-var("semantic", "success", "100");
}
&.#{$eccgui}-intent--info {
- background-color: $eccgui-color-info-background;
+ background-color: eccgui-color-var("semantic", "info", "100");
}
&.#{$eccgui}-intent--warning {
- background-color: $eccgui-color-warning-background;
+ background-color: eccgui-color-var("semantic", "warning", "100");
}
&.#{$eccgui}-intent--danger {
- background-color: $eccgui-color-danger-background;
+ background-color: eccgui-color-var("semantic", "danger", "100");
}
&.#{$ns}-interactive:hover {
@@ -38,13 +38,13 @@ $eccgui-size-card-spacing: $eccgui-size-typo-base !default;
&.#{$ns}-selected {
background-color: $card-selected-background-color;
- box-shadow: 0 0 0 3px rgba($eccgui-color-accent, 0.2), 0 0 0 1px $eccgui-color-accent;
+ box-shadow: 0 0 0 3px eccgui-color-rgba($eccgui-color-accent, 0.2), 0 0 0 1px $eccgui-color-accent;
&.#{$ns}-interactive {
- box-shadow: 0 0 0 3px rgba($eccgui-color-accent, 0.2), 0 0 0 1px $eccgui-color-accent;
+ box-shadow: 0 0 0 3px eccgui-color-rgba($eccgui-color-accent, 0.2), 0 0 0 1px $eccgui-color-accent;
&:hover {
- background-color: color.mix($card-selected-background-color, $button-background-color-hover, 50%);
+ background-color: eccgui-color-mix($card-selected-background-color, $button-background-color-hover);
}
}
}
@@ -176,9 +176,9 @@ $eccgui-size-card-spacing: $eccgui-size-typo-base !default;
.#{$eccgui}-card__actions {
display: flex;
- flex-flow: row wrap;
flex-grow: 0;
flex-shrink: 0;
+ flex-flow: row wrap;
align-items: center;
padding: $eccgui-size-card-spacing * 0.25 $eccgui-size-card-spacing;
@@ -242,8 +242,8 @@ $eccgui-size-card-spacing: $eccgui-size-typo-base !default;
.#{$eccgui}-card__actions__aux {
display: flex;
- flex-flow: row wrap;
flex-grow: 1;
+ flex-flow: row wrap;
align-items: center;
justify-content: flex-end;
order: 1000;
diff --git a/src/components/Chat/stories/ChatField.stories.tsx b/src/components/Chat/stories/ChatField.stories.tsx
index 9adf4fd81..d336f07b6 100644
--- a/src/components/Chat/stories/ChatField.stories.tsx
+++ b/src/components/Chat/stories/ChatField.stories.tsx
@@ -1,7 +1,7 @@
import React from "react";
import { Meta, StoryFn } from "@storybook/react";
-import { ChatField } from "../../../index";
+import { ChatField, ContextMenu, MenuItem } from "../../../index";
export default {
title: "Components/Chat/ChatField",
@@ -15,4 +15,9 @@ const TemplateFull: StoryFn = (args) => alert(value),
+ rightElement: (
+
+
+
+ ),
};
diff --git a/src/components/Checkbox/checkbox.scss b/src/components/Checkbox/checkbox.scss
index f74916602..f72a9fbdd 100644
--- a/src/components/Checkbox/checkbox.scss
+++ b/src/components/Checkbox/checkbox.scss
@@ -24,9 +24,9 @@ $control-indicator-spacing: $eccgui-size-inline-whitespace !default;
// $switch-background-color-active: rgba($gray1, 0.5) !default;
// $switch-background-color-disabled: $button-background-color-disabled !default;
$switch-checked-background-color: $eccgui-color-accent !default;
-$switch-checked-background-color-hover: rgba($switch-checked-background-color, $eccgui-opacity-narrow) !default;
+$switch-checked-background-color-hover: eccgui-color-rgba($switch-checked-background-color, $eccgui-opacity-narrow) !default;
$switch-checked-background-color-active: $switch-checked-background-color-hover !default;
-$switch-checked-background-color-disabled: rgba($switch-checked-background-color, $eccgui-opacity-disabled) !default;
+$switch-checked-background-color-disabled: eccgui-color-rgba($switch-checked-background-color, $eccgui-opacity-disabled) !default;
@import "~@blueprintjs/core/src/components/forms/controls"; // Checkbox, Radio, Switch
diff --git a/src/components/CodeAutocompleteField/CodeAutocompleteField.tsx b/src/components/CodeAutocompleteField/CodeAutocompleteField.tsx
deleted file mode 100644
index 0215bc7dd..000000000
--- a/src/components/CodeAutocompleteField/CodeAutocompleteField.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from "react";
-
-import { CLASSPREFIX as eccgui } from "../../configuration/constants";
-import AutoSuggestion, { AutoSuggestionProps } from "../AutoSuggestion/AutoSuggestion";
-
-export interface CodeAutocompleteFieldProps extends AutoSuggestionProps {}
-
-/**
- * Input component that allows partial, fine-grained auto-completion, i.e. of sub-strings of the input string.
- * This is comparable to a one line code editor.
- *
- * Example usage: input of a path string offering auto-completion for each single part of the path.
- */
-export function CodeAutocompleteField({ className, ...otherProps }: CodeAutocompleteFieldProps) {
- // Currently this works only as an alias element for `AutoSuggestion`.
- return (
-
- );
-}
diff --git a/src/components/CodeAutocompleteField/index.ts b/src/components/CodeAutocompleteField/index.ts
index fea6af8a4..3ef2a69eb 100644
--- a/src/components/CodeAutocompleteField/index.ts
+++ b/src/components/CodeAutocompleteField/index.ts
@@ -1 +1,8 @@
-export * from "./CodeAutocompleteField";
+import { AutoSuggestionList, AutoSuggestionListProps } from "./../AutoSuggestion/AutoSuggestionList";
+import { ExtendedCodeEditor, ExtendedCodeEditorProps } from "./../AutoSuggestion/ExtendedCodeEditor";
+
+export * from "./../AutoSuggestion/AutoSuggestion";
+
+export { AutoSuggestionList, ExtendedCodeEditor };
+
+export type { AutoSuggestionListProps, ExtendedCodeEditorProps };
diff --git a/src/components/ContentGroup/_contentgroup.scss b/src/components/ContentGroup/_contentgroup.scss
index 8f29176d4..4519fe65d 100644
--- a/src/components/ContentGroup/_contentgroup.scss
+++ b/src/components/ContentGroup/_contentgroup.scss
@@ -1,5 +1,11 @@
-$eccgui-color-scontentgroup-border-main: rgba($eccgui-color-workspace-text, $eccgui-opacity-muted) !default;
-$eccgui-color-scontentgroup-border-sub: rgba($eccgui-color-workspace-text, $eccgui-opacity-disabled) !default;
+$eccgui-color-scontentgroup-border-main: eccgui-color-rgba(
+ $eccgui-color-workspace-text,
+ $eccgui-opacity-muted
+) !default;
+$eccgui-color-scontentgroup-border-sub: eccgui-color-rgba(
+ $eccgui-color-workspace-text,
+ $eccgui-opacity-disabled
+) !default;
.#{$eccgui}-contentgroup {
--#{$eccgui}-color-contentgroup-border-main: #{$eccgui-color-scontentgroup-border-main};
diff --git a/src/components/ContextOverlay/ContextMenu.tsx b/src/components/ContextOverlay/ContextMenu.tsx
index b18c40c88..8e9a5a057 100644
--- a/src/components/ContextOverlay/ContextMenu.tsx
+++ b/src/components/ContextOverlay/ContextMenu.tsx
@@ -66,6 +66,8 @@ export const ContextMenu = ({
so by default we use the title attribute instead of Tooltip. */
tooltipAsTitle = true,
preventPlaceholder = false,
+ "data-test-id": dataTestId,
+ "data-testid": dataTestid,
...restProps
}: ContextMenuProps) => {
const toggleButton =
@@ -76,7 +78,8 @@ export const ContextMenu = ({
text={togglerText}
large={togglerLarge}
disabled={!!disabled}
- data-test-id={restProps["data-test-id"]}
+ data-test-id={dataTestId ?? undefined}
+ data-testid={dataTestid ?? undefined}
/>
) : (
(togglerElement as ReactElement)
diff --git a/src/components/ContextOverlay/ContextOverlay.tsx b/src/components/ContextOverlay/ContextOverlay.tsx
index 1d3991f93..7b3c884ed 100644
--- a/src/components/ContextOverlay/ContextOverlay.tsx
+++ b/src/components/ContextOverlay/ContextOverlay.tsx
@@ -2,6 +2,7 @@ import React from "react";
import {
Classes as BlueprintClasses,
Popover as BlueprintPopover,
+ PopoverInteractionKind as InteractionKind,
PopoverProps as BlueprintPopoverProps,
Utils as BlueprintUtils,
} from "@blueprintjs/core";
@@ -37,8 +38,11 @@ export const ContextOverlay = ({
usePlaceholder = false,
...otherPopoverProps
}: ContextOverlayProps) => {
- const placeholderRef = React.useRef(null);
- const eventMemory = React.useRef(undefined);
+ const placeholderRef = React.useRef(null);
+ const eventMemory = React.useRef(undefined);
+ const swapDelay = React.useRef(null);
+ const interactionKind = React.useRef(otherPopoverProps.interactionKind ?? InteractionKind.CLICK);
+ const swapDelayTime = 15;
const [placeholder, setPlaceholder] = React.useState(
// use placeholder only for "simple" overlays without special states
!otherPopoverProps.disabled &&
@@ -48,30 +52,85 @@ export const ContextOverlay = ({
usePlaceholder
);
+ const swap = (ev: MouseEvent | globalThis.FocusEvent) => {
+ const waitForClick =
+ interactionKind.current === InteractionKind.CLICK ||
+ interactionKind.current === InteractionKind.CLICK_TARGET_ONLY;
+
+ if (swapDelay.current) {
+ clearTimeout(swapDelay.current);
+ }
+
+ const replacePlaceholder = () => {
+ eventMemory.current = ev.type as "mouseenter" | "focusin" | "click";
+ setPlaceholder(false);
+ };
+
+ if (waitForClick) {
+ ev.stopImmediatePropagation();
+ replacePlaceholder();
+ return;
+ }
+
+ swapDelay.current = setTimeout(
+ replacePlaceholder,
+ // we delay the swap for hover/focus to prevent unwanted effects
+ // (e.g. event hickup after replacing elements when it is not really necessary)
+ swapDelayTime
+ );
+ };
+
React.useEffect(() => {
+ interactionKind.current = otherPopoverProps.interactionKind ?? InteractionKind.CLICK;
+ const waitForClick =
+ interactionKind.current === InteractionKind.CLICK ||
+ interactionKind.current === InteractionKind.CLICK_TARGET_ONLY;
+ const removeEvents = () => {
+ if (placeholderRef.current) {
+ placeholderRef.current.removeEventListener("click", swap);
+ placeholderRef.current.removeEventListener("mouseenter", swap);
+ placeholderRef.current.removeEventListener("focusin", swap);
+ }
+ return;
+ };
if (placeholderRef.current) {
- const swap = (ev: MouseEvent | globalThis.FocusEvent) => {
- eventMemory.current = ev.type === "focusin" ? "afterfocus" : "afterhover";
- setPlaceholder(false);
- };
- (placeholderRef.current as HTMLElement).addEventListener("mouseenter", swap);
- (placeholderRef.current as HTMLElement).addEventListener("focusin", swap);
+ removeEvents(); // remove events in case of interaction kind changed during existence
+ if (waitForClick) {
+ placeholderRef.current.addEventListener("click", swap);
+ } else {
+ placeholderRef.current.addEventListener("mouseenter", swap);
+ placeholderRef.current.addEventListener("focusin", swap);
+ }
return () => {
- if (placeholderRef.current) {
- (placeholderRef.current as HTMLElement).removeEventListener("mouseenter", swap);
- (placeholderRef.current as HTMLElement).removeEventListener("focusin", swap);
- }
+ removeEvents();
};
}
return () => {};
- }, [!!placeholderRef.current]);
+ }, [!!placeholderRef.current, otherPopoverProps.interactionKind]);
const refocus = React.useCallback((node) => {
- if (eventMemory.current === "afterfocus" && node) {
- const target = node.targetRef.current.children[0];
- if (target) {
+ const target = node?.targetRef.current.children[0];
+ if (!eventMemory.current || !target) {
+ return;
+ }
+ switch (eventMemory.current) {
+ case "focusin":
target.focus();
- }
+ break;
+ case "click":
+ target.click();
+ break;
+ case "mouseenter":
+ // re-check if the cursor is still over the element after swapping the placeholder before triggering the event to bubble up
+ (target as HTMLElement).addEventListener(
+ "mouseover",
+ () => (target as HTMLElement).dispatchEvent(new MouseEvent("mouseover", { bubbles: true })),
+ {
+ capture: true,
+ once: true,
+ }
+ );
+ break;
}
}, []);
@@ -87,7 +146,7 @@ export const ContextOverlay = ({
PlaceholderElement,
{
...otherPopoverProps?.targetProps,
- className: `${BlueprintClasses.POPOVER_TARGET} ${targetClassName}`,
+ className: `${BlueprintClasses.POPOVER_TARGET} ${targetClassName} ${eccgui}-contextoverlay__wrapper--placeholder`,
ref: placeholderRef,
},
React.cloneElement(childTarget, {
diff --git a/src/components/ContextOverlay/tests/ContextMenu.test.tsx b/src/components/ContextOverlay/tests/ContextMenu.test.tsx
new file mode 100644
index 000000000..e2c909521
--- /dev/null
+++ b/src/components/ContextOverlay/tests/ContextMenu.test.tsx
@@ -0,0 +1,43 @@
+import React from "react";
+import { fireEvent, render, screen } from "@testing-library/react";
+
+import "@testing-library/jest-dom";
+
+import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
+
+import ContextMenu from "./../ContextMenu";
+import { Default as ContextMenuStory } from "./../ContextMenu.stories";
+
+const overlayWrapper = `${eccgui}-contextoverlay`;
+const placeholderClass = `${overlayWrapper}__wrapper--placeholder`;
+
+const checkForPlaceholderClass = (container: HTMLElement, tobe: number) => {
+ expect(container.getElementsByClassName(placeholderClass).length).toBe(tobe);
+};
+
+describe("ContextMenu", () => {
+ it("should render placeholder automatically", () => {
+ const { container } = render( );
+ checkForPlaceholderClass(container, 1);
+ });
+ it("should not render placeholder when `preventPlaceholder===true`", () => {
+ const { container } = render( );
+ checkForPlaceholderClass(container, 0);
+ });
+ it("should render placeholder when `preventPlaceholder===false`", () => {
+ const { container } = render( );
+ checkForPlaceholderClass(container, 1);
+ });
+ it("if no placeholder is used the menu should be displayed on click", async () => {
+ const { container } = render( );
+ checkForPlaceholderClass(container, 0);
+ fireEvent.click(container.getElementsByClassName(overlayWrapper)[0]);
+ expect(await screen.findByText("First option")).toBeVisible();
+ });
+ it("if placeholder is used the menu should be displayed on click", async () => {
+ const { container } = render( );
+ checkForPlaceholderClass(container, 1);
+ fireEvent.click(container.getElementsByClassName(overlayWrapper)[0]);
+ expect(await screen.findByText("First option")).toBeVisible();
+ });
+});
diff --git a/src/components/ContextOverlay/tests/ContextOverlay.test.tsx b/src/components/ContextOverlay/tests/ContextOverlay.test.tsx
new file mode 100644
index 000000000..644cb137c
--- /dev/null
+++ b/src/components/ContextOverlay/tests/ContextOverlay.test.tsx
@@ -0,0 +1,71 @@
+import React from "react";
+import { PopoverInteractionKind } from "@blueprintjs/core";
+import { fireEvent, render, screen, waitFor } from "@testing-library/react";
+
+import "@testing-library/jest-dom";
+
+import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
+
+import ContextOverlay from "./../ContextOverlay";
+import { Default as ContextOverlayStory } from "./../ContextOverlay.stories";
+
+const overlayWrapper = `${eccgui}-contextoverlay`;
+const placeholderClass = `${overlayWrapper}__wrapper--placeholder`;
+
+const checkForPlaceholderClass = (container: HTMLElement, tobe: number) => {
+ expect(container.getElementsByClassName(placeholderClass).length).toBe(tobe);
+};
+
+describe("ContextOverlay", () => {
+ it("should not render placeholder automatically", () => {
+ const { container } = render( );
+ checkForPlaceholderClass(container, 0);
+ });
+ it("should render placeholder when `usePlaceholder===true`", () => {
+ const { container } = render( );
+ checkForPlaceholderClass(container, 1);
+ });
+ it("should render no placeholder when `usePlaceholder===false`", () => {
+ const { container } = render( );
+ checkForPlaceholderClass(container, 0);
+ });
+ it("if no placeholder is used the overlay should be displayed on click", async () => {
+ const { container } = render( );
+ fireEvent.click(container.getElementsByClassName(overlayWrapper)[0]);
+ expect(await screen.findByText("Overlay:")).toBeVisible();
+ });
+ it("if no placeholder is used the overlay should be displayed on hover (hover interactionKind)", async () => {
+ const { container } = render(
+
+ );
+ fireEvent.mouseEnter(container.getElementsByClassName(overlayWrapper)[0]);
+ expect(await screen.findByText("Overlay:")).toBeVisible();
+ });
+ it("if placeholder is used the overlay should be displayed on click", async () => {
+ const { container } = render( );
+ fireEvent.click(container.getElementsByClassName(overlayWrapper)[0]);
+ expect(await screen.findByText("Overlay:")).toBeVisible();
+ });
+ it("if placeholder is used the overlay should be displayed on hover (hover interactionKind)", async () => {
+ const { container } = render(
+
+ );
+ checkForPlaceholderClass(container, 1);
+ fireEvent.mouseEnter(container.getElementsByClassName(overlayWrapper)[0]);
+ await waitFor(async () => {
+ expect(screen.queryByDisplayValue("Overlay:")).toBeNull();
+ checkForPlaceholderClass(container, 0);
+ // we need to emulate another mouseover to simulate real user behaviour
+ fireEvent.mouseOver(container.getElementsByClassName(overlayWrapper)[0]);
+ expect(await screen.findByText("Overlay:")).toBeVisible();
+ });
+ });
+});
diff --git a/src/components/Dialog/Modal.tsx b/src/components/Dialog/Modal.tsx
index 9b0587045..e28e97295 100644
--- a/src/components/Dialog/Modal.tsx
+++ b/src/components/Dialog/Modal.tsx
@@ -5,11 +5,13 @@ import {
Overlay2Props as BlueprintOverlayProps,
} from "@blueprintjs/core";
+import { preventReactFlowActionsClasses } from "../../cmem";
import { utils } from "../../common";
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
import { TestableComponent } from "../interfaces";
import { Card } from "./../Card";
+import { ModalContext } from "./ModalContext";
export interface ModalProps extends TestableComponent, BlueprintOverlayProps {
children: React.ReactNode | React.ReactNode[];
@@ -20,7 +22,7 @@ export interface ModalProps extends TestableComponent, BlueprintOverlayProps {
/**
* Size of the modal.
*/
- size?: "tiny" | "small" | "regular" | "large" | "xlarge" | "fullscreen";
+ size?: ModalSize;
/**
* Prevents that a backdrop area is displayed behind the modal elements.
*/
@@ -42,8 +44,18 @@ export interface ModalProps extends TestableComponent, BlueprintOverlayProps {
* If this option is used inflationary then this could harm the visibility of other overlays.
*/
forceTopPosition?: boolean;
+ /**
+ * Modal ID that should be globally unique. If a ModalContext is provided this can be used to track opening/closing of this modal.
+ */
+ modalId?: string;
+ /**
+ * Prevents that pan and zooming actions of an existing react-flow instance are triggered while this Modal is open.
+ */
+ preventReactFlowEvents?: boolean;
}
+export type ModalSize = "tiny" | "small" | "regular" | "large" | "xlarge" | "fullscreen";
+
/**
* Displays contents on top of other elements, used to create dialogs.
* For most situations the usage of `SimpleDialog` and `AlertDialog` should be sufficient.
@@ -65,8 +77,24 @@ export const Modal = ({
onOpening,
"data-test-id": dataTestId,
"data-testid": dataTestid,
+ modalId,
+ preventReactFlowEvents = true,
...otherProps
}: ModalProps) => {
+ const modalContext = React.useContext(ModalContext)
+ const uniqueModalId = React.useRef(modalId ?? Date.now().toString(36) + Math.random().toString(36).substring(2))
+
+ React.useEffect(() => {
+ return () => {
+ // Make sure to always remove flag when modal is removed
+ modalContext.setModalOpen(uniqueModalId.current, false)
+ }
+ }, [])
+
+ React.useEffect(() => {
+ modalContext.setModalOpen(uniqueModalId.current, otherProps.isOpen)
+ }, [otherProps.isOpen])
+
const backdropProps: React.HTMLProps | undefined =
!canOutsideClickClose && canEscapeKeyClose
? {
@@ -114,7 +142,7 @@ export const Modal = ({
void;
+
+ /** The currently opened modals ordered by when they have been opened. Oldest coming first. */
+ openModalStack(): string[] | undefined;
+}
+
+/** Can be provided in the application to react to modal related changes. */
+export const ModalContext = React.createContext({
+ setModalOpen: () => {},
+ openModalStack: () => [],
+});
+
+/** Default implementation for modal context props.
+ * Tracks open modals in a stack representation.
+ **/
+export const useModalContext = (): ModalContextProps => {
+ // A stack of modal IDs. These should reflect a stacked opening of modals on top of each other.
+ const currentOpenModalStack = React.useRef([]);
+
+ const setOpenModalStack = ((stackUpdateFunction: (old: string[]) => string[]) => {
+ currentOpenModalStack.current = stackUpdateFunction([...currentOpenModalStack.current])
+ })
+
+ const setModalOpen = React.useCallback((modalId: string, isOpen: boolean) => {
+ setOpenModalStack(old => {
+ if (isOpen) {
+ return [...old, modalId];
+ } else {
+ const idx = old.findIndex((id) => modalId === id);
+ switch (idx) {
+ case -1:
+ // Trying to close modal that has not been registered as open!
+ return old;
+ case old.length - 1:
+ return old.slice(0, idx);
+ default:
+ // Modal in between is closed. Consider all modals after it also as closed.
+ return old.slice(0, idx);
+ }
+ }
+ });
+ }, []);
+
+ const openModalStack = React.useCallback(() => {
+ return currentOpenModalStack.current.length ? [...currentOpenModalStack.current] : undefined
+ }, [])
+
+ return {
+ openModalStack,
+ setModalOpen,
+ };
+};
diff --git a/src/components/Dialog/SimpleDialog.tsx b/src/components/Dialog/SimpleDialog.tsx
index f750b8c22..8e910c3d5 100644
--- a/src/components/Dialog/SimpleDialog.tsx
+++ b/src/components/Dialog/SimpleDialog.tsx
@@ -136,7 +136,8 @@ export const modalPreventEvents = {
onDrag: (event: BaseSyntheticEvent) => event.stopPropagation(),
onDragStart: (event: BaseSyntheticEvent) => event.stopPropagation(),
onDragEnd: (event: BaseSyntheticEvent) => event.stopPropagation(),
- onMouseDown: (event: BaseSyntheticEvent) => event.stopPropagation(),
+ // The following prevents some drop-downs to not close anymore when clicking outside of them
+ // onMouseDown: (event: BaseSyntheticEvent) => event.stopPropagation(),
onMouseUp: (event: BaseSyntheticEvent) => event.stopPropagation(),
onClick: (event: BaseSyntheticEvent) => event.stopPropagation(),
};
diff --git a/src/components/Dialog/dialog.scss b/src/components/Dialog/dialog.scss
index c1e72938d..f0c699418 100644
--- a/src/components/Dialog/dialog.scss
+++ b/src/components/Dialog/dialog.scss
@@ -11,7 +11,10 @@ $eccgui-size-modal-large-width: math.div(9, 16) * 100vw !default;
$eccgui-size-modal-large-height: math.div(6, 9) * 100vh !default;
$eccgui-size-modal-xlarge-width: math.div(12, 16) * 100vw !default;
$eccgui-size-modal-xlarge-height: math.div(7, 9) * 100vh !default;
-$eccgui-color-modal-backdrop: rgba(invert($eccgui-color-workspace-background), 0.69) !default;
+$eccgui-color-modal-backdrop: eccgui-color-rgba(
+ eccgui-color-var("identity", "background", "900"),
+ $eccgui-opacity-muted
+) !default;
@import "~@blueprintjs/core/src/components/dialog/dialog";
diff --git a/src/components/Dialog/index.ts b/src/components/Dialog/index.ts
index 6db73324f..1f831946a 100644
--- a/src/components/Dialog/index.ts
+++ b/src/components/Dialog/index.ts
@@ -1,3 +1,4 @@
export * from "./Modal";
export * from "./SimpleDialog";
export * from "./AlertDialog";
+export * from "./ModalContext";
diff --git a/src/components/Dialog/stories/Modal.stories.tsx b/src/components/Dialog/stories/Modal.stories.tsx
index 2b5452a5d..c306611c1 100644
--- a/src/components/Dialog/stories/Modal.stories.tsx
+++ b/src/components/Dialog/stories/Modal.stories.tsx
@@ -15,15 +15,18 @@ export default {
control: false,
},
},
+ decorators: [
+ (Story) => (
+
+
+
+
+
+ ),
+ ],
} as Meta;
-const Template: StoryFn = (args) => (
-
-
-
-
-
-);
+const Template: StoryFn = (args) => ;
export const Default = Template.bind({});
Default.args = {
diff --git a/src/components/Dialog/stories/ModalContext.stories.tsx b/src/components/Dialog/stories/ModalContext.stories.tsx
new file mode 100644
index 000000000..f5b90e7cf
--- /dev/null
+++ b/src/components/Dialog/stories/ModalContext.stories.tsx
@@ -0,0 +1,153 @@
+import React from "react";
+import { Classes, OverlaysProvider } from "@blueprintjs/core";
+import { Meta } from "@storybook/react";
+
+import {
+ Button,
+ Card,
+ CardContent,
+ Modal,
+ ModalContext,
+ ModalContextProps,
+ ModalSize,
+ Spacing,
+ useModalContext,
+} from "./../../../../index";
+
+/**
+ * `ModalContext` can be used as provider to track a stack of modals.
+ *
+ * ```(Javascript)
+ * import { ModalContext, SimpleDialog } from "@eccenca/gui-elements";
+ *
+ * const ContextTemplate = () => {
+ * const { setModalOpen, openModalStack } = useModalContext();
+ * return (
+ *
+ *
+ *
+ *
+ *
+ * );
+ * };
+ *
+ * const OtherModal = () => {
+ * const modalContext = React.useContext(ModalContext);
+ * return (
+ *
+ *
+ * {(modalContext.openModalStack ?? []).map((modalId, idx) => (
+ *
+ * {idx + 1}. {modalId}
+ *
+ * ))}
+ *
+ *
+ * );
+ * };
+ * ```
+ */
+export default {
+ title: "Components/Dialog/ModalContext",
+ decorators: [
+ (Story) => (
+
+
+
+
+
+ ),
+ ],
+} as Meta;
+
+export const Usage = () => {
+ const { setModalOpen, openModalStack } = useModalContext();
+
+ return (
+
+
+
+
+
+ );
+};
+
+const ModalContent = ({ children }: React.HTMLAttributes) => {
+ return (
+
+ {children}
+
+ );
+};
+
+/** Component for nested modals. */
+const ExampleModal = ({
+ id,
+ size,
+ children,
+}: {
+ id?: string;
+ size: ModalSize;
+ children?: React.HTMLAttributes["children"];
+}) => {
+ const [isOpen, setIsOpen] = React.useState(true);
+ const [portalElement, setPortalElement] = React.useState();
+
+ React.useEffect(() => {
+ setPortalElement(document.getElementById("modalPortal")!);
+ }, []);
+
+ return (
+ {
+ // workaround, Blueprint attach a class to body tht prevents scrolling, probably it is attached to the wrong portal
+ document.body.classList.remove(Classes.OVERLAY_OPEN);
+ }}
+ >
+
+ Modal with constant modal ID "{id}".
+
+
+
+ {children}
+
+ setIsOpen(false)}>
+ Close
+
+
+
+ );
+};
+
+const InnerModal = () => {
+ return ;
+};
+
+const MiddleModal = () => {
+ return (
+
+
+
+ );
+};
+
+/** Shows the current stack of open modals. */
+const TrackingContent = () => {
+ const modalContext = React.useContext(ModalContext);
+
+ return (
+
+ {(modalContext.openModalStack() ?? []).map((modalId, idx) => (
+
+ {idx + 1}. {modalId}
+
+ ))}
+
+ );
+};
diff --git a/src/components/Form/FieldItem.tsx b/src/components/Form/FieldItem.tsx
index f73f06b4f..252efcbef 100644
--- a/src/components/Form/FieldItem.tsx
+++ b/src/components/Form/FieldItem.tsx
@@ -5,40 +5,7 @@ import { CLASSPREFIX as eccgui } from "../../configuration/constants";
import { TestableComponent } from "../interfaces";
import Label, { LabelProps } from "../Label/Label";
-/*
- FIXME: Improve development convenience and prevent development errors
-
- * disabled state could be automatically forwarded to inserted input element,
- currently this need to be dome explicitly .
- * input id could be forwarded to label and input element
- * input id could be created when not given
-*/
-
export interface FieldItemProps extends React.HTMLAttributes, TestableComponent {
- /**
- * Set primary state.
- * This is not routed through automatically.
- * @deprecated (v25) use `intent="primary"` instead.
- */
- hasStatePrimary?: boolean;
- /**
- * Set success state.
- * This is not routed through automatically.
- * @deprecated (v25) use `intent="success"` instead.
- */
- hasStateSuccess?: boolean;
- /**
- * Set warning state.
- * This is not routed through automatically.
- * @deprecated (v25) use `intent="warning"` instead.
- */
- hasStateWarning?: boolean;
- /**
- * Set danger state.
- * This is not routed through automatically.
- * @deprecated (v25) use `intent="danger"` instead.
- */
- hasStateDanger?: boolean;
/**
* Intent state of the field item.
*/
@@ -69,10 +36,6 @@ export interface FieldItemProps extends React.HTMLAttributes, Te
* Form element that manages the combination of label, helper texts, input element and feedback messages.
*/
export const FieldItem = ({
- hasStatePrimary = false,
- hasStateSuccess = false,
- hasStateWarning = false,
- hasStateDanger = false,
children,
className,
disabled,
@@ -82,24 +45,6 @@ export const FieldItem = ({
intent,
...otherProps
}: FieldItemProps) => {
- let classIntent = "";
- switch (true) {
- case hasStatePrimary:
- classIntent = " " + IntentClassNames.PRIMARY;
- break;
- case hasStateSuccess:
- classIntent = " " + IntentClassNames.SUCCESS;
- break;
- case hasStateWarning:
- classIntent = " " + IntentClassNames.WARNING;
- break;
- case hasStateDanger:
- classIntent = " " + IntentClassNames.DANGER;
- break;
- default:
- break;
- }
-
const intentClass = intent ? " " + IntentClassNames[intent.toUpperCase()] : "";
const label = ;
@@ -117,9 +62,9 @@ export const FieldItem = ({
const notification =
messageText &&
(typeof messageText === "string" ? (
- {messageText}
+ {messageText}
) : (
- {messageText}
+ {messageText}
));
return (
diff --git a/src/components/Form/FieldSet.tsx b/src/components/Form/FieldSet.tsx
index d9814fa17..9e9fbaec5 100644
--- a/src/components/Form/FieldSet.tsx
+++ b/src/components/Form/FieldSet.tsx
@@ -9,26 +9,6 @@ export interface FieldSetProps extends Omit {
- let classIntent = "";
- switch (true) {
- case hasStatePrimary:
- classIntent = " " + IntentClassNames.PRIMARY;
- break;
- case hasStateSuccess:
- classIntent = " " + IntentClassNames.SUCCESS;
- break;
- case hasStateWarning:
- classIntent = " " + IntentClassNames.WARNING;
- break;
- case hasStateDanger:
- classIntent = " " + IntentClassNames.DANGER;
- break;
- default:
- break;
- }
-
- const intentClass = intent ? " " + IntentClassNames[intent.toUpperCase()] : "";
-
const userhelp =
helperText &&
(typeof helperText === "string" ? (
@@ -109,7 +65,7 @@ export const FieldSet = ({
className={
`${eccgui}-fieldset` +
(className ? " " + className : "") +
- (intentClass || classIntent) +
+ (intent ? " " + IntentClassNames[intent.toUpperCase()] : "") +
(boxed ? ` ${eccgui}-fieldset--boxed` : "")
}
{...otherProps}
diff --git a/src/components/Form/form.scss b/src/components/Form/form.scss
index 65c0ce3cc..508585c06 100644
--- a/src/components/Form/form.scss
+++ b/src/components/Form/form.scss
@@ -1,6 +1,6 @@
$eccgui-size-typo-formitem: $eccgui-size-typo-caption !default;
$eccgui-size-typo-formitem-lineheight: $eccgui-size-typo-caption-lineheight !default;
-$eccgui-color-formitem-text: rgba($eccgui-color-workspace-text, $eccgui-opacity-narrow);
+$eccgui-color-formitem-text: eccgui-color-rgba($eccgui-color-workspace-text, $eccgui-opacity-narrow);
@import "~@blueprintjs/core/src/components/forms/common";
@import "~@blueprintjs/core/src/components/forms/control-group";
@@ -39,7 +39,7 @@ form {
color: $eccgui-color-formitem-text;
.#{$eccgui}-fielditem--disabled > & {
- color: rgba($eccgui-color-formitem-text, 1) !important;
+ color: $eccgui-color-workspace-text !important;
opacity: $eccgui-opacity-disabled !important;
}
}
diff --git a/src/components/Icon/BaseIcon.tsx b/src/components/Icon/BaseIcon.tsx
index 7de20dbcd..ddb31eead 100644
--- a/src/components/Icon/BaseIcon.tsx
+++ b/src/components/Icon/BaseIcon.tsx
@@ -32,19 +32,10 @@ export interface BaseIconProps extends Omit>;
- /**
- * @deprecated (v25) Use `title` as replacement.
- */
- iconTitle?: CarbonIconProps["title"];
}
/**
@@ -58,8 +49,6 @@ function BaseIcon({
tooltipText,
tooltipProps,
intent,
- description,
- iconTitle,
tabIndex,
...restProps
}: BaseIconProps) {
@@ -70,9 +59,6 @@ function BaseIcon({
const icon = (
{
+ extends Omit, TestableComponent {
/**
* Canonical icon name, or an array of strings.
* In case of the array the first valid icon name is used.
diff --git a/src/components/Icon/canonicalIconNames.tsx b/src/components/Icon/canonicalIconNames.tsx
index 4f22e8ced..93ed7f87e 100644
--- a/src/components/Icon/canonicalIconNames.tsx
+++ b/src/components/Icon/canonicalIconNames.tsx
@@ -23,6 +23,19 @@ const canonicalIcons = {
"artefact-task-pivot": icons.Transpose,
"artefact-task-unpivot": icons.Transpose,
"artefact-task-concatenatetofile": icons.DocumentExport,
+ "artefact-task-sqlupdatequeryoperator": icons.Sql,
+ "artefact-task-customsqlexecution": icons.Sql,
+ "artefact-task-multitablemerge": icons.JoinFull,
+ "artefact-task-jsonparseroperator": icons.JsonReference,
+ "artefact-task-searchaddresses": icons.SearchLocate,
+ "artefact-task-sparkfunction": icons.Flash,
+ "artefact-task-eccencadataplatformgraphstorefileuploadoperator": icons.Upload,
+ "artefact-task-xsltoperator": icons.TransformCode,
+ "artefact-task-distinctby": icons.Filter,
+ "artefact-task-template": icons.Template,
+ "artefact-task-merge": icons.Connect,
+ "artefact-task-scheduler": icons.EventSchedule,
+ "artefact-task-sendemail": icons.Email,
"artefact-dataset-csv": icons.Csv,
"artefact-dataset-eccencadataplatform": icons.DataVis_1,
"artefact-dataset-excel": icons.Xls,
@@ -75,6 +88,7 @@ const canonicalIcons = {
"item-execution": icons.Run,
"item-info": icons.Information,
"item-launch": icons.Launch,
+ "item-legend": icons.Legend,
"item-moremenu": icons.OverflowMenuVertical,
"item-question": icons.Help,
"item-reload": icons.Renew,
@@ -92,8 +106,8 @@ const canonicalIcons = {
"item-hidedetails": icons.ViewOff,
"item-image": icons.Image,
- "list-sortasc": icons.ArrowDown,
- "list-sortdesc": icons.ArrowUp,
+ "list-sortasc": icons.ArrowUp,
+ "list-sortdesc": icons.ArrowDown,
"list-sort": icons.ArrowsVertical,
"module-accesscontrol": icons.UserAdmin,
@@ -145,6 +159,7 @@ const canonicalIcons = {
"operation-logout": icons.Logout,
"operation-magic": icons.MagicWand,
"operation-merge": icons.DirectionMerge,
+ "operation-tour": icons.Tour,
"operation-redo": icons.Redo,
"operation-search": icons.Search,
"operation-send": icons.Send,
@@ -159,9 +174,13 @@ const canonicalIcons = {
"state-confirmed": icons.ThumbsUp,
"state-danger": icons.ErrorFilled,
"state-declined": icons.ThumbsDown,
+ "state-flagged": icons.Flag,
"state-info": icons.InformationFilled,
"state-locked": icons.Locked,
"state-partlychecked": icons.CheckboxIndeterminate,
+ "state-progress": icons.InProgress,
+ "state-progress-error": icons.InProgressError,
+ "state-progress-warning": icons.InProgressWarning,
"state-protected": icons.DocumentProtected,
"state-success": icons.CheckmarkFilled,
"state-unchecked": icons.Checkbox,
@@ -169,13 +188,19 @@ const canonicalIcons = {
"state-warning": icons.WarningAltFilled,
"toggler-caret": icons.CaretSort,
+ "toggler-carettop": icons.CaretUp,
"toggler-caretright": icons.CaretRight,
"toggler-caretdown": icons.CaretDown,
+ "toggler-caretleft": icons.CaretLeft,
"toggler-maximize": icons.Maximize,
"toggler-minimize": icons.Minimize,
+ "toggler-micon": icons.Microphone,
+ "toggler-micoff": icons.MicrophoneOff,
"toggler-moveleft": icons.ChevronLeft,
"toggler-moveright": icons.ChevronRight,
"toggler-list": icons.List,
+ "toggler-radio": icons.RadioButton,
+ "toggler-radio-checked": icons.RadioButtonChecked,
"toggler-rowexpand": icons.RowExpand,
"toggler-rowcollapse": icons.RowCollapse,
"toggler-showless": icons.ChevronUp,
diff --git a/src/components/Icon/icon.scss b/src/components/Icon/icon.scss
index 755351c05..2285cf987 100644
--- a/src/components/Icon/icon.scss
+++ b/src/components/Icon/icon.scss
@@ -1,6 +1,12 @@
.#{$eccgui}-icon {
vertical-align: text-bottom;
+ &.#{$eccgui}-intent--primary {
+ color: $eccgui-color-primary;
+ }
+ &.#{$eccgui}-intent--accent {
+ color: $eccgui-color-accent;
+ }
&.#{$eccgui}-intent--info {
color: $eccgui-color-info-text;
}
diff --git a/src/components/Icon/stories/Icon.stories.tsx b/src/components/Icon/stories/Icon.stories.tsx
index 42652a9a5..1840f6cca 100644
--- a/src/components/Icon/stories/Icon.stories.tsx
+++ b/src/components/Icon/stories/Icon.stories.tsx
@@ -2,7 +2,18 @@ import React from "react";
import { OverlaysProvider } from "@blueprintjs/core";
import { Meta, StoryFn } from "@storybook/react";
-import { Button, Icon } from "../../../../index";
+import {
+ Card,
+ FlexibleLayoutContainer,
+ FlexibleLayoutItem,
+ Icon,
+ OverflowText,
+ OverviewItem,
+ OverviewItemDepiction,
+ OverviewItemDescription,
+ OverviewItemLine,
+ TitleSubsection,
+} from "../../../../index";
import { Definitions } from "../../../common/Intent";
import BaseIcon from "../BaseIcon";
@@ -19,7 +30,8 @@ export default {
},
intent: {
control: "select",
- options: { ...Definitions },
+ options: [...Object.keys(Definitions)],
+ mapping: { ...Definitions },
},
},
} as Meta;
@@ -49,12 +61,60 @@ IconSizes.args = {
name: "undefined",
};
+/**
+ * Available icons by their canonical names.
+ * If you need another icon then use ` component.
+ */
export const IconsOverview = () => {
+ let section = "";
+ let separation = <>>;
return (
- {Object.keys(canonicalIcons).map((iconName) => {
- return ;
- })}
+
+ {Object.keys(canonicalIcons)
+ .sort()
+ .map((iconName) => {
+ if (
+ section !==
+ iconName.substring(0, iconName.indexOf("-") > 0 ? iconName.indexOf("-") : iconName.length)
+ ) {
+ section = iconName.substring(
+ 0,
+ iconName.indexOf("-") > 0 ? iconName.indexOf("-") : iconName.length
+ );
+ separation = (
+
+ {section}
+
+ );
+ } else {
+ separation = <>>;
+ }
+ return (
+
+ {separation}
+
+
+
+
+
+
+
+
+ {iconName}
+
+
+
+
+
+
+ );
+ })}
+
);
};
diff --git a/src/components/Icon/stories/IconButton.stories.tsx b/src/components/Icon/stories/IconButton.stories.tsx
index d8e7478a1..9191ca7a1 100644
--- a/src/components/Icon/stories/IconButton.stories.tsx
+++ b/src/components/Icon/stories/IconButton.stories.tsx
@@ -5,13 +5,13 @@ import { Meta, StoryFn } from "@storybook/react";
import { IconButton, TestIcon } from "../../../../index";
+import buttonStory from "./../../Button/Button.stories";
import canonicalIcons from "./../canonicalIconNames";
export default {
title: "Components/IconButton",
component: IconButton,
argTypes: {
- text: { control: "text" },
name: {
control: "select",
options: ["Test icon", ...Object.keys(canonicalIcons)],
@@ -20,6 +20,7 @@ export default {
...Object.keys(canonicalIcons),
},
},
+ intent: buttonStory.argTypes?.intent,
},
} as Meta;
diff --git a/src/components/Label/label.scss b/src/components/Label/label.scss
index 6b1983845..a99781ece 100644
--- a/src/components/Label/label.scss
+++ b/src/components/Label/label.scss
@@ -1,7 +1,7 @@
$eccgui-size-typo-label: $eccgui-size-typo-caption !default;
$eccgui-size-typo-label-lineheight: $eccgui-size-typo-caption-lineheight !default;
$eccgui-color-label-text: $eccgui-color-workspace-text;
-$eccgui-color-label-info: rgba($eccgui-color-workspace-text, $eccgui-opacity-muted);
+$eccgui-color-label-info: eccgui-color-rgba($eccgui-color-workspace-text, $eccgui-opacity-muted);
.#{$eccgui}-label {
display: block;
diff --git a/src/components/Link/link.scss b/src/components/Link/link.scss
index 5af197571..d07676b68 100644
--- a/src/components/Link/link.scss
+++ b/src/components/Link/link.scss
@@ -11,7 +11,7 @@
}
&:focus-visible {
- outline: rgba($eccgui-color-accent, $eccgui-opacity-muted) solid 2px;
+ outline: eccgui-color-rgba($eccgui-color-accent, $eccgui-opacity-muted) solid 2px;
outline-offset: 1px;
}
}
diff --git a/src/components/Menu/menu.scss b/src/components/Menu/menu.scss
index 431bc386e..4cc1ca749 100644
--- a/src/components/Menu/menu.scss
+++ b/src/components/Menu/menu.scss
@@ -1,30 +1,7 @@
-// uses button colors, we can remove it if we decide to use the blueprint buttons
-$button-intents: (
- "primary": (
- $pt-intent-primary,
- $blue2,
- $blue1,
- ),
- "success": (
- $pt-intent-success,
- $green2,
- $green1,
- ),
- "warning": (
- $pt-intent-warning,
- $orange2,
- $orange1,
- ),
- "danger": (
- $pt-intent-danger,
- $red2,
- $red1,
- ),
-) !default;
-$minimal-button-background-color-hover: rgba($gray4, 0.3) !default;
-$minimal-button-background-color-active: rgba($gray2, 0.3) !default;
-$dark-minimal-button-background-color-hover: rgba($gray3, 0.15) !default;
-$dark-minimal-button-background-color-active: rgba($gray3, 0.3) !default;
+$minimal-button-background-color-hover: eccgui-color-rgba($gray4, 0.3) !default;
+$minimal-button-background-color-active: eccgui-color-rgba($gray2, 0.3) !default;
+$dark-minimal-button-background-color-hover: eccgui-color-rgba($gray3, 0.15) !default;
+$dark-minimal-button-background-color-active: eccgui-color-rgba($gray3, 0.3) !default;
// $half-grid-size: $pt-grid-size * 0.5 !default;
// $menu-item-border-radius: $pt-border-radius - 1 !default;
diff --git a/src/components/MultiSelect/MultiSelect.tsx b/src/components/MultiSelect/MultiSelect.tsx
index 6494ed91f..3685ed862 100644
--- a/src/components/MultiSelect/MultiSelect.tsx
+++ b/src/components/MultiSelect/MultiSelect.tsx
@@ -12,14 +12,13 @@ import { TestableComponent } from "../interfaces";
import { ContextOverlayProps, Highlighter, IconButton, MenuItem, OverflowText, Spinner } from "./../../index";
-/** @deprecated (v25) use MultiSuggestFieldSelectionProps */
-export interface MultiSelectSelectionProps {
+export interface MultiSuggestFieldSelectionProps {
newlySelected?: T;
selectedItems: T[];
createdItems: Partial[];
}
-interface MultiSelectCommonProps
+interface MultiSuggestFieldCommonProps
extends TestableComponent,
Pick, "items" | "placeholder" | "openOnKeyDown"> {
/**
@@ -38,7 +37,7 @@ interface MultiSelectCommonProps
/**
* function handler that would be called anytime an item is selected/deselected or an item is created/removed
*/
- onSelection?: (params: MultiSelectSelectionProps) => void;
+ onSelection?: (params: MultiSuggestFieldSelectionProps) => void;
/**
* Props to spread to `ContextOverlay`. Note that `content` cannot be changed.
*/
@@ -82,26 +81,6 @@ interface MultiSelectCommonProps
* Intent state of the multi select.
*/
intent?: BlueprintIntent;
- /**
- * The input element is displayed with primary color scheme.
- * @deprecated (v25) use `intent="primary"` instead.
- */
- hasStatePrimary?: boolean;
- /**
- * The input element is displayed with success (some type of green) color scheme.
- * @deprecated (v25) use `intent="success"` instead.
- */
- hasStateSuccess?: boolean;
- /**
- * The input element is displayed with warning (some type of orange) color scheme.
- * @deprecated (v25) use `intent="warning"` instead.
- */
- hasStateWarning?: boolean;
- /**
- * The input element is displayed with danger (some type of red) color scheme.
- * @deprecated (v25) use `intent="danger"` instead.
- */
- hasStateDanger?: boolean;
/**
* Disables the input element
*/
@@ -135,12 +114,12 @@ interface MultiSelectCommonProps
limitHeightOpened?: boolean | number;
}
-/** @deprecated (v25) use MultiSuggestFieldProps */
-export type MultiSelectProps = MultiSelectCommonProps &
+export type MultiSuggestFieldProps = MultiSuggestFieldCommonProps &
(
| {
/**
- * Predefined selected values
+ * Predefined selected values.
+ * `prePopulateWithItems` cannot be used then.
*/
selectedItems?: T[];
prePopulateWithItems?: never;
@@ -148,17 +127,22 @@ export type MultiSelectProps = MultiSelectCommonProps &
| {
selectedItems?: never;
/**
- * When set to true will set the multi-select value with all the items provided
+ * When set to `true` will set the multi-select value with all the items provided.
+ * `selectedItems` cannot be used then.
*/
prePopulateWithItems?: boolean;
}
);
/**
- * This component will be re-implemented as `Select` like element allowing multiple selections (or a `Select` option).
- * New name for this component is `MultiSuggestField`.
+ * Element behaves very similar to `SuggestField` but allows multiple selections.
+ * Its value does not represent a string but a stack of objects.
+ *
+ * Example usage: input field for user created tags.
+ *
+ * Attention: there may be another `MultiSelect` component in future but this will be a re-implemented `Select` like element allowing multiple selections.
*/
-function MultiSelect({
+export function MultiSuggestField({
items,
selectedItems: externalSelectedItems,
prePopulateWithItems,
@@ -173,10 +157,6 @@ function MultiSelect({
noResultText = "No results.",
newItemCreationText = "Add new item",
newItemPostfix = " (new item)",
- hasStatePrimary,
- hasStateDanger,
- hasStateSuccess,
- hasStateWarning,
disabled,
createNewItemFromQuery,
requestDelay = 0,
@@ -189,7 +169,7 @@ function MultiSelect({
limitHeightOpened,
intent,
...otherMultiSelectProps
-}: MultiSelectProps) {
+}: MultiSuggestFieldProps) {
// Options created by a user
const createdItems = useRef([]);
// Options passed ouside (f.e. from the backend)
@@ -212,24 +192,6 @@ function MultiSelect({
timeoutId?: number;
}>({});
- let stateIntent;
- switch (true) {
- case hasStatePrimary:
- stateIntent = BlueprintIntent.PRIMARY;
- break;
- case hasStateSuccess:
- stateIntent = BlueprintIntent.SUCCESS;
- break;
- case hasStateWarning:
- stateIntent = BlueprintIntent.WARNING;
- break;
- case hasStateDanger:
- stateIntent = BlueprintIntent.DANGER;
- break;
- default:
- break;
- }
-
/** Update external items when they change
* e.g for auto-complete when query change
*/
@@ -479,7 +441,8 @@ function MultiSelect({
) : undefined;
@@ -520,10 +483,10 @@ function MultiSelect({
"data-testid": dataTestid ? dataTestid + "_searchinput" : undefined,
...inputProps,
} as React.InputHTMLAttributes,
- className: `${eccgui}-multiselect` + (className ? ` ${className}` : ""),
+ className: `${eccgui}-multisuggestfield ${eccgui}-multiselect` + (className ? ` ${className}` : ""),
fill: fullWidth,
inputRef: inputRef,
- intent: intent || stateIntent,
+ intent: intent,
addOnBlur: true,
onKeyDown: handleOnKeyDown,
onKeyUp: handleOnKeyUp,
@@ -584,8 +547,8 @@ function MultiSelect({
// we still return the Blueprint element here because it was already used like that
/**
- * @deprecated (v25) use directly > (`ofType` also returns the original BlueprintJS element, not ours!)
+ * @deprecated (v26) use directly > (`ofType` also returns the original BlueprintJS element, not ours!)
*/
-MultiSelect.ofType = BlueprintMultiSelect.ofType;
+MultiSuggestField.ofType = BlueprintMultiSelect.ofType;
-export default MultiSelect;
+export default MultiSuggestField;
diff --git a/src/components/MultiSuggestField/MultiSuggestField.stories.tsx b/src/components/MultiSuggestField/MultiSuggestField.stories.tsx
index 94f9ce897..028c8b88c 100644
--- a/src/components/MultiSuggestField/MultiSuggestField.stories.tsx
+++ b/src/components/MultiSuggestField/MultiSuggestField.stories.tsx
@@ -29,7 +29,7 @@ export default {
component: MultiSuggestField,
argTypes: {
items: {
- control: "none",
+ control: false,
},
intent: {
...helpersArgTypes.exampleIntent,
diff --git a/src/components/MultiSuggestField/MultiSuggestField.tsx b/src/components/MultiSuggestField/MultiSuggestField.tsx
deleted file mode 100644
index 8fcd28853..000000000
--- a/src/components/MultiSuggestField/MultiSuggestField.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import React from "react";
-
-import { CLASSPREFIX as eccgui } from "../../configuration/constants";
-import MultiSelect, { MultiSelectProps, MultiSelectSelectionProps } from "../MultiSelect/MultiSelect";
-
-export type MultiSuggestFieldSelectionProps = MultiSelectSelectionProps;
-
-export interface MultiSuggestFieldProps extends Omit, "onSelection"> {
- /**
- * function handler that would be called anytime an item is selected/deselected or an item is created/removed
- */
- onSelection?: (params: MultiSuggestFieldSelectionProps) => void;
-}
-
-/**
- * Element behaves very similar to `SuggestField` but allows multiple selections.
- * Its value does not represent a string but a stack of objects.
- *
- * Example usage: input field for user created tags.
- */
-export function MultiSuggestField({ className, ...otherProps }: MultiSuggestFieldProps) {
- // Currently this works only as an alias element for `MultiSelect`.
- return (
-
- className={`${eccgui}-multisuggestfield` + (className ? ` ${className}` : "")}
- {...(otherProps as MultiSelectProps)}
- />
- );
-}
-
-// we still return the Blueprint element here because it was already used like that
-/**
- * @deprecated (v25) use directly > (`ofType` also returns the original BlueprintJS element, not ours!)
- */
-MultiSuggestField.ofType = MultiSelect.ofType;
diff --git a/src/components/MultiSuggestField/index.ts b/src/components/MultiSuggestField/index.ts
new file mode 100644
index 000000000..a4a03e2ff
--- /dev/null
+++ b/src/components/MultiSuggestField/index.ts
@@ -0,0 +1 @@
+export * from "./../MultiSelect/MultiSelect";
\ No newline at end of file
diff --git a/src/components/Notification/Notification.stories.tsx b/src/components/Notification/Notification.stories.tsx
index a0dd4fff1..6a346f066 100644
--- a/src/components/Notification/Notification.stories.tsx
+++ b/src/components/Notification/Notification.stories.tsx
@@ -1,16 +1,16 @@
import React from "react";
-import { LoremIpsum } from "react-lorem-ipsum";
+import { LoremIpsum, loremIpsum } from "react-lorem-ipsum";
import { Meta, StoryFn } from "@storybook/react";
import { helpersArgTypes } from "../../../.storybook/helpers";
-import { Button, HtmlContentBlock, Notification, Spacing } from "../../../index";
+import { Button, HtmlContentBlock, Markdown, Notification, Spacing } from "../../../index";
export default {
title: "Components/Notification",
component: Notification,
argTypes: {
message: {
- control: "none",
+ control: false,
},
icon: {
...helpersArgTypes.exampleIcon,
@@ -33,29 +33,43 @@ ExampleWithMessage.args = {
export const ExampleWithChildren = TemplateFull.bind({});
ExampleWithChildren.args = {
children: (
-
-
-
-
+ <>
+
+
+
+
+
+
+ {"```\n" + loremIpsum({ random: false }) + "\n```"}
+
+ >
),
onDismiss: false, // workaround for undefined function in Storybook
+ actions: [<>>],
};
export const ExampleNeutralMessage = TemplateFull.bind({});
ExampleNeutralMessage.args = {
message: ,
onDismiss: false, // workaround for undefined function in Storybook
- neutral: true,
+ intent: "neutral",
};
export const ExampleWithActions = TemplateFull.bind({});
ExampleWithActions.args = {
message: ,
onDismiss: false, // workaround for undefined function in Storybook
- danger: true,
+ intent: "danger",
actions: [
,
,
- ,
+ ,
],
};
diff --git a/src/components/Notification/Notification.tsx b/src/components/Notification/Notification.tsx
index aa8f75a5c..85809b942 100644
--- a/src/components/Notification/Notification.tsx
+++ b/src/components/Notification/Notification.tsx
@@ -29,29 +29,6 @@ export interface NotificationProps
* Intent state of the notification.
*/
intent?: Extract;
- /**
- * Notification has a neutral color scheme.
- * @deprecated (v25) use `intent="neutral"` instead.
- */
- neutral?: boolean;
- /**
- * Notification is a success info.
- * This defines the colorization and the icon symbol.
- * @deprecated (v25) use `intent="success"` instead.
- */
- success?: boolean;
- /**
- * Notification is a warning alert.
- * This defines the colorization and the icon symbol.
- * @deprecated (v25) use `intent="warning"` instead.
- */
- warning?: boolean;
- /**
- * Notification is a danger alert.
- * This defines the colorization and the icon symbol.
- * @deprecated (v25) use `intent="danger"` instead.
- */
- danger?: boolean;
/**
* Notification uses the the given space more flexible.
* Default notification is displayed in min and max limits.
@@ -79,42 +56,17 @@ export const Notification = ({
children,
className,
message,
- success = false,
- warning = false,
- danger = false,
- neutral = false,
flexWidth = false,
icon,
timeout,
wrapperProps,
"data-test-id": dataTestId,
"data-testid": dataTestid,
- intent,
+ intent = "info",
...otherProps
}: NotificationProps) => {
- let intentLevel: string = IntentClassNames.INFO;
- let iconSymbol = "state-info";
- switch (true) {
- case success:
- intentLevel = IntentClassNames.SUCCESS;
- iconSymbol = "state-success";
- break;
- case warning:
- intentLevel = IntentClassNames.WARNING;
- iconSymbol = "state-warning";
- break;
- case danger:
- intentLevel = IntentClassNames.DANGER;
- iconSymbol = "state-danger";
- break;
- case neutral:
- intentLevel = IntentClassNames.NEUTRAL;
- break;
- }
-
- const intents: Array = ["info", "success", "warning", "danger"];
const intentClass = intent ? " " + IntentClassNames[intent.toUpperCase()] : "";
- const intentIconSymbol = intents.includes(intent) ? `state-${intent}` : iconSymbol;
+ const intentIconSymbol = intent !== "neutral" ? `state-${intent}` : false;
let notificationIcon = icon !== false ? icon : undefined;
if (icon !== false && !notificationIcon && !!intentIconSymbol) {
@@ -136,7 +88,7 @@ export const Notification = ({
{
- /**
- * Displays the element using reduced height and less white space inside.
- * @deprecated (v25) use property directly on `OverviewItem` children.
- */
- densityHigh?: boolean;
/**
* Add a bit white space around each of the contained items.
*/
@@ -30,7 +25,6 @@ export interface OverviewItemListProps extends React.HTMLAttributes 1 ? `${eccgui}-overviewitem__list--hascolumns ` : "") + // FIXME: Support numbers > 2
diff --git a/src/components/OverviewItem/overviewitem.scss b/src/components/OverviewItem/overviewitem.scss
index 72daced37..41744f93f 100644
--- a/src/components/OverviewItem/overviewitem.scss
+++ b/src/components/OverviewItem/overviewitem.scss
@@ -76,16 +76,14 @@ $eccgui-size-overviewitem-line-typo-large-lineheight: $eccgui-size-typo-subtitle
}
}
-.#{$eccgui}-overviewitem__item--highdensity,
-.#{$eccgui}-overviewitem__list--highdensity > li > .#{$eccgui}-overviewitem__item {
+.#{$eccgui}-overviewitem__item--highdensity {
// same fix for Firefox v132+ like for the normal element height
- // height: $button-height; // mini-units(4);
min-height: $button-height;
max-height: $button-height;
& > .#{$eccgui}-overviewitem__depiction {
- width: $button-height; // mini-units(4);
- height: $button-height; // mini-units(4);
+ width: $button-height;
+ height: $button-height;
}
}
@@ -93,8 +91,7 @@ $eccgui-size-overviewitem-line-typo-large-lineheight: $eccgui-size-typo-subtitle
box-sizing: content-box;
padding: $eccgui-size-overviewitem-spacing * 0.5;
- &.#{$eccgui}-overviewitem__item--highdensity,
- .#{$eccgui}-overviewitem__list--highdensity > li > & {
+ &.#{$eccgui}-overviewitem__item--highdensity {
box-sizing: border-box;
& > .#{$eccgui}-overviewitem__depiction {
@@ -136,9 +133,9 @@ $eccgui-size-overviewitem-line-typo-large-lineheight: $eccgui-size-typo-subtitle
.#{$eccgui}-overviewitem__description {
display: flex;
- flex-direction: column;
flex-grow: 1;
flex-shrink: 1;
+ flex-direction: column;
place-content: stretch flex-start;
align-items: stretch;
overflow: hidden;
@@ -175,9 +172,9 @@ $eccgui-size-overviewitem-line-typo-large-lineheight: $eccgui-size-typo-subtitle
.#{$eccgui}-overviewitem__actions {
display: flex;
- flex-flow: row nowrap;
flex-grow: 0;
flex-shrink: 0;
+ flex-flow: row nowrap;
align-items: center;
justify-content: flex-end;
diff --git a/src/components/OverviewItem/stories/OverviewItemList.stories.tsx b/src/components/OverviewItem/stories/OverviewItemList.stories.tsx
index 9266e4d23..8ab7cf946 100644
--- a/src/components/OverviewItem/stories/OverviewItemList.stories.tsx
+++ b/src/components/OverviewItem/stories/OverviewItemList.stories.tsx
@@ -24,7 +24,6 @@ export const ItemList = Template.bind({});
ItemList.args = {
hasSpacing: true,
hasDivider: true,
- densityHigh: false,
columns: 1,
children: Array(4).fill( ),
};
diff --git a/src/components/Pagination/pagination.scss b/src/components/Pagination/pagination.scss
index e341fea7e..054e9e103 100644
--- a/src/components/Pagination/pagination.scss
+++ b/src/components/Pagination/pagination.scss
@@ -51,7 +51,7 @@ span.#{$prefix}--pagination__text {
.#{$prefix}--pagination__button--no-index {
// TODO: revalidate if this is still necessary using the latest version of carbon lib
- color: rgba($eccgui-color-workspace-text, $eccgui-opacity-disabled);
+ color: eccgui-color-rgba($eccgui-color-workspace-text, $eccgui-opacity-disabled);
}
.#{$eccgui}-pagination--hideinfotext {
diff --git a/src/components/ProgressBar/Stories/ProgressBar.stories.tsx b/src/components/ProgressBar/Stories/ProgressBar.stories.tsx
index 8a361494a..f180cc134 100644
--- a/src/components/ProgressBar/Stories/ProgressBar.stories.tsx
+++ b/src/components/ProgressBar/Stories/ProgressBar.stories.tsx
@@ -1,11 +1,17 @@
import React from "react";
import { Meta, StoryFn } from "@storybook/react";
+import { helpersArgTypes } from "../../../../.storybook/helpers";
import { ProgressBar } from "../../../../index";
export default {
title: "Components/ProgressBar",
component: ProgressBar,
- argTypes: {},
+ argTypes: {
+ intent: {
+ ...helpersArgTypes.exampleIntent,
+ options: ["UNDEFINED", "primary", "success", "warning", "danger"],
+ },
+ },
} as Meta;
const ProgressBarExample: StoryFn = (args) => ;
diff --git a/src/components/Select/Select.stories.tsx b/src/components/Select/Select.stories.tsx
index e6607a1e5..edcba80ec 100644
--- a/src/components/Select/Select.stories.tsx
+++ b/src/components/Select/Select.stories.tsx
@@ -53,7 +53,7 @@ export const ControlledTarget = Template.bind({});
ControlledTarget.args = {
...Default.args,
fill: false,
- children: ,
+ children: ,
onActiveItemChange: fn(),
};
diff --git a/src/components/Spinner/Spinner.tsx b/src/components/Spinner/Spinner.tsx
index 7ddbd0bfc..75413d3d1 100644
--- a/src/components/Spinner/Spinner.tsx
+++ b/src/components/Spinner/Spinner.tsx
@@ -1,29 +1,38 @@
import React, { useEffect, useState } from "react";
import {
- Overlay as BlueprintOverlay,
+ Overlay2 as BlueprintOverlay,
OverlayProps as BlueprintOverlayProps,
Spinner as BlueprintSpinner,
SpinnerProps as BlueprintSpinnerProps,
} from "@blueprintjs/core";
+import Color from "color";
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
+import { ButtonProps } from "./../Button/Button";
+
type SpinnerPosition = "local" | "inline" | "global";
type SpinnerSize = "tiny" | "small" | "medium" | "large" | "xlarge" | "inherit";
type SpinnerStroke = "thin" | "medium" | "bold";
-type Intent = "inherit" | "primary" | "success" | "warning" | "danger" | "none";
/** A spinner that is either displayed globally or locally. */
-export interface SpinnerProps extends Omit {
+export interface SpinnerProps extends Omit {
+ /**
+ * Must be a valid css color definition.
+ * `intent` property will always overwrite this setting.
+ */
+ color?: Color | string | "inherit";
/**
- * intent value or a valid css color definition
- * @deprecated (v25) it will allow in the future only a color value string and that for other states the intent property needs to be used
+ * Intent state of the spinner.
+ * When used the spinner is colored.
+ * Property overwrites `elevated` setting.
*/
- color?: Intent | string;
+ intent?: ButtonProps["intent"];
/**
- * Intent state of the field item.
+ * Highlight the spinner.
+ * It is displayed with accent color intent.
*/
- intent?: Intent;
+ elevated?: boolean;
/**
* Additional CSS class names.
*/
@@ -60,26 +69,19 @@ export interface SpinnerProps extends Omit {
const [showSpinner, setShowSpinner] = useState(!delay || delay <= 0);
@@ -90,7 +92,7 @@ export const Spinner = ({
}
return;
}, [showSpinner, delay]);
- const availableIntent = ["primary", "success", "warning", "danger", "inherit"];
+
const internSizes = {
thin: 100,
medium: 50,
@@ -99,9 +101,6 @@ export const Spinner = ({
const spinnerElement = position === "inline" ? "span" : "div";
- const spinnerColor = !intent && availableIntent.indexOf(color) < 0 ? color : null;
- const spinnerIntent = !intent && availableIntent.indexOf(color) < 0 ? "usercolor" : intent || color;
-
let spinnerSize;
let spinnerStroke;
switch (position) {
@@ -129,7 +128,8 @@ export const Spinner = ({
className={
`${eccgui}-spinner` +
` ${eccgui}-spinner--position-${position}` +
- ` ${eccgui}-spinner--intent-${spinnerIntent}` +
+ (elevated ? ` ${eccgui}-spinner--intent-accent` : "") +
+ (intent ? ` ${eccgui}-spinner--intent-${intent}` : "") +
` ${eccgui}-spinner--size-${spinnerSize}` +
(showLocalBackdrop ? ` ${eccgui}-spinner--localbackdrop` : "") +
(className ? " " + className : "")
@@ -138,8 +138,15 @@ export const Spinner = ({
/>
);
- if (spinnerColor && spinnerIntent === "usercolor") {
- spinner = {spinner} ;
+ if (!intent) {
+ try {
+ const spinnerColor = color === "inherit" ? color : Color(color).rgb().toString();
+ spinner = {spinner} ;
+ } catch {
+ spinner = {spinner} ;
+ // eslint-disable-next-line no-console
+ console.warn("Spinner received invalid color property: " + color);
+ }
}
return position === "global" ? (
diff --git a/src/components/Spinner/Stories/spinner.stories.tsx b/src/components/Spinner/Stories/spinner.stories.tsx
index a746cb270..e2c71a73d 100644
--- a/src/components/Spinner/Stories/spinner.stories.tsx
+++ b/src/components/Spinner/Stories/spinner.stories.tsx
@@ -10,7 +10,7 @@ export default {
color: { control: "color" },
intent: {
...helpersArgTypes.exampleIntent,
- options: ["UNDEFINED", "primary", "success", "warning", "danger", "none"],
+ options: ["UNDEFINED", "primary", "accent", "success", "warning", "danger", "none"],
},
position: { control: "radio", options: ["local", "inline", "global"] },
size: { control: "radio", options: ["tiny", "small", "medium", "large", "xlarge", "inherit"] },
diff --git a/src/components/Spinner/spinner.scss b/src/components/Spinner/spinner.scss
index 5ed97c194..43b77a486 100644
--- a/src/components/Spinner/spinner.scss
+++ b/src/components/Spinner/spinner.scss
@@ -15,12 +15,13 @@ $eccgui-size-spinner-xlarge: 256px !default;
stroke: currentcolor;
}
.#{$ns}-spinner-track {
- stroke: rgba(#000, 0.1);
+ stroke: eccgui-color-rgba($eccgui-color-workspace-text, $eccgui-opacity-ghostly);
}
}
span.#{$eccgui}-spinner {
display: inline-flex;
+ height: auto;
vertical-align: text-top;
}
@@ -28,10 +29,14 @@ span.#{$eccgui}-spinner {
color: inherit;
}
-.#{$eccgui}-spinner--intent-primary {
+.#{$eccgui}-spinner--intent-accent {
color: $eccgui-color-accent;
}
+.#{$eccgui}-spinner--intent-primary {
+ color: $eccgui-color-primary;
+}
+
.#{$eccgui}-spinner--intent-success {
color: $eccgui-color-success-text;
}
@@ -72,10 +77,10 @@ span.#{$eccgui}-spinner {
.#{$eccgui}-spinner--localbackdrop {
position: absolute;
inset: 0;
- background-color: rgba($eccgui-color-workspace-background, $eccgui-opacity-muted);
+ background-color: eccgui-color-rgba($eccgui-color-workspace-background, $eccgui-opacity-muted);
.#{$eccgui}-card & {
- background-color: rgba($card-background-color, $eccgui-opacity-muted);
+ background-color: eccgui-color-rgba($card-background-color, $eccgui-opacity-muted);
}
}
@@ -91,5 +96,5 @@ span.#{$eccgui}-spinner {
}
.#{$eccgui}-spinner__backdrop {
- background-color: rgba($eccgui-color-workspace-background, $eccgui-opacity-muted);
+ background-color: eccgui-color-rgba($eccgui-color-workspace-background, $eccgui-opacity-muted);
}
diff --git a/src/components/Sticky/sticky.scss b/src/components/Sticky/sticky.scss
index ca03cedf1..fa2553c6b 100644
--- a/src/components/Sticky/sticky.scss
+++ b/src/components/Sticky/sticky.scss
@@ -80,22 +80,22 @@
--eccgui-sticky-target-bgcolor: #{$card-background-color};
.#{$eccgui}-card.#{$eccgui}-intent--primary & {
- --eccgui-sticky-target-bgcolor: #{color.mix($eccgui-color-primary, $card-background-color, 5%)};
+ --eccgui-sticky-target-bgcolor: eccgui-color-var("identity", "brand", "100");
}
.#{$eccgui}-card.#{$eccgui}-intent--accent & {
- --eccgui-sticky-target-bgcolor: #{color.mix($eccgui-color-accent, $card-background-color, 10%)};
+ --eccgui-sticky-target-bgcolor: eccgui-color-var("identity", "accent", "100");
}
.#{$eccgui}-card.#{$eccgui}-intent--success & {
- --eccgui-sticky-target-bgcolor: #{$eccgui-color-success-background};
+ --eccgui-sticky-target-bgcolor: eccgui-color-var("semantic", "success", "100");
}
.#{$eccgui}-card.#{$eccgui}-intent--info & {
- --eccgui-sticky-target-bgcolor: #{$eccgui-color-info-background};
+ --eccgui-sticky-target-bgcolor: eccgui-color-var("semantic", "info", "100");
}
.#{$eccgui}-card.#{$eccgui}-intent--warning & {
- --eccgui-sticky-target-bgcolor: #{$eccgui-color-warning-background};
+ --eccgui-sticky-target-bgcolor: eccgui-color-var("semantic", "warning", "100");
}
.#{$eccgui}-card.#{$eccgui}-intent--danger & {
- --eccgui-sticky-target-bgcolor: #{$eccgui-color-danger-background};
+ --eccgui-sticky-target-bgcolor: eccgui-color-var("semantic", "danger", "100");
}
.#{$eccgui}-card.#{$ns}-interactive:hover & {
@@ -112,7 +112,7 @@
}
.#{$eccgui}-sticky__target--bg-application {
- --eccgui-sticky-target-bgcolor: #{$eccgui-color-application-background};
+ --eccgui-sticky-target-bgcolor: #{$eccgui-color-workspace-background};
}
.#{$eccgui}-sticky__target--issticky {
diff --git a/src/components/SuggestField/SuggestField.tsx b/src/components/SuggestField/SuggestField.tsx
deleted file mode 100644
index 6e9a811a9..000000000
--- a/src/components/SuggestField/SuggestField.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from "react";
-
-import { CLASSPREFIX as eccgui } from "../../configuration/constants";
-import AutoCompleteField, { AutoCompleteFieldProps } from "../AutocompleteField/AutoCompleteField";
-
-/**
- * Parameters for the auto-complete field parameterized by T and U.
- * @param T is the input data structure/type of the items that can be selected.
- * @param UPDATE_VALUE The value type that will be pushed into the onChange callback.
- */
-export type SuggestFieldProps = AutoCompleteFieldProps;
-
-/**
- * A component with the appearance of an input field that allows to select and optionally create new items.
- * It shows suggestions for the entered text from which the user can select any option.
- * It has the following fixed behavior:
- *
- * - When not focused, a different representation of the item value can be shown, e.g. the label of the value.
- * - When changing an existing item the input text is set to the original value in order to be able to edit the original value.
- * - When for a specific input text, the only item returns is the currently set item itself, all items are shown below it, to make
- * clear that there are still other items to choose from.
- * - The suggestions are fetched with a short delay, so not too many unnecessary requests are fired.
- * - Items where itemRenderer returns a string have a default representation, i.e. highlighting of search words, active flag etc.
- */
-export function SuggestField({ className, ...otherProps }: SuggestFieldProps) {
- // Currently this works only as an alias element for `AutoCompleteField`.
- return (
-
- className={`${eccgui}-suggestfield` + (className ? ` ${className}` : "")}
- {...otherProps}
- />
- );
-}
diff --git a/src/components/SuggestField/index.ts b/src/components/SuggestField/index.ts
index fa03542b9..8714d8626 100644
--- a/src/components/SuggestField/index.ts
+++ b/src/components/SuggestField/index.ts
@@ -1,5 +1,11 @@
import { createNewItemRendererFactory } from "./../AutocompleteField/autoCompleteFieldUtils";
-export * from "./SuggestField";
+
+export * from "./../AutocompleteField/AutoCompleteField";
+export * from "./../AutocompleteField/interfaces";
+
export const suggestFieldUtils = {
createNewItemRendererFactory,
};
+
+// @deprecated (v26) use `suggestFieldUtils`
+export const autoCompleteFieldUtils = suggestFieldUtils;
diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx
index 94fe7d4f7..0f2e9b828 100644
--- a/src/components/Table/Table.tsx
+++ b/src/components/Table/Table.tsx
@@ -4,8 +4,7 @@ import { DataTableSize as CarbonDataTableSize, Table as CarbonTable } from "@car
// import { TableProps as CarbonTableProps } from "@carbon/react/es/components/DataTable/Table"; // TODO: check later again, currently interface is not exported
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
-// @deprecated (v25) use `TableProps["size"]`
-export type TableRowHeightSize = "small" | "medium" | "large";
+type TableRowHeightSize = "small" | "medium" | "large";
// workaround to get type/interface
type CarbonTableProps = React.ComponentProps;
diff --git a/src/components/Table/TableContainer.tsx b/src/components/Table/TableContainer.tsx
index ad541f611..8e91322c1 100644
--- a/src/components/Table/TableContainer.tsx
+++ b/src/components/Table/TableContainer.tsx
@@ -9,7 +9,7 @@ import { TableContainerProps as CarbonTableContainerProps } from "@carbon/react/
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
-import { TableRowHeightSize, tableRowHeightSizes } from "./Table";
+import { TableProps, tableRowHeightSizes } from "./Table";
export interface TableDataContainerProps
extends Omit<
@@ -21,7 +21,7 @@ export interface TableDataContainerProps
>,
React.TableHTMLAttributes {
children(signature: any): JSX.Element;
- size?: TableRowHeightSize;
+ size?: TableProps["size"];
}
export interface TableSimpleContainerProps
extends Omit,
diff --git a/src/components/Table/table.scss b/src/components/Table/table.scss
index fe1856d13..1f9bd5223 100644
--- a/src/components/Table/table.scss
+++ b/src/components/Table/table.scss
@@ -21,15 +21,11 @@ $eccgui-size-tablecell-font-weight: $eccgui-font-weight-regular !default;
$eccgui-size-tableheader-font-weight: $eccgui-font-weight-bold !default;
$eccgui-color-table-background: $card-background-color !default;
$eccgui-color-tableheader-background: $button-background-color !default;
-$eccgui-color-tablerow-background-even: color.adjust($menu-item-color-hover, $lightness: 24%) !default;
+$eccgui-color-tablerow-background-even: eccgui-color-mix($menu-item-color-hover, $white 24%) !default;
$eccgui-color-tablerow-background-odd: transparent !default;
$eccgui-color-tablerow-hover: $menu-item-color-hover !default;
-$eccgui-color-tablerow-selected: rgba($eccgui-color-accent, 0.1) !default;
-$eccgui-color-tablerow-selected-hover: color.mix(
- $eccgui-color-tablerow-selected,
- $eccgui-color-tablerow-hover,
- 50%
-) !default;
+$eccgui-color-tablerow-selected: eccgui-color-var("identity", "accent", "100") !default;
+$eccgui-color-tablerow-selected-hover: eccgui-color-var("identity", "accent", "200") !default;
$eccgui-color-tablerow-border: $pt-divider-black !default;
// changes
@@ -168,11 +164,10 @@ $eccgui-color-tablerow-border: $pt-divider-black !default;
&.#{$prefix}--data-table--selected {
& > th {
- --#{$eccgui}-color-cell: #{color.mix(
- $eccgui-color-tablerow-selected,
- $eccgui-color-tableheader-background,
- 50%
- )};
+ --#{$eccgui}-color-cell: eccgui-color-mix(
+ #{$eccgui-color-tablerow-selected},
+ #{$eccgui-color-tableheader-background}
+ );
}
& > td {
@@ -181,11 +176,10 @@ $eccgui-color-tablerow-border: $pt-divider-black !default;
&:hover {
& > th {
- --#{$eccgui}-color-cell: #{color.mix(
- $eccgui-color-tablerow-selected-hover,
- $eccgui-color-tableheader-background,
- 50%
- )};
+ --#{$eccgui}-color-cell: eccgui-color-mix(
+ #{$eccgui-color-tablerow-selected-hover},
+ #{$eccgui-color-tableheader-background}
+ );
}
& > td {
@@ -219,46 +213,44 @@ $eccgui-color-tablerow-border: $pt-divider-black !default;
&.#{$prefix}--expandable-row--hover {
& > th,
& > td {
- --#{$eccgui}-color-cell: #{color.mix(
- $eccgui-color-tablerow-hover,
- $eccgui-color-tablerow-background-even,
- 50%
- )};
+ --#{$eccgui}-color-cell: eccgui-color-mix(
+ #{$eccgui-color-tablerow-hover},
+ #{$eccgui-color-tablerow-background-even}
+ );
}
}
&.#{$prefix}--data-table--selected {
& > th {
- --#{$eccgui}-color-cell: #{color.mix(
- color.mix($eccgui-color-tablerow-selected, $eccgui-color-tablerow-background-even, 50%),
- $eccgui-color-tableheader-background,
- 50%
- )};
+ --#{$eccgui}-color-cell: eccgui-color-mix(
+ eccgui-color-mix(#{$eccgui-color-tablerow-selected}, #{$eccgui-color-tablerow-background-even}),
+ #{$eccgui-color-tableheader-background}
+ );
}
& > td {
- --#{$eccgui}-color-cell: #{color.mix(
- $eccgui-color-tablerow-selected,
- $eccgui-color-tablerow-background-even,
- 50%
- )};
+ --#{$eccgui}-color-cell: eccgui-color-mix(
+ #{$eccgui-color-tablerow-selected},
+ #{$eccgui-color-tablerow-background-even}
+ );
}
&:hover {
& > th {
- --#{$eccgui}-color-cell: #{color.mix(
- color.mix($eccgui-color-tablerow-selected-hover, $eccgui-color-tablerow-background-even, 50%),
- $eccgui-color-tableheader-background,
- 50%
- )};
+ --#{$eccgui}-color-cell: eccgui-color-mix(
+ eccgui-color-mix(
+ #{$eccgui-color-tablerow-selected-hover},
+ #{$eccgui-color-tablerow-background-even}
+ ),
+ #{$eccgui-color-tableheader-background}
+ );
}
& > td {
- --#{$eccgui}-color-cell: #{color.mix(
- $eccgui-color-tablerow-selected-hover,
- $eccgui-color-tablerow-background-even,
- 50%
- )};
+ --#{$eccgui}-color-cell: eccgui-color-mix(
+ #{$eccgui-color-tablerow-selected-hover},
+ #{$eccgui-color-tablerow-background-even}
+ );
}
}
}
@@ -360,10 +352,6 @@ tr.#{$prefix}--parent-row.#{$prefix}--expandable-row + tr[data-child-row] {
}
.#{$prefix}--data-table--sticky-header {
- thead tr th {
- // border-bottom-color: $active-ui;
- }
-
tr {
min-height: $eccgui-size-tablecell-height-regular;
}
diff --git a/src/components/Tabs/Tab.tsx b/src/components/Tabs/Tab.tsx
index 4590953d2..7be3fd16f 100644
--- a/src/components/Tabs/Tab.tsx
+++ b/src/components/Tabs/Tab.tsx
@@ -40,8 +40,9 @@ export const transformTabProperties = ({
let color = Color("#ffffff");
try {
color = Color(backgroundColor);
- } catch (ex) {
- console.warn("Received invalid background color for tag: " + backgroundColor);
+ } catch {
+ // eslint-disable-next-line no-console
+ console.warn("Tag received invalid backgroundColor property: " + backgroundColor);
}
colorStyles = {
backgroundColor: `${color.rgb().toString()}`,
diff --git a/src/components/Tabs/stories/Tab.stories.tsx b/src/components/Tabs/stories/Tab.stories.tsx
index d7a567748..44ec92bdc 100644
--- a/src/components/Tabs/stories/Tab.stories.tsx
+++ b/src/components/Tabs/stories/Tab.stories.tsx
@@ -4,7 +4,7 @@ import { Meta, StoryFn } from "@storybook/react";
import { Tab as TabDummyForStorybook, Tabs } from "./../../../../";
export default {
- title: "Components/Tabs",
+ title: "Components/Tabs/Tab",
component: TabDummyForStorybook,
argTypes: {
backgroundColor: {
diff --git a/src/components/Tabs/stories/TabPanel.stories.tsx b/src/components/Tabs/stories/TabPanel.stories.tsx
index 0ba72f783..270a513ed 100644
--- a/src/components/Tabs/stories/TabPanel.stories.tsx
+++ b/src/components/Tabs/stories/TabPanel.stories.tsx
@@ -5,7 +5,7 @@ import { Meta, StoryFn } from "@storybook/react";
import { TabPanel } from "./../../../";
export default {
- title: "Components/Tabs",
+ title: "Components/Tabs/TabPanel",
component: TabPanel,
argTypes: {},
} as Meta;
diff --git a/src/components/Tabs/stories/TabTitle.stories.tsx b/src/components/Tabs/stories/TabTitle.stories.tsx
index 8bb53ba50..c4124754d 100644
--- a/src/components/Tabs/stories/TabTitle.stories.tsx
+++ b/src/components/Tabs/stories/TabTitle.stories.tsx
@@ -4,7 +4,7 @@ import { Meta, StoryFn } from "@storybook/react";
import { Tabs, TabTitle as TabTitleOrg } from "./../../../";
export default {
- title: "Components/Tabs",
+ title: "Components/Tabs/TabTitle",
component: TabTitleOrg,
argTypes: {},
} as Meta;
diff --git a/src/components/Tag/tag.scss b/src/components/Tag/tag.scss
index 458643ab9..2ef47acdb 100644
--- a/src/components/Tag/tag.scss
+++ b/src/components/Tag/tag.scss
@@ -7,19 +7,21 @@ $eccgui-size-margin-tag: $eccgui-size-inline-whitespace * 0.5 !default;
$eccgui-color-tag-background-emphasized: $eccgui-color-workspace-text !default;
// lib vars
-$tag-default-color: $eccgui-color-tag-background-emphasized; // !default;
+$tag-default-color: $eccgui-color-tag-background-emphasized;
+
// $dark-tag-default-color: $gray5 !default;
-$tag-height: $eccgui-size-typo-tag * $eccgui-size-typo-tag-lineheight; // !default;
-$tag-line-height: $eccgui-size-typo-tag; // !default;
-$tag-padding-top: ($tag-height - $tag-line-height) * 0.5; // !default;
-$tag-padding: $tag-padding-top * 2; // !default;
-$tag-margin: 0; // !default;
-$tag-height-small: $eccgui-size-typo-tag; // !default;
-$tag-line-height-small: $tag-height-small; // !default;
-$tag-padding-small: $tag-padding-top * 0.5; // !default;
-$tag-height-large: $eccgui-size-typo-tag-large * $eccgui-size-typo-tag-large-lineheight; // !default;
-$tag-line-height-large: $eccgui-size-typo-tag-large; // !default;
-$tag-padding-large: ($tag-height-large - $tag-line-height-large); // !default;
+$tag-height: $eccgui-size-typo-tag * $eccgui-size-typo-tag-lineheight;
+$tag-line-height: $eccgui-size-typo-tag;
+$tag-padding-top: ($tag-height - $tag-line-height) * 0.5;
+$tag-padding: $tag-padding-top * 2;
+$tag-margin: 0;
+$tag-height-small: $eccgui-size-typo-tag;
+$tag-line-height-small: $tag-height-small;
+$tag-padding-small: $tag-padding-top * 0.5;
+$tag-height-large: $eccgui-size-typo-tag-large * $eccgui-size-typo-tag-large-lineheight;
+$tag-line-height-large: $eccgui-size-typo-tag-large;
+$tag-padding-large: ($tag-height-large - $tag-line-height-large);
+
// $tag-icon-spacing: ($tag-height - 12px) * 0.5 !default;
// $tag-icon-spacing-large: ($tag-height-large - $pt-icon-size-standard) * 0.5 !default;
$tag-round-adjustment: 0 !default;
@@ -139,109 +141,128 @@ $tag-round-adjustment: 0 !default;
border-width: 1px;
&:not([class*="#{$ns}-intent-"]) {
+ --eccgui-tag-bg: #{$tag-default-color};
+ --eccgui-tag-border: #{$tag-default-color};
+ --eccgui-tag-text: #{eccgui-color-var("identity", "text", "100")};
+ --eccgui-tag-emfactor: 100%;
+
+ color: var(--eccgui-tag-text);
+ background-color: eccgui-color-mix(
+ var(--eccgui-tag-bg) var(--eccgui-tag-emfactor),
+ eccgui-color-var("identity", "background", "100")
+ );
+ border-color: var(--eccgui-tag-border);
+
&.#{$eccgui}-tag--strongeremphasis {
- background-color: rgba($tag-default-color, 1);
- border-color: rgba($tag-default-color, 1);
+ --eccgui-tag-emfactor: 95%;
}
&.#{$eccgui}-tag--strongemphasis {
- background-color: rgba($tag-default-color, 0.875);
- border-color: rgba($tag-default-color, 0.875);
+ --eccgui-tag-emfactor: 90%;
}
&.#{$eccgui}-tag--normalemphasis {
- background-color: rgba($tag-default-color, 0.75);
- border-color: rgba($tag-default-color, 0.75);
+ --eccgui-tag-emfactor: 85%;
}
&.#{$eccgui}-tag--weakemphasis {
- background-color: rgba($tag-default-color, 0.625);
- border-color: rgba($tag-default-color, 0.625);
+ --eccgui-tag-emfactor: 80%;
}
&.#{$eccgui}-tag--weakeremphasis {
- background-color: rgba($tag-default-color, 0.5);
- border-color: rgba($tag-default-color, 0.5);
+ --eccgui-tag-emfactor: 75%;
}
&.#{$eccgui}-intent--primary {
- color: $eccgui-color-primary-contrast;
- background-color: $eccgui-color-primary;
- border-color: $eccgui-color-primary;
+ --eccgui-tag-bg: #{$eccgui-color-primary};
+ --eccgui-tag-border: #{$eccgui-color-primary};
+ --eccgui-tag-text: #{$eccgui-color-primary-contrast};
}
&.#{$eccgui}-intent--accent {
- color: $eccgui-color-accent-contrast;
- background-color: $eccgui-color-accent;
- border-color: $eccgui-color-accent;
+ --eccgui-tag-bg: #{$eccgui-color-accent};
+ --eccgui-tag-border: #{$eccgui-color-accent};
+ --eccgui-tag-text: #{$eccgui-color-accent-contrast};
}
&.#{$eccgui}-intent--info {
- color: $eccgui-color-info-background;
- background-color: $eccgui-color-info-text;
- border-color: $eccgui-color-info-text;
+ --eccgui-tag-bg: #{$eccgui-color-info-text};
+ --eccgui-tag-border: #{$eccgui-color-info-text};
+ --eccgui-tag-text: #{$eccgui-color-info-background};
}
&.#{$eccgui}-intent--success {
- color: $eccgui-color-success-background;
- background-color: $eccgui-color-success-text;
- border-color: $eccgui-color-success-text;
+ --eccgui-tag-bg: #{$eccgui-color-success-text};
+ --eccgui-tag-border: #{$eccgui-color-success-text};
+ --eccgui-tag-text: #{$eccgui-color-success-background};
}
&.#{$eccgui}-intent--warning {
- color: $eccgui-color-warning-background;
- background-color: $eccgui-color-warning-text;
- border-color: $eccgui-color-warning-text;
+ --eccgui-tag-bg: #{$eccgui-color-warning-text};
+ --eccgui-tag-border: #{$eccgui-color-warning-text};
+ --eccgui-tag-text: #{$eccgui-color-warning-background};
}
&.#{$eccgui}-intent--danger {
- color: $eccgui-color-danger-background;
- background-color: $eccgui-color-danger-text;
- border-color: $eccgui-color-danger-text;
+ --eccgui-tag-bg: #{$eccgui-color-danger-text};
+ --eccgui-tag-border: #{$eccgui-color-danger-text};
+ --eccgui-tag-text: #{$eccgui-color-danger-background};
}
&.#{$ns}-minimal,
&.#{$ns}-minimal.#{$ns}-interactive {
+ --eccgui-tag-bg: #{eccgui-color-var("identity", "background", "500")};
+ --eccgui-tag-border: #{$tag-default-color};
+ --eccgui-tag-text: #{$tag-default-color};
+
+ color: var(--eccgui-tag-text);
+ background-color: eccgui-color-mix(
+ var(--eccgui-tag-bg) var(--eccgui-tag-emfactor),
+ eccgui-color-var("identity", "background", "100")
+ );
+ border-color: var(--eccgui-tag-border);
+
&.#{$eccgui}-tag--strongeremphasis {
- background-color: rgba(color.mix(rgba($tag-default-color, 0.3), #fff), 1);
- border-color: rgba($tag-default-color, 0.3);
+ --eccgui-tag-emfactor: 100%;
}
&.#{$eccgui}-tag--strongemphasis {
- background-color: rgba(color.mix(rgba($tag-default-color, 0.225), #fff), 0.875);
- border-color: rgba($tag-default-color, 0.225);
+ --eccgui-tag-emfactor: 90%;
}
&.#{$eccgui}-tag--normalemphasis {
- background-color: rgba(color.mix(rgba($tag-default-color, 0.15), #fff), 0.75);
- border-color: rgba($tag-default-color, 0.15);
+ --eccgui-tag-emfactor: 80%;
}
&.#{$eccgui}-tag--weakemphasis {
- background-color: rgba(color.mix(rgba($tag-default-color, 0.075), #fff), 0.625);
- border-color: rgba($tag-default-color, 0.075);
+ --eccgui-tag-emfactor: 70%;
}
&.#{$eccgui}-tag--weakeremphasis {
- background-color: rgba(color.mix(rgba($tag-default-color, 0), #fff), 0.5);
- border-color: rgba($tag-default-color, 0.15);
+ --eccgui-tag-emfactor: 60%;
+ }
+
+ &[class*="#{$eccgui}-intent--"] {
+ color: eccgui-color-rgba(var(--eccgui-tag-text), var(--eccgui-tag-emfactor));
+ border-color: eccgui-color-rgba(var(--eccgui-tag-border), var(--eccgui-tag-emfactor));
}
+
&.#{$eccgui}-intent--primary {
- color: $eccgui-color-primary;
- background-color: $eccgui-color-primary-contrast;
- border-color: $eccgui-color-primary;
+ --eccgui-tag-text: #{$eccgui-color-primary};
+ --eccgui-tag-border: #{$eccgui-color-primary};
+ --eccgui-tag-bg: #{$eccgui-color-primary-contrast};
}
&.#{$eccgui}-intent--accent {
- color: $eccgui-color-accent;
- background-color: $eccgui-color-accent-contrast;
- border-color: $eccgui-color-accent;
+ --eccgui-tag-text: #{$eccgui-color-accent};
+ --eccgui-tag-border: #{$eccgui-color-accent};
+ --eccgui-tag-bg: #{$eccgui-color-accent-contrast};
}
&.#{$eccgui}-intent--info {
- color: $eccgui-color-info-text;
- background-color: $eccgui-color-info-background;
- border-color: $eccgui-color-info-text;
+ --eccgui-tag-text: #{$eccgui-color-info-text};
+ --eccgui-tag-border: #{$eccgui-color-info-text};
+ --eccgui-tag-bg: #{$eccgui-color-info-background};
}
&.#{$eccgui}-intent--success {
- color: $eccgui-color-success-text;
- background-color: $eccgui-color-success-background;
- border-color: $eccgui-color-success-text;
+ --eccgui-tag-text: #{$eccgui-color-success-text};
+ --eccgui-tag-border: #{$eccgui-color-success-text};
+ --eccgui-tag-bg: #{$eccgui-color-success-background};
}
&.#{$eccgui}-intent--warning {
- color: $eccgui-color-warning-text;
- background-color: $eccgui-color-warning-background;
- border-color: $eccgui-color-warning-text;
+ --eccgui-tag-text: #{$eccgui-color-warning-text};
+ --eccgui-tag-border: #{$eccgui-color-warning-text};
+ --eccgui-tag-bg: #{$eccgui-color-warning-background};
}
&.#{$eccgui}-intent--danger {
- color: $eccgui-color-danger-text;
- background-color: $eccgui-color-danger-background;
- border-color: $eccgui-color-danger-text;
+ --eccgui-tag-text: #{$eccgui-color-danger-text};
+ --eccgui-tag-border: #{$eccgui-color-danger-text};
+ --eccgui-tag-bg: #{$eccgui-color-danger-background};
}
}
}
diff --git a/src/components/TextField/SearchField.tsx b/src/components/TextField/SearchField.tsx
index 5343617eb..eb5ca37f9 100644
--- a/src/components/TextField/SearchField.tsx
+++ b/src/components/TextField/SearchField.tsx
@@ -7,12 +7,7 @@ import IconButton from "../Icon/IconButton";
import TextField, { TextFieldProps } from "./TextField";
-export interface SearchFieldProps
- extends TestableComponent,
- Omit<
- TextFieldProps,
- "placeholder | hasStatePrimary | hasStateSuccess | hasStateWarning | hasStateDanger | fullWidth"
- > {
+export interface SearchFieldProps extends TestableComponent, Omit {
/**
* Placeholder text for search box.
*/
diff --git a/src/components/TextField/stories/SearchField.stories.tsx b/src/components/TextField/stories/SearchField.stories.tsx
index 7f25c166f..b25b486b0 100644
--- a/src/components/TextField/stories/SearchField.stories.tsx
+++ b/src/components/TextField/stories/SearchField.stories.tsx
@@ -15,10 +15,6 @@ export default {
rightElement: {
...helpersArgTypes.exampleIcon,
},
- hasStatePrimary: { table: { disable: true } },
- hasStateSuccess: { table: { disable: true } },
- hasStateWarning: { table: { disable: true } },
- hasStateDanger: { table: { disable: true } },
fullWidth: { table: { disable: true } },
},
} as Meta;
diff --git a/src/components/TextField/textfield.scss b/src/components/TextField/textfield.scss
index 633ab7e06..e7c673647 100644
--- a/src/components/TextField/textfield.scss
+++ b/src/components/TextField/textfield.scss
@@ -9,8 +9,9 @@ $eccgui-size-textfield-height-large: $eccgui-size-textfield-height-regular * $ec
$eccgui-size-textfield-padding-horizontal-regular: $eccgui-size-inline-whitespace !default;
$eccgui-size-textfield-padding-horizontal-small: $eccgui-size-inline-whitespace * 0.5 !default;
$eccgui-typo-textfield-fontweight: $eccgui-font-weight-regular !default;
-$eccgui-color-textfield-text: $eccgui-color-application-text !default;
-$eccgui-color-textfield-background: white !default; // TODO define global var for it
+$eccgui-color-textfield-text: $eccgui-color-workspace-text !default;
+$eccgui-color-textfield-background: eccgui-color-var("identity", "background", 100) !default;
+
// lib vars
$pt-input-height: $eccgui-size-textfield-height-regular; // !default;
$pt-input-height-large: $eccgui-size-textfield-height-large; // !default;
@@ -20,8 +21,8 @@ $input-small-padding: $eccgui-size-textfield-padding-horizontal-small; // !defau
$input-font-weight: $eccgui-typo-textfield-fontweight; // !default;
// $input-transition: box-shadow $pt-transition-duration $pt-transition-ease;
$input-color: $eccgui-color-textfield-text; // !default;
-$input-color-disabled: rgba($eccgui-color-textfield-text, 0.39); // !default;
-$input-placeholder-color: rgba($eccgui-color-textfield-text, 0.61); // !default;
+$input-color-disabled: eccgui-color-rgba($eccgui-color-textfield-text, 0.39); // !default;
+$input-placeholder-color: eccgui-color-rgba($eccgui-color-textfield-text, 0.61); // !default;
$input-background-color: $eccgui-color-textfield-background; // !default;
// $input-background-color-disabled: rgba($light-gray1, 0.5) !default;
// $input-shadow-color-focus: $pt-intent-primary !default;
@@ -84,15 +85,15 @@ $eccgui-map-intent-bgcolors: (
@mixin intent-state-flash-animation($state, $bgcolor, $mixratio: 24%) {
@keyframes intent-state-flash-#{$state} {
0% {
- background-color: color.mix($bgcolor, $eccgui-color-textfield-background, $mixratio);
+ background-color: eccgui-color-var("semantic", $state, "100");
}
39% {
- background-color: $bgcolor;
+ background-color: eccgui-color-var("semantic", $state, "300");
}
100% {
- background-color: color.mix($bgcolor, $eccgui-color-textfield-background, $mixratio);
+ background-color: eccgui-color-var("semantic", $state, "100");
}
}
}
@@ -109,7 +110,7 @@ $eccgui-map-intent-bgcolors: (
@each $each-intent, $each-bgcolor in $eccgui-map-intent-bgcolors {
.#{$ns}-input-group.#{$ns}-intent-#{$each-intent} & {
- background-color: color.mix($each-bgcolor, $eccgui-color-textfield-background, 24%);
+ background-color: eccgui-color-var("semantic", $each-intent, "100");
animation-name: intent-state-flash-#{$each-intent};
}
}
@@ -149,7 +150,7 @@ $eccgui-map-intent-bgcolors: (
@each $each-intent, $each-bgcolor in $eccgui-map-intent-bgcolors {
&.#{$eccgui}-intent--#{$each-intent} {
- background-color: color.mix($each-bgcolor, $eccgui-color-textfield-background, 24%);
+ background-color: eccgui-color-var("semantic", $each-intent, "100");
animation-name: intent-state-flash-#{$each-intent};
}
}
@@ -191,33 +192,40 @@ $eccgui-map-intent-bgcolors: (
position: absolute;
top: 0;
left: 0;
+ margin-top: -1 * $eccgui-size-textfield-padding-horizontal-small;
+ margin-right: -1 * $eccgui-size-textfield-padding-horizontal-small;
+
+ .#{$ns}-input.#{$ns}-small ~ & {
+ margin-top: -0.5 * $eccgui-size-textfield-padding-horizontal-small;
+ margin-right: -0.5 * $eccgui-size-textfield-padding-horizontal-small;
+ }
}
.#{$eccgui}-textarea__options {
position: absolute;
top: 0;
right: 0;
+ margin-top: -1 * $eccgui-size-textfield-padding-horizontal-small;
+ margin-right: -1 * $eccgui-size-textfield-padding-horizontal-small;
+ text-align: right;
filter: grayscale(1);
+ .#{$ns}-input.#{$ns}-small ~ & {
+ margin-top: -0.5 * $eccgui-size-textfield-padding-horizontal-small;
+ margin-right: -0.5 * $eccgui-size-textfield-padding-horizontal-small;
+ }
+
&:hover,
.#{$eccgui}-textarea:focus ~ & {
filter: none;
}
- & > .#{$eccgui}-button--icon {
- margin-top: -1 * $eccgui-size-textfield-padding-horizontal-regular;
-
- &:last-of-type {
- margin-right: -1 * $eccgui-size-textfield-padding-horizontal-regular;
- }
- }
-
- .#{$ns}-input.#{$ns}-small ~ & > .#{$eccgui}-button--icon {
- margin-top: -1 * $eccgui-size-textfield-padding-horizontal-small;
-
- &:last-of-type {
- margin-right: -1 * $eccgui-size-textfield-padding-horizontal-small;
- }
+ & > .#{$eccgui}-button,
+ & > .#{$eccgui}-icon,
+ & > .#{$eccgui}-contextoverlay,
+ & > .#{$eccgui}-tooltip__wrapper {
+ display: inline-block;
+ vertical-align: middle;
}
}
diff --git a/src/components/TextReducer/TextReducer.stories.tsx b/src/components/TextReducer/TextReducer.stories.tsx
index b81250463..48aa04684 100644
--- a/src/components/TextReducer/TextReducer.stories.tsx
+++ b/src/components/TextReducer/TextReducer.stories.tsx
@@ -18,8 +18,9 @@ Default.args = {
,
"Simple text with URL http://example.com/ that should not get parsed.",
"a < b to test equations in text like b > a.",
+ `Something with a "quote" in it.`,
<>
- {`* This\n* is\n* a\n* list\n\nwritten in Markdown.`}
+ {`* This\n* is\n* a\n* list\n\nwritten in Markdown\n* containing a few HTML 'entities' & "quotes".`}
Block with sub elements
diff --git a/src/components/TextReducer/TextReducer.test.tsx b/src/components/TextReducer/TextReducer.test.tsx
new file mode 100644
index 000000000..691adf2dd
--- /dev/null
+++ b/src/components/TextReducer/TextReducer.test.tsx
@@ -0,0 +1,44 @@
+import React from "react";
+import {render, RenderResult} from "@testing-library/react";
+
+import "@testing-library/jest-dom";
+
+import { Markdown, TextReducer } from "./../../";
+import { Default as TextReducerStory } from "./TextReducer.stories";
+
+describe("TextReducer", () => {
+ const textMustExist = (queryByText: RenderResult["queryByText"], text: string) => {
+ expect(queryByText(text, { exact: false })).not.toBeNull();
+ }
+ const textMustNotExist = (queryByText: RenderResult["queryByText"], text: string) => {
+ expect(queryByText(text, { exact: false })).toBeNull();
+ }
+ it("should display encoded HTML entities by default if they are used in the transformed markup", () => {
+ const { queryByText } = render( );
+ textMustExist(queryByText, "'entities' & "quotes"");
+ textMustNotExist(queryByText, `'entities' & "quotes"`);
+ });
+ it("should not display encoded HTML entities if `decodeHtmlEntities` is enabled", () => {
+ const { queryByText } = render( );
+ textMustNotExist(queryByText, "'entities' & "quotes"");
+ textMustExist(queryByText, `'entities' & "quotes"`);
+ });
+ it("should only decode if correct encoded HTML entities are found (strict mode)", () => {
+ const { queryByText } = render(
+
+ & & foo&bar
+
+ );
+ textMustExist(queryByText, "& & foo&bar");
+ textMustNotExist(queryByText, "& & foo&bar");
+ });
+ it("should allow decoding non-strict encoded HTML entities", () => {
+ const { queryByText } = render(
+
+ & & foo&bar
+
+ );
+ textMustNotExist(queryByText, "& & foo&bar");
+ textMustExist(queryByText, "& & foo&bar");
+ });
+});
diff --git a/src/components/TextReducer/TextReducer.tsx b/src/components/TextReducer/TextReducer.tsx
index d02fc02b8..b73d2ee96 100644
--- a/src/components/TextReducer/TextReducer.tsx
+++ b/src/components/TextReducer/TextReducer.tsx
@@ -1,7 +1,6 @@
import React from "react";
-import { renderToString } from "react-dom/server";
-import * as ReactIs from "react-is";
+import { DecodeHtmlEntitiesOptions, utils } from "../../common";
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
import { OverflowText, OverflowTextProps } from "./../Typography";
@@ -25,6 +24,17 @@ export interface TextReducerProps extends Pick
* Specify more `OverflowText` properties used when `useOverflowTextWrapper` is set to `true`.
*/
overflowTextProps?: Omit;
+ /**
+ * If you transform HTML markup to text then the result could contain HTML entity encoded strings.
+ * By enabling this option they are decoded back to it's original char.
+ */
+ decodeHtmlEntities?: boolean;
+ /**
+ * Set the options used to decode the HTML entities, if `decodeHtmlEntities` is enabled.
+ * Internally we use `he` library, see their [documentation on decode options](https://www.npmjs.com/package/he#hedecodehtml-options).
+ * If not set we use `{ isAttributeValue: true, strict: true }` as default value.
+ */
+ decodeHtmlEntitiesOptions?: DecodeHtmlEntitiesOptions;
}
/**
@@ -33,52 +43,15 @@ export interface TextReducerProps extends Pick
*/
export const TextReducer = ({
children,
- maxNodes,
- maxLength,
useOverflowTextWrapper,
overflowTextProps,
+ ...reduceToTextOptions
}: TextReducerProps) => {
- const nodesCount = 0;
-
- const onlyText = (children: React.ReactNode | React.ReactNode[], maxNodes?: number): string => {
- if (typeof maxNodes !== "undefined" && nodesCount >= maxNodes) {
- return "";
- }
-
- if (children instanceof Array) {
- return children
- .slice(0, maxNodes)
- .map((child: React.ReactNode) => {
- return onlyText(child, maxNodes);
- })
- .join(" ");
- }
-
- return React.Children.toArray(children)
- .slice(0, maxNodes)
- .map((child) => {
- if (ReactIs.isFragment(child)) {
- return onlyText(child.props?.children, maxNodes);
- }
- if (typeof child === "string") {
- return child;
- }
- if (typeof child === "number") {
- return child.toString();
- }
- if (ReactIs.isElement(child)) {
- // for some reasons `renderToString` returns empty string if not wrappe in a `span`
- return renderToString({child} );
- }
- return "";
- })
- .join(" ")
- .replaceAll("\n", " ");
- };
+ if (typeof children === "undefined") {
+ return <>>;
+ }
- const shrinkedContent = onlyText(children, maxNodes)
- .replaceAll(/<[^\s][^>]*>/g, "")
- .slice(0, maxLength);
+ const shrinkedContent = utils.reduceToText(children, reduceToTextOptions);
return useOverflowTextWrapper ? (
{
/**
* The size specifies the dimension the tooltip overlay element can maximal grow.
*/
- size?: "small" | "medium" | "large";
+ size?: TooltipSize;
/**
* The tooltip will be attached to this element when it is hovered.
*/
@@ -50,6 +50,8 @@ export interface TooltipProps extends Omit {
swapPlaceholderDelay?: number;
}
+export type TooltipSize = "small" | "medium" | "large"
+
export const Tooltip = ({
children,
content,
@@ -199,9 +201,10 @@ export const Tooltip = ({
targetProps={
{
...otherTooltipProps.targetProps,
- "data-postplaceholder": eventMemory.current
- ? `id${eventMemory.current}${searchId.current}`
- : undefined,
+ "data-postplaceholder":
+ eventMemory.current && searchId.current
+ ? `id${eventMemory.current}${searchId.current}`
+ : undefined,
} as React.HTMLProps
}
>
diff --git a/src/components/Tooltip/tooltip.scss b/src/components/Tooltip/tooltip.scss
index 460b62011..3e9678bee 100644
--- a/src/components/Tooltip/tooltip.scss
+++ b/src/components/Tooltip/tooltip.scss
@@ -6,8 +6,9 @@ $eccgui-size-typo-tooltip-lineheight: $eccgui-size-typo-caption-lineheight !defa
$eccgui-size-tooltip-width: 20em !default;
// library vars
-$tooltip-background-color: $eccgui-color-applicationheader-text; // !default;
-$tooltip-text-color: $eccgui-color-applicationheader-background; // !default;
+$tooltip-background-color: #{eccgui-color-var("layout", "grey", "900")};
+$tooltip-text-color: #{eccgui-color-var("identity", "text", "300")};
+
// $dark-tooltip-background-color: $light-gray3 !default;
// $dark-tooltip-text-color: $dark-gray5 !default;
$tooltip-padding-vertical: $eccgui-size-block-whitespace * 0.25; // !default;
@@ -45,7 +46,10 @@ $tooltip-padding-horizontal: $eccgui-size-block-whitespace * 0.5; // !default;
pre,
.#{$eccgui}-typography__contentblock pre,
pre.#{$eccgui}-typography__text {
- background-color: color.invert($eccgui-color-workspace-background);
+ background-color: eccgui-color-mix(
+ eccgui-color-var("identity", "background", "900") 100% * $eccgui-opacity-ghostly,
+ transparent
+ );
}
}
diff --git a/src/components/Typography/OverflowText.tsx b/src/components/Typography/OverflowText.tsx
index 6a707edbc..a5c55385e 100644
--- a/src/components/Typography/OverflowText.tsx
+++ b/src/components/Typography/OverflowText.tsx
@@ -1,7 +1,7 @@
import React from "react";
-import { CLASSPREFIX as eccgui } from "../../configuration/constants";
import { TestableComponent } from "../../components/interfaces";
+import { CLASSPREFIX as eccgui } from "../../configuration/constants";
export interface OverflowTextProps extends React.HTMLAttributes, TestableComponent {
/**
@@ -25,11 +25,6 @@ export interface OverflowTextProps extends React.HTMLAttributes, Te
* HTML element that is used for the component.
*/
useHtmlElement?: "p" | "div" | "span";
- /**
- * Used for all other necessary properties.
- * @deprecated (v25) we will allow only basic HTML element properties and testing IDs
- */
- [key: string]: any;
}
/** Prevents text from overflowing. */
diff --git a/src/components/Typography/typography.scss b/src/components/Typography/typography.scss
index 5a9eb7afc..d746b149d 100644
--- a/src/components/Typography/typography.scss
+++ b/src/components/Typography/typography.scss
@@ -53,7 +53,7 @@ mark {
styles from other stylesheets we cannot control here
TODO: need to reevaluated when it is not used together with MDL anymore
*/
- background-color: rgba($eccgui-color-info-background, 1) !important;
+ background-color: eccgui-color-rgba($eccgui-color-info-background, 1) !important;
}
// HtmlContentBlock
diff --git a/src/components/VisualTour/VisualTour.tsx b/src/components/VisualTour/VisualTour.tsx
new file mode 100644
index 000000000..095a7dff4
--- /dev/null
+++ b/src/components/VisualTour/VisualTour.tsx
@@ -0,0 +1,381 @@
+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 } from "../../configuration/constants";
+import {
+ Badge,
+ Button,
+ Card,
+ CardActions,
+ CardActionsAux,
+ CardContent,
+ CardHeader,
+ CardOptions,
+ CardTitle,
+ IconButton,
+ Markdown,
+ ModalSize,
+ SimpleDialog,
+ Spacing,
+ TooltipSize,
+} from "../../index";
+
+export interface VisualTourProps {
+ /** The steps of the tour. */
+ steps: VisualTourStep[];
+ /** Called when the tour is cancelled or closed at then end. This should usually remove the component from the outside. */
+ onClose: () => void;
+ /** Label of the button to close the tour. */
+ closeLabel?: string;
+ /** The label for the 'next' button. */
+ nextLabel?: string;
+ /** The label for the 'previous' button. */
+ prevLabel?: string;
+ /** The step target is usable, e.g. it can be clicked. */
+ usableStepTarget?: boolean;
+ /** Need to be set to `true` that the tour is displayed. */
+ isOpen?: boolean;
+}
+
+export interface VisualTourStep {
+ title: string;
+ /** The description or more elaborate content element that is shown in the modal/overlay. */
+ content: string | (() => React.JSX.Element);
+ /** Optional element that should be highlighted. The step content is displayed as a tooltip instead of a modal.
+ * In case of an array, the first match is highlighted. */
+ highlightElementQuery?: string | string[];
+ /** The texts used in the step, e.g. when custom layouts are rendered, these will be used for the text strings. */
+ texts?: Record;
+ /** An image URL. This will be displayed in the step description. */
+ image?: string;
+ /** The size of the tooltip or modal. */
+ size?: TooltipSize | ModalSize;
+ /** The step target is usable, e.g. it can be clicked. Overwrites the setting in ` `. */
+ usableStepTarget?: boolean;
+}
+
+/** This should be used for defining steps in a separate object/file. Use with 'satisfies' after the object definition. */
+export type VisualTourStepDefinitions = Record>;
+
+const highlightElementBaseClass = `${eccgui}-visual-tour__highlighted-element`;
+
+/** A visual tour multi-step tour of the current view. */
+export const VisualTour = ({
+ steps,
+ onClose,
+ closeLabel = "Close",
+ nextLabel = "Next",
+ prevLabel = "Back",
+ usableStepTarget = false,
+ isOpen = false,
+}: VisualTourProps) => {
+ if (isOpen === false) {
+ return null;
+ }
+
+ const [currentStepIndex, setCurrentStepIndex] = React.useState(0);
+ const [currentStepComponent, setCurrentStepComponent] = React.useState(null);
+
+ React.useEffect(() => {
+ const closeTour = () => {
+ // clear observer and disconnect
+ if (lastObserver) {
+ lastObserver.takeRecords();
+ lastObserver.disconnect();
+ }
+ // empty step
+ setCurrentStepComponent(null);
+ // remove highlight classes
+ document.querySelector(`.${highlightElementBaseClass}`)?.classList.remove(highlightElementBaseClass);
+ document
+ .querySelector(`.${highlightElementBaseClass}--useable`)
+ ?.classList.remove(`${highlightElementBaseClass}--useable`);
+ // call callback function from outside
+ onClose();
+ };
+
+ const step = steps[currentStepIndex];
+ if (!step) {
+ // This should not happen
+ closeTour();
+ return;
+ }
+ const highlightElementClass = (
+ typeof step["usableStepTarget"] === "undefined" ? usableStepTarget : step["usableStepTarget"]
+ )
+ ? `${highlightElementBaseClass}--useable`
+ : highlightElementBaseClass;
+ const hasNextStep = currentStepIndex + 1 < steps.length;
+ const hasPreviousStep = currentStepIndex > 0;
+ // Configure optional highlighting
+ let elementToHighlight: HTMLElement | null = null;
+ let lastObserver: MutationObserver | null = null;
+ const setStepComponent = () => {
+ const stepDisplay = (
+
+ {` ${currentStepIndex + 1}/${steps.length} `}
+
+ );
+ const closeButton = ;
+ const titleOptions = (
+ <>
+ {stepDisplay}
+ {closeButton}
+ >
+ );
+ const actionButtons = [
+ hasNextStep ? (
+ {
+ setCurrentStepIndex(currentStepIndex + 1);
+ }}
+ rightIcon={"navigation-next"}
+ >
+ {nextLabel}: {steps[currentStepIndex + 1].title}
+
+ ) : (
+
+ ),
+ hasPreviousStep ? (
+
+ {
+ setCurrentStepIndex(currentStepIndex - 1);
+ }}
+ icon={"navigation-previous"}
+ >
+ {prevLabel}
+
+
+ ) : null,
+ ];
+ // TODO: What to do if an element should have been highlighted, but none was found?
+ if (elementToHighlight) {
+ setCurrentStepComponent(
+
+ );
+ } else {
+ setCurrentStepComponent(
+
+ );
+ }
+ };
+ const addElementHighlighting = () => {
+ if (step.highlightElementQuery) {
+ const queries: string[] =
+ typeof step.highlightElementQuery === "string"
+ ? [step.highlightElementQuery]
+ : step.highlightElementQuery;
+ queries.forEach((query) => {
+ if (elementToHighlight == null) {
+ elementToHighlight = document.querySelector(query);
+ }
+ });
+ } else {
+ elementToHighlight = null;
+ }
+ if (elementToHighlight) {
+ // Typescript for some reason incorrectly infers the type of elementToHighlight as never
+ (elementToHighlight as HTMLElement).classList.add(highlightElementClass);
+ (elementToHighlight as HTMLElement).scrollIntoView({
+ behavior: "smooth",
+ block: "center",
+ });
+ if (lastObserver) {
+ lastObserver.disconnect();
+ }
+ lastObserver = new MutationObserver(function () {
+ // Re-new element highlighting
+ if (step.highlightElementQuery) {
+ if (!document.body.contains(elementToHighlight)) {
+ // Element has been removed or replaced
+ elementToHighlight = null;
+ addElementHighlighting();
+ } else if (!elementToHighlight?.classList.contains(highlightElementClass)) {
+ // Only the classes have been removed
+ elementToHighlight?.classList.add(highlightElementClass);
+ }
+ }
+ });
+ lastObserver.observe(document.body, { childList: true, subtree: true });
+ }
+ setStepComponent();
+ };
+ addElementHighlighting();
+ return () => {
+ // Remove previous element highlight
+ document.querySelector(`.${highlightElementClass}`)?.classList.remove(highlightElementClass);
+ if (lastObserver) {
+ lastObserver.disconnect();
+ }
+ };
+ }, [currentStepIndex, usableStepTarget]);
+
+ return currentStepComponent;
+};
+
+interface StepModalProps {
+ step: VisualTourStep;
+ // Current step starting with 1
+ titleOption: React.JSX.Element;
+ // Close the visual tour
+ onClose: () => void;
+ // The navigation buttons
+ actionButtons: (React.JSX.Element | null)[];
+}
+
+// Main content of a step
+const StepContent = ({ step }: { step: VisualTourStep }) => {
+ return (
+ <>
+ {step.image && (
+ <>
+
+
+ >
+ )}
+ {typeof step.content === "string" ? {step.content} : step.content()}
+ >
+ );
+};
+
+/** Modal that is displayed for a step. */
+const StepModal = ({ step, titleOption, onClose, actionButtons }: StepModalProps) => {
+ return (
+
+
+
+ );
+};
+
+interface StepPopoverProps {
+ highlightedElement: Element;
+ step: VisualTourStep;
+ // Current step starting with 1
+ titleOption: React.JSX.Element;
+ // The navigation buttons
+ actionButtons: (React.JSX.Element | null)[];
+}
+
+/** Popover that is displayed and points at the highlighted element. */
+const StepPopover = ({ highlightedElement, step, titleOption, actionButtons }: StepPopoverProps) => {
+ const tooltipRef = React.useCallback(
+ (tooltip: HTMLDivElement | null) => {
+ if (tooltip) {
+ createPopper(highlightedElement, tooltip, {
+ placement: "auto",
+ modifiers: [
+ {
+ name: "offset",
+ options: {
+ offset: [0, 15],
+ },
+ },
+ ],
+ });
+ }
+ },
+ [highlightedElement]
+ );
+
+ const backdropRef = React.useCallback(
+ (backdrop: HTMLDivElement | null) => {
+ const highlightStencil = () => {
+ const targetRect = highlightedElement.getBoundingClientRect();
+ backdrop!.style.left = `calc(${
+ targetRect.left + window.scrollX + "px"
+ } - var(--${eccgui}-visual-tour-focus-padding))`;
+ backdrop!.style.top = `calc(${
+ targetRect.top + window.scrollY + "px"
+ } - var(--${eccgui}-visual-tour-focus-padding))`;
+ backdrop!.style.width = `calc(${
+ targetRect.width + "px"
+ } + 2 * var(--${eccgui}-visual-tour-focus-padding))`;
+ backdrop!.style.height = `calc(${
+ targetRect.height + "px"
+ } + 2 * var(--${eccgui}-visual-tour-focus-padding))`;
+ };
+ if (backdrop) {
+ highlightStencil();
+ window.addEventListener("resize", highlightStencil);
+ return () => {
+ window.removeEventListener("resize", highlightStencil);
+ };
+ }
+ return;
+ },
+ [highlightedElement]
+ );
+
+ return createPortal(
+
+
+
+
+
+
+
+
+ {step.title}
+ {titleOption}
+
+
+
+
+ {actionButtons}
+
+
+
+
,
+ document.body
+ );
+};
+
+export default VisualTour;
diff --git a/src/components/VisualTour/stories/VisualTour.stories.tsx b/src/components/VisualTour/stories/VisualTour.stories.tsx
new file mode 100644
index 000000000..702434e15
--- /dev/null
+++ b/src/components/VisualTour/stories/VisualTour.stories.tsx
@@ -0,0 +1,112 @@
+import React from "react";
+import { Meta, StoryFn } from "@storybook/react";
+
+import {
+ Button,
+ Icon,
+ OverflowText,
+ OverviewItem,
+ OverviewItemDepiction,
+ OverviewItemDescription,
+ OverviewItemLine,
+ Toolbar,
+ ToolbarSection,
+ VisualTour,
+ VisualTourProps,
+} from "../../../../index";
+
+import stepDefinitionsEn from "./defaultTour";
+
+export default {
+ title: "Components/VisualTour",
+ component: VisualTour,
+ argTypes: {},
+} as Meta;
+
+const Template: StoryFn = (args: VisualTourProps) => {
+ const [isOpen, setIsOpen] = React.useState();
+
+ return (
+
+
+
+ Some text
+
+
+ Action A
+ Action B
+ setIsOpen(true)}>
+ Start tour!
+
+
+
+
+ Some other element for the tour.
+
+
+
+ Another element for the tour, not visible at first.
+
+
setIsOpen(false)}
+ isOpen={typeof isOpen !== "undefined" ? isOpen : args.isOpen}
+ />
+
+ );
+};
+
+const stepDefinitions = stepDefinitionsEn;
+
+export const Default = Template.bind({});
+const defaultArgs: VisualTourProps = {
+ steps: [
+ {
+ ...stepDefinitions.firstStep,
+ },
+ {
+ ...stepDefinitions.customContent,
+ content: () => {
+ const texts = stepDefinitions.customContent.texts;
+ return (
+
+
+
+
+
+
+ {texts.firstLine}
+
+
+ {texts.secondLine}
+
+
+
+ );
+ },
+ },
+ {
+ ...stepDefinitions.highlightElementA,
+ highlightElementQuery: "#actionA",
+ },
+ {
+ ...stepDefinitions.highlightElementB,
+ highlightElementQuery: "#actionB",
+ },
+ {
+ ...stepDefinitions.highlightElementLeft,
+ highlightElementQuery: "#textSection",
+ },
+ {
+ ...stepDefinitions.highlightElementC,
+ highlightElementQuery: "#actionC",
+ },
+ {
+ ...stepDefinitions.highlightElementD,
+ highlightElementQuery: "#actionD",
+ },
+ ],
+ onClose: () => {},
+ isOpen: false,
+};
+Default.args = defaultArgs;
diff --git a/src/components/VisualTour/stories/defaultTour.ts b/src/components/VisualTour/stories/defaultTour.ts
new file mode 100644
index 000000000..a6b0dd7d7
--- /dev/null
+++ b/src/components/VisualTour/stories/defaultTour.ts
@@ -0,0 +1,42 @@
+import { VisualTourStepDefinitions } from "../VisualTour";
+
+const definition = {
+ firstStep: {
+ title: "First step",
+ content: "This is a demonstration of a visual tour. A step can be simple text.",
+ },
+ customContent: {
+ title: "Custom content",
+ texts: {
+ firstLine: "Or a step can be arbitrary content that is displayed in a modal by default.",
+ secondLine: "The developer can choose what's appropriate.",
+ },
+ },
+ highlightElementA: {
+ title: "Highlight element A",
+ usableStepTarget: false,
+ content:
+ "It's possible to highlight specific elements on a page. The step content is then displayed in a kind of tooltip instead of a modal.",
+ },
+ highlightElementB: {
+ title: "Highlight element B",
+ usableStepTarget: true,
+ content: "Context overlay for another highlighted element.",
+ },
+ highlightElementLeft: {
+ title: "Highlight element on the left & portrait image",
+ image: "https://upload.wikimedia.org/wikipedia/commons/a/a3/Knowledge_graph_installation_at_the_Futurium_Berlin_21.jpg",
+ content: "The tooltip is placed where it is best seen by the user.",
+ },
+ highlightElementC: {
+ title: "Highlight element C & landscape image",
+ image: "https://upload.wikimedia.org/wikipedia/commons/1/15/Knowledge_graph_installation_at_the_Futurium_Berlin.jpg",
+ content: "Element outside tour container.",
+ },
+ highlightElementD: {
+ title: "Highlight element D",
+ content: "Element not visible at first.",
+ },
+} satisfies VisualTourStepDefinitions;
+
+export default definition;
diff --git a/src/components/VisualTour/visualTour.scss b/src/components/VisualTour/visualTour.scss
new file mode 100644
index 000000000..8b73875c7
--- /dev/null
+++ b/src/components/VisualTour/visualTour.scss
@@ -0,0 +1,83 @@
+.#{$eccgui}-visual-tour {
+ opacity: 1;
+
+ --#{$eccgui}-visual-tour-focus-padding: #{0.5 * $eccgui-size-block-whitespace};
+}
+
+[class*="#{$eccgui}-visual-tour__highlighted-element"] {
+ .#{$eccgui}-overviewitem__actions--hiddeninteractions:has(&) {
+ display: inherit;
+ }
+}
+
+.#{$eccgui}-visual-tour__highlighted-element--useable {
+ position: relative;
+ z-index: 999999 !important;
+}
+
+.#{$eccgui}-visual-tour__focushelper {
+ position: absolute;
+ z-index: 8001; // 1 over application header
+ box-sizing: border-box;
+ border: 2px solid $eccgui-color-accent;
+ border-radius: var(--#{$eccgui}-visual-tour-focus-padding);
+ box-shadow: 0 0 0 10000px $eccgui-color-modal-backdrop;
+}
+
+.#{$eccgui}-visual-tour__backdrop {
+ position: fixed;
+ inset: 0;
+ box-sizing: content-box;
+ opacity: 0;
+}
+
+.#{$eccgui}-visual-tour__arrow {
+ &::before {
+ background: $card-background-color;
+ }
+
+ .#{$eccgui}-visual-tour__overlay[data-popper-placement="top"] & {
+ bottom: -0.5 * $eccgui-size-block-whitespace;
+ }
+ .#{$eccgui}-visual-tour__overlay[data-popper-placement="right"] & {
+ left: -0.5 * $eccgui-size-block-whitespace;
+ }
+ .#{$eccgui}-visual-tour__overlay[data-popper-placement="bottom"] & {
+ top: -0.5 * $eccgui-size-block-whitespace;
+ }
+ .#{$eccgui}-visual-tour__overlay[data-popper-placement="left"] & {
+ right: -0.5 * $eccgui-size-block-whitespace;
+ }
+}
+
+.#{$eccgui}-visual-tour__overlay {
+ z-index: 8002; // 2 over application header
+ &--small {
+ @extend .#{$eccgui}-tooltip--small;
+ }
+
+ &--medium {
+ @extend .#{$eccgui}-tooltip--medium;
+ }
+
+ &--large {
+ @extend .#{$eccgui}-tooltip--large;
+ }
+}
+
+.#{$eccgui}-card__content {
+ .#{$eccgui}-visual-tour__overlay__content & {
+ max-height: 45vh;
+ }
+ .#{$eccgui}-visual-tour__overlay__content &,
+ .#{$eccgui}-visual-tour__dialog & {
+ img {
+ display: block;
+ width: auto;
+ max-width: 100%;
+ height: auto;
+ max-height: 40vh;
+ margin: 0 auto;
+ }
+ }
+}
diff --git a/src/components/index.scss b/src/components/index.scss
index 3e244f890..edd0976c4 100644
--- a/src/components/index.scss
+++ b/src/components/index.scss
@@ -35,6 +35,7 @@
@import "./TagInput/taginput";
@import "./Toolbar/toolbar";
@import "./Tooltip/tooltip";
+@import "./VisualTour/visualTour";
@import "./Tree/tree";
@import "./Typography/typography";
@import "./Workspace/workspace";
diff --git a/src/components/index.ts b/src/components/index.ts
index 980860bf0..6f7fdf95b 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -1,16 +1,13 @@
export * from "./Accordion";
export * from "./Application";
-export * from "./AutocompleteField";
-export * from "./SuggestField";
-export * from "./AutoSuggestion";
-export * from "./CodeAutocompleteField";
export * from "./Badge/Badge";
export * from "./Breadcrumb";
export * from "./Button/Button";
export * from "./Card";
export * from "./Chat";
export * from "./Checkbox/Checkbox";
-export * from "./TextReducer/TextReducer";
+export * from "./CodeAutocompleteField";
+export * from "./ContentGroup/ContentGroup";
export * from "./ContextOverlay";
export * from "./Depiction/Depiction";
export * from "./Dialog";
@@ -25,8 +22,7 @@ export * from "./Label/Label";
export * from "./Link/Link";
export * from "./List/List";
export * from "./Menu";
-export * from "./MultiSelect/MultiSelect";
-export * from "./MultiSuggestField/MultiSuggestField";
+export * from "./MultiSuggestField";
export * from "./Notification";
export * from "./OverviewItem";
export * from "./Pagination/Pagination";
@@ -40,16 +36,18 @@ export * from "./Skeleton/Skeleton";
export * from "./Spinner/Spinner";
export * from "./Sticky";
export * from "./Structure";
+export * from "./SuggestField";
export * from "./Switch/Switch";
export * from "./Table";
export * from "./Tabs";
export * from "./Tag";
export * from "./TextField";
+export * from "./TextReducer/TextReducer";
export * from "./Toolbar";
export * from "./Tooltip/Tooltip";
export * from "./Tree/Tree";
export * from "./Typography";
+export * from "./VisualTour/VisualTour";
export * from "./Workspace";
-export * from "./ContentGroup/ContentGroup";
export * from "./interfaces";
diff --git a/src/configuration/_libprefix.scss b/src/configuration/_libprefix.scss
new file mode 100644
index 000000000..73a4d21a0
--- /dev/null
+++ b/src/configuration/_libprefix.scss
@@ -0,0 +1 @@
+$eccgui: "eccgui" !default;
diff --git a/src/configuration/_palettes.scss b/src/configuration/_palettes.scss
new file mode 100644
index 000000000..6d2c1de5e
--- /dev/null
+++ b/src/configuration/_palettes.scss
@@ -0,0 +1,40 @@
+/**
+ * Base definition for colors.
+ * Can be overwritten if it is defined before this file is included.
+ * You need to define all or nothing, we currently don't support overwriting only some parts of it.
+ */
+
+$eccgui-color-palette-light: (
+ "identity": (
+ "brand": eccgui-create-color-tints(#fbead9 #f8cd99 #f6b966 #f4a533 #f29100),
+ "accent": eccgui-create-color-tints(#e5f4fb #aecfe3 #77abca #4186b2 #0a6199),
+ "text": eccgui-create-color-tints(#f8f8f8 #bcbcbc #818181 #434343 #090909),
+ "background": eccgui-create-color-tints(#fff #e8e8e8 #d6d6d6 #bfbfbf #a6a6a6),
+ ),
+ "semantic": (
+ "info": eccgui-create-color-tints(#e5f4fb #aecfe3 #77aaca #4086b2 #096199),
+ "success": eccgui-create-color-tints(#e8f5e9 #b1d4b7 #7ab286 #429154 #0b6f22),
+ "warning": eccgui-create-color-tints(#fff3e0 #fad2b3 #f5b287 #f0915a #eb702d),
+ "danger": eccgui-create-color-tints(#fff5f6 #edbfc0 #db8989 #c95253 #b71c1c),
+ ),
+ "layout": (
+ "yellow": eccgui-create-color-tints(#fff6d5 #f1ecb5 #e3db79 #d4c93c #a07d00),
+ "purple": eccgui-create-color-tints(#f8e9f7 #c8a2d1 #9d6eb8 #71378f #370e59),
+ "magenta": eccgui-create-color-tints(#ffeaf2 #f5a6c3 #e276a4 #be4c80 #8c1656),
+ "pink": eccgui-create-color-tints(#fde4f1 #e6b4ce #d08aae #bb5f8e #711c4d),
+ "violet": eccgui-create-color-tints(#f4e3f4 #d8b0d8 #b377b3 #904490 #6e1f6e),
+ "indigo": eccgui-create-color-tints(#efe4fb #b89ee0 #8f72c5 #6547aa #3b1e8f),
+ "petrol": eccgui-create-color-tints(#e7eef2 #b0c8d4 #7aa2b5 #437c97 #0c5678),
+ "cyan": eccgui-create-color-tints(#dff9fc #86d6e5 #5abfd4 #2da9c4 #006a8f),
+ "teal": eccgui-create-color-tints(#dff4ef #a3ddd3 #6dc0b2 #479d8d #104c42),
+ "lime": eccgui-create-color-tints(#e4f3ea #d2edd6 #9dcd99 #688a55 #5a7b2c),
+ "amber": eccgui-create-color-tints(#fff3d9 #ffe9c4 #f9cd8d #eeb757 #c77400),
+ "vermilion": eccgui-create-color-tints(#ffe8e2 #f5b8a8 #d48772 #8c4b3a #651c09),
+ "grey": eccgui-create-color-tints(#f5f6f7 #b7b7b7 #808080 #484848 #1c2329),
+ ),
+ "extra": (
+ "gold": eccgui-create-color-tints(#fff7d5 #ebd893 #dfc670 #d3b44e #c7a22b),
+ "silver": eccgui-create-color-tints(#f0f0f0 #dedede #ccc #bababa #a8a8a8),
+ "bronze": eccgui-create-color-tints(#fbe9db #f2d6bc #eac29d #e1af7e #d89b5f),
+ ),
+) !default;
diff --git a/src/configuration/_variables.scss b/src/configuration/_variables.scss
index 6f980db67..57d1e46cb 100644
--- a/src/configuration/_variables.scss
+++ b/src/configuration/_variables.scss
@@ -12,29 +12,30 @@
*/
@use "sass:math";
-
-$eccgui: "eccgui" !default;
+@use "sass:map";
+@use "sass:list";
+@import "palettes";
// -- Configuration stack of colors --------------------------------------------
-$eccgui-color-primary: rgb(254 143 1) !default;
-$eccgui-color-primary-contrast: rgb(255 255 255) !default;
-$eccgui-color-accent: rgb(10 103 163) !default;
-$eccgui-color-accent-contrast: rgb(255 255 255) !default;
-$eccgui-color-success-text: #1b5e20 !default;
-$eccgui-color-success-background: rgb(232 245 233) !default;
-$eccgui-color-info-text: rgb(21 101 192) !default;
-$eccgui-color-info-background: rgb(227 242 253) !default;
-$eccgui-color-warning-text: #e65100 !default;
-$eccgui-color-warning-background: rgb(255 243 224) !default;
-$eccgui-color-danger-text: #b71c1c !default;
-$eccgui-color-danger-background: rgb(255 235 238) !default;
-$eccgui-color-applicationheader-text: #222 !default;
-$eccgui-color-applicationheader-background: #ddd !default;
-$eccgui-color-workspace-text: #444 !default;
-$eccgui-color-workspace-background: #f5f5f5 !default;
-$eccgui-color-application-text: $eccgui-color-workspace-text !default; // deprecated
-$eccgui-color-application-background: $eccgui-color-workspace-background !default; // deprecated
+// @deprecated (v26) those variable cannot be set by other SCSS, the will only set here (no `default!` anymore)
+
+$eccgui-color-primary: eccgui-color-var("identity", "brand", "900") !default;
+$eccgui-color-primary-contrast: eccgui-color-var("identity", "brand", "100") !default;
+$eccgui-color-accent: eccgui-color-var("identity", "accent", "900") !default;
+$eccgui-color-accent-contrast: eccgui-color-var("identity", "accent", "100") !default;
+$eccgui-color-success-text: eccgui-color-var("semantic", "success", "900") !default;
+$eccgui-color-success-background: eccgui-color-var("semantic", "success", "100") !default;
+$eccgui-color-info-text: eccgui-color-var("semantic", "info", "900") !default;
+$eccgui-color-info-background: eccgui-color-var("semantic", "info", "100") !default;
+$eccgui-color-warning-text: eccgui-color-var("semantic", "warning", "900") !default;
+$eccgui-color-warning-background: eccgui-color-var("semantic", "warning", "100") !default;
+$eccgui-color-danger-text: eccgui-color-var("semantic", "danger", "900") !default;
+$eccgui-color-danger-background: eccgui-color-var("semantic", "danger", "100") !default;
+$eccgui-color-applicationheader-text: eccgui-color-var("identity", "text", "900") !default;
+$eccgui-color-applicationheader-background: eccgui-color-var("identity", "background", "500") !default;
+$eccgui-color-workspace-text: eccgui-color-var("identity", "text", "700") !default;
+$eccgui-color-workspace-background: eccgui-color-var("identity", "background", "300") !default;
// -- Configuration stack of typography ----------------------------------------
diff --git a/src/configuration/constants.ts b/src/configuration/constants.ts
index e2b79864a..a9171f0e8 100644
--- a/src/configuration/constants.ts
+++ b/src/configuration/constants.ts
@@ -1,2 +1,4 @@
// basic vars
export const CLASSPREFIX = "eccgui";
+export const COLORMINDISTANCE = 10;
+export const COLORMINCONTRAST = 4;
diff --git a/src/extensions/codemirror/CodeMirror.tsx b/src/extensions/codemirror/CodeMirror.tsx
index 4a65a525f..281394be4 100644
--- a/src/extensions/codemirror/CodeMirror.tsx
+++ b/src/extensions/codemirror/CodeMirror.tsx
@@ -1,6 +1,6 @@
import React, { useMemo, useRef } from "react";
import { defaultKeymap, indentWithTab } from "@codemirror/commands";
-import { foldKeymap } from "@codemirror/language";
+import { defaultHighlightStyle, foldKeymap } from "@codemirror/language";
import { EditorState, Extension, Compartment } from "@codemirror/state";
import { DOMEventHandlers, EditorView, KeyBinding, keymap, Rect, ViewUpdate } from "@codemirror/view";
import { minimalSetup } from "codemirror";
@@ -30,11 +30,13 @@ import {
adaptedHighlightSpecialChars,
adaptedLineNumbers,
adaptedLintGutter,
- adaptedPlaceholder, compartment,
+ adaptedPlaceholder,
+ compartment,
+ adaptedSyntaxHighlighting,
} from "./tests/codemirrorTestHelper";
import { ExtensionCreator } from "./types";
-export interface CodeEditorProps extends TestableComponent {
+export interface CodeEditorProps extends Omit, "translate" | "onChange" | "onKeyDown" | "onMouseDown" | "onScroll">, TestableComponent {
// Is called with the editor instance that allows access via the CodeMirror API
setEditorView?: (editor: EditorView | undefined) => void;
/**
@@ -53,9 +55,8 @@ export interface CodeEditorProps extends TestableComponent {
/**
* Handler method to receive onChange events.
* As input the new value is given.
- * @deprecated (v25) use `(v: string) => void` in future
*/
- onChange?: (v: any) => void;
+ onChange?: (v: string) => void;
/**
* Called when the focus status changes
*/
@@ -99,7 +100,11 @@ export interface CodeEditorProps extends TestableComponent {
/** Long lines are wrapped and displayed on multiple lines */
wrapLines?: boolean;
- outerDivAttributes?: Omit, "id" | "data-test-id">;
+ /**
+ * Add properties to the `div` used as warpper element.
+ * @deprecated (v26) You can now use all properties directly on `CodeEditor`.
+ */
+ outerDivAttributes?: Omit, "id" | "data-test-id" | "data-testid" | "translate" | "onChange" | "onKeyDown" | "onMouseDown" | "onScroll">;
/**
* Size in spaces that is used for a tabulator key.
@@ -185,6 +190,7 @@ const ModeToolbarSupport: ReadonlyArray = ["markdown"]
* Includes a code editor, currently we use CodeMirror library as base.
*/
export const CodeEditor = ({
+ className,
onChange,
onSelection,
onMouseDown,
@@ -212,7 +218,6 @@ export const CodeEditor = ({
enableTab = false,
height,
useLinting = false,
- "data-test-id": dataTestId,
autoFocus = false,
disabled = false,
intent,
@@ -353,6 +358,7 @@ export const CodeEditor = ({
wrapLinesCompartment.current.of(addExtensionsFor(wrapLines, EditorView?.lineWrapping)),
supportCodeFoldingCompartment.current.of(addExtensionsFor(supportCodeFolding, adaptedFoldGutter(), adaptedCodeFolding())),
useLintingCompartment.current.of(addExtensionsFor(useLinting, ...linters)),
+ adaptedSyntaxHighlighting(defaultHighlightStyle),
additionalExtensions,
];
@@ -488,14 +494,13 @@ export const CodeEditor = ({
// overwrite/extend some attributes
id={id ? id : name ? `codemirror-${name}` : undefined}
ref={parent}
- // @deprecated (v25) fallback with static test id will be removed
- data-test-id={dataTestId ? dataTestId : "codemirror-wrapper"}
+ {...otherCodeEditorProps}
className={
`${eccgui}-codeeditor ${eccgui}-codeeditor--mode-${mode}` +
+ (className ? ` ${className}` : "") +
(outerDivAttributes?.className ? ` ${outerDivAttributes?.className}` : "") +
(hasToolbarSupport ? ` ${eccgui}-codeeditor--has-toolbar` : "")
}
- {...otherCodeEditorProps}
>
{hasToolbarSupport && editorToolbar(mode)}
diff --git a/src/extensions/codemirror/_codemirror.scss b/src/extensions/codemirror/_codemirror.scss
index 583454c7b..dc010e56b 100644
--- a/src/extensions/codemirror/_codemirror.scss
+++ b/src/extensions/codemirror/_codemirror.scss
@@ -71,7 +71,7 @@ $eccgui-size-codeeditor-toolbar-height: $button-height !default;
@each $each-intent, $each-bgcolor in $eccgui-map-intent-bgcolors {
&.#{eccgui}-intent--#{$each-intent} {
- background-color: color.mix($each-bgcolor, $eccgui-color-textfield-background, 24%);
+ background-color: eccgui-color-mix($each-bgcolor 24%, $eccgui-color-textfield-background);
animation-name: intent-state-flash-#{$each-intent};
}
}
@@ -195,7 +195,7 @@ $eccgui-size-codeeditor-toolbar-height: $button-height !default;
&::after {
position: absolute;
left: 10%;
- color: rgba($eccgui-color-workspace-text, $eccgui-opacity-muted);
+ color: eccgui-color-rgba($eccgui-color-workspace-text, $eccgui-opacity-muted);
content: "⇥";
}
}
diff --git a/src/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.ts b/src/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.ts
index 8a429ae56..ad057c6bd 100644
--- a/src/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.ts
+++ b/src/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.ts
@@ -5,6 +5,8 @@ import { markdown } from "@codemirror/lang-markdown";
import { sql } from "@codemirror/lang-sql";
import { xml } from "@codemirror/lang-xml";
import { yaml } from "@codemirror/lang-yaml";
+import {html} from "@codemirror/lang-html"
+
import { defaultHighlightStyle, LanguageSupport, StreamLanguage, StreamParser } from "@codemirror/language";
//legacy mode imports
import { jinja2 } from "@codemirror/legacy-modes/mode/jinja2";
@@ -30,6 +32,7 @@ const supportedModes = {
mathematica,
sql,
javascript,
+ html
} as const;
export const supportedCodeEditorModes = Object.keys(supportedModes) as Array;
@@ -42,6 +45,7 @@ const v6AdaptedModes: ReadonlyMap = new Map([
["sql", true],
["yaml", true],
["javascript", true],
+ ["html", true]
]);
export const useCodeMirrorModeExtension = (mode?: SupportedCodeEditorModes) => {
diff --git a/src/extensions/react-flow/_config.scss b/src/extensions/react-flow/_config.scss
index d5855aaf4..296cfadc6 100644
--- a/src/extensions/react-flow/_config.scss
+++ b/src/extensions/react-flow/_config.scss
@@ -1,16 +1,22 @@
+$reactflow-background-color: $card-background-color !default;
$reactflow-node-basesize: $button-height !default;
$reactflow-node-largesize: mini-units(6) !default;
-$reactflow-node-border-color: $eccgui-color-workspace-text !default;
-$reactflow-node-background-color: $button-background-color !default;
+$reactflow-node-border-color: #{eccgui-color-var("identity", "text", "700")} !default;
+$reactflow-node-background-color: #{eccgui-color-var("layout", "grey", "100")} !default;
$reactflow-node-color: $eccgui-color-workspace-text !default;
$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-stroke-opacity-default: 0.6 !default;
-$reactflow-edge-stroke-opacity-hover: 0.8 !default;
-$reactflow-edge-stroke-opacity-selected: 1 !default;
-$reactflow-edge-stroke-color-default: $eccgui-color-workspace-text !default;
-$reactflow-edge-stroke-color-hover: $eccgui-color-workspace-text !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-opacity-default: $eccgui-opacity-muted !default;
+$reactflow-edge-stroke-opacity-hover: $eccgui-opacity-narrow !default;
+$reactflow-edge-stroke-opacity-selected: $eccgui-opacity-regular !default;
+$reactflow-edge-stroke-opacity-interaction-ratio: $eccgui-opacity-ghostly !default;
+$reactflow-edge-stroke-color-default: #{eccgui-color-var("identity", "text", "700")} !default;
+$reactflow-edge-stroke-color-hover: $reactflow-edge-stroke-color-default !default;
$reactflow-edge-stroke-color-selected: $eccgui-color-accent !default;
$reactflow-transition-time: 0.25s !default;
$reactflow-transition-function: "" !default;
diff --git a/src/extensions/react-flow/_react-flow.scss b/src/extensions/react-flow/_react-flow.scss
index 3a331543a..21f6f4f4e 100644
--- a/src/extensions/react-flow/_react-flow.scss
+++ b/src/extensions/react-flow/_react-flow.scss
@@ -1,10 +1,7 @@
@import "config";
@import "nodes/nodes";
@import "edges/edges";
+@import "markers/markers";
@import "handles/handles";
@import "minimap/minimap";
@import "react-flow_v12";
-
-.react-flow__background {
- border: solid 1px $eccgui-color-separation-divider;
-}
diff --git a/src/extensions/react-flow/_react-flow_v12.scss b/src/extensions/react-flow/_react-flow_v12.scss
index 9f3dd31e0..857acd992 100644
--- a/src/extensions/react-flow/_react-flow_v12.scss
+++ b/src/extensions/react-flow/_react-flow_v12.scss
@@ -1,12 +1,220 @@
-// needed styles from "@xyflow/react/dist/style.css" to ensure proper functionality
+/**
+ * We need some styles from "@xyflow/react/dist/style.css" to ensure proper functionality.
+ * Some of them are directly included to the component styles.
+ * Other stuff is here.
+ * Colors are removed or altered.
+ */
+
+.react-flow {
+ direction: ltr;
+ z-index: 0;
+}
+
+.react-flow__pane {
+ z-index: 1;
+}
+
+.react-flow__pane.draggable {
+ cursor: grab;
+}
+
+.react-flow__pane.dragging {
+ cursor: grabbing;
+}
+
+.react-flow__pane.selection {
+ cursor: pointer;
+}
+
+.react-flow__viewport {
+ z-index: 2;
+ pointer-events: none;
+ transform-origin: 0 0;
+}
+
+.react-flow__renderer {
+ z-index: 4;
+}
+
+.react-flow__selection {
+ z-index: 6;
+}
+
+.react-flow__controls {
+ display: flex;
+ flex-direction: column;
+}
+
+.react-flow__controls.horizontal {
+ flex-direction: row;
+}
+
+.react-flow__controls-button {
+ display: flex;
+ justify-content: center;
+ cursor: pointer;
+ user-select: none;
+}
+
+.react-flow__controls-button svg {
+ width: 100%;
+ max-width: 12px;
+ max-height: 12px;
+ fill: currentcolor;
+}
+
+.react-flow .react-flow__edges {
+ position: absolute;
+}
+
+.react-flow .react-flow__edges svg:not(.#{$eccgui}-icon) {
+ position: absolute;
+ overflow: visible;
+ pointer-events: none;
+}
+
+.react-flow__edge {
+ pointer-events: visiblestroke;
+}
+
+.react-flow__edge.inactive {
+ pointer-events: none;
+}
+
+.react-flow__edge-textwrapper {
+ pointer-events: all;
+}
+
+.react-flow__edge .react-flow__edge-text {
+ pointer-events: none;
+ user-select: none;
+}
+
+.react-flow__connection {
+ pointer-events: none;
+}
+
svg.react-flow__connectionline {
position: absolute;
z-index: 1001;
overflow: visible;
}
-.react-flow .react-flow__edges svg {
+.react-flow__nodes {
+ pointer-events: none;
+ transform-origin: 0 0;
+}
+
+.react-flow__node {
position: absolute;
- overflow: visible;
+ box-sizing: border-box;
+ pointer-events: all;
+ cursor: default;
+ user-select: none;
+ transform-origin: 0 0;
+}
+
+.react-flow__node.selectable {
+ cursor: pointer;
+}
+
+.react-flow__node.draggable {
+ pointer-events: all;
+ cursor: grab;
+}
+
+.react-flow__node.draggable.dragging {
+ cursor: grabbing;
+}
+
+.react-flow__nodesselection {
+ z-index: 3;
pointer-events: none;
+ transform-origin: left top;
+}
+
+.react-flow__nodesselection-rect {
+ position: absolute;
+ pointer-events: all;
+ cursor: grab;
+}
+
+.react-flow__handle.connectingfrom {
+ pointer-events: all;
+}
+
+.react-flow__handle.connectionindicator {
+ pointer-events: all;
+}
+
+.react-flow__edgeupdater {
+ pointer-events: all;
+ cursor: move;
+}
+
+.react-flow__minimap-svg {
+ display: block;
+}
+
+.react-flow__node.selectable:focus,
+.react-flow__node.selectable:focus-visible {
+ outline: none;
+}
+
+.react-flow__nodesselection-rect:focus,
+.react-flow__nodesselection-rect:focus-visible,
+.react-flow__selection:focus,
+.react-flow__selection:focus-visible {
+ outline: none;
+}
+
+.react-flow__controls-button:disabled {
+ pointer-events: none;
+}
+
+// -- adjustments
+
+.react-flow__background {
+ z-index: -1;
+ pointer-events: none;
+ background-color: $reactflow-background-color;
+ border: solid 1px $eccgui-color-separation-divider;
+}
+
+.react-flow__background-pattern,
+.react-flow__background pattern *:first-child:not(.react-flow__background-pattern) {
+ opacity: $eccgui-opacity-muted;
+ stroke: $eccgui-color-separation-divider;
+}
+
+.react-flow__background-pattern.dots,
+.react-flow__background pattern circle:first-child:not(.react-flow__background-pattern) {
+ fill: #{eccgui-color-var("identity", "text", "500")};
+}
+
+.react-flow__background-pattern.cross {
+ opacity: $eccgui-opacity-disabled;
+ stroke: #{eccgui-color-var("identity", "text", "500")};
+ stroke-width: 0.3;
+}
+
+.react-flow__background-pattern.lines {
+ stroke-width: 0.4;
+}
+
+.react-flow__attribution {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ z-index: 10;
+ padding: $eccgui-size-inline-whitespace * 0.5 $eccgui-size-inline-whitespace;
+ margin: 0;
+ font-size: $eccgui-size-typo-caption * 0.61;
+ background: transparent;
+ opacity: $eccgui-opacity-muted;
+}
+
+.react-flow__attribution a {
+ color: $eccgui-color-workspace-text;
+ text-decoration: none;
}
diff --git a/src/extensions/react-flow/edges/EdgeBezier.tsx b/src/extensions/react-flow/edges/EdgeBezier.tsx
new file mode 100644
index 000000000..f86419336
--- /dev/null
+++ b/src/extensions/react-flow/edges/EdgeBezier.tsx
@@ -0,0 +1,47 @@
+import React, { memo } from "react";
+import { Edge, EdgeProps, getBezierPath } from "@xyflow/react";
+
+import { ReactFlowVersions, useReactFlowVersion } from "../versionsupport";
+
+import { EdgeDefault, EdgeDefaultV9Props } from "./EdgeDefault";
+import { EdgeDefaultV12DataProps, EdgeDefaultV12Props } from "./EdgeDefaultV12";
+
+interface EdgeBezierDataV12Props extends EdgeDefaultV12DataProps {
+ curvature?: number;
+}
+
+/**
+ * @deprecated (v26) v9 support is removed after v25
+ */
+export interface EdgeBezierV12Props
+ extends Omit,
+ EdgeProps> {}
+
+export type EdgeBezierProps = EdgeDefaultV9Props | EdgeBezierV12Props;
+
+/**
+ * This element cannot be used directly, it must be connected via a `edgeTypes` definition.
+ * Our v9 edges do not support bezier paths.
+ * @see https://reactflow.dev/docs/api/nodes/
+ */
+export const EdgeBezier = memo((props: EdgeBezierProps) => {
+ const flowVersionCheck = useReactFlowVersion();
+ switch (flowVersionCheck) {
+ case ReactFlowVersions.V9:
+ return ;
+ case ReactFlowVersions.V12:
+ return (
+ {
+ return getBezierPath({
+ ...params,
+ curvature: (props.data as EdgeBezierDataV12Props)?.curvature,
+ });
+ }}
+ />
+ );
+ default:
+ return <>>;
+ }
+});
diff --git a/src/extensions/react-flow/edges/EdgeDefault.tsx b/src/extensions/react-flow/edges/EdgeDefault.tsx
index 65b7b2675..b7e395eab 100644
--- a/src/extensions/react-flow/edges/EdgeDefault.tsx
+++ b/src/extensions/react-flow/edges/EdgeDefault.tsx
@@ -4,9 +4,11 @@ import { EdgeProps as ReactFlowEdgeProps } from "react-flow-renderer/dist/types"
import { intentClassName, IntentTypes } from "../../../common/Intent";
import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
+import { ReactFlowVersions, useReactFlowVersion } from "../versionsupport";
import { nodeContentUtils } from "./../nodes/NodeContent";
import { NodeHighlightColor } from "./../nodes/sharedTypes";
+import { EdgeDefaultV12, EdgeDefaultV12Props } from "./EdgeDefaultV12";
import { drawEdgeStep, drawEdgeStraight } from "./utils";
export interface EdgeDefaultDataProps {
@@ -26,15 +28,13 @@ export interface EdgeDefaultDataProps {
* Size of the "glow" effect when the edge is hovered.
*/
pathGlowWidth?: number;
- /*
- * Direction of the SVG path is inversed.
- * This is important for the placement of the markers and the animation movement.
- */
- inversePath?: boolean;
/**
- * Reference link to the SVG marker used for the start of the edge
+ * Controls where arrow heads appear on the edge.
+ * - `normal`: arrow at the end (target)
+ * - `inversed`: arrow at the start (source)
+ * - `bidirectional`: arrows at both start and end
*/
- markerStart?: string;
+ arrowDirection?: "normal" | "inversed" | "bidirectional"; // FIXME: direction of animation is not inverted
/**
* Callback handler that returns a React element used as edge title.
*/
@@ -46,19 +46,35 @@ export interface EdgeDefaultDataProps {
edgeSvgProps?: React.SVGProps;
}
-export interface EdgeDefaultProps extends ReactFlowEdgeProps {
+/**
+ * @deprecated (v26) v9 support is removed after v25
+ */
+export interface EdgeDefaultV9DataProps extends EdgeDefaultDataProps {
+ /**
+ * Reference link to the SVG marker used for the start of the edge
+ * @deprecated (v26) only necessary for react flow v9
+ */
+ markerStart?: string;
+}
+
+/**
+ * @deprecated (v26) v9 support is removed after v25
+ */
+export interface EdgeDefaultV9Props extends ReactFlowEdgeProps {
/**
* Defining content and markers for the edge.
*/
- data?: EdgeDefaultDataProps;
+ data?: EdgeDefaultV9DataProps;
/**
* Callback handler that returns a SVG path as string to define how the edge is rendered.
*/
drawSvgPath?: (edge: ReactFlowEdgeProps) => string;
}
-export const EdgeDefault = memo(
- ({ data = {}, drawSvgPath = drawEdgeStraight, ...edgeOriginalProperties }: EdgeDefaultProps) => {
+export type EdgeDefaultProps = EdgeDefaultV9Props | EdgeDefaultV12Props;
+
+const EdgeDefaultV9 = memo(
+ ({ data = {}, drawSvgPath = drawEdgeStraight, ...edgeOriginalProperties }: EdgeDefaultV9Props) => {
const { pathGlowWidth = 10, markerStart, strokeType, intent, highlightColor, edgeSvgProps } = data;
const pathDisplay = drawSvgPath({ ...edgeOriginalProperties, data });
@@ -94,7 +110,11 @@ export const EdgeDefault = memo(
return (
{
+ const flowVersionCheck = useReactFlowVersion();
+ switch (flowVersionCheck) {
+ case ReactFlowVersions.V9:
+ return ;
+ case ReactFlowVersions.V12:
+ return ;
+ default:
+ return <>>;
+ }
+});
+
const createEdgeDefaultClassName = (
{ strokeType, intent, highlightColor }: EdgeDefaultDataProps,
- baseClass = "react-flow__edge-path"
+ baseClass = "react-flow__edge-path",
+ flowVersion?: ReactFlowVersions
) => {
const { highlightClassNameSuffix } = nodeContentUtils.evaluateHighlightColors("--edge-highlight", highlightColor);
return (
baseClass +
+ (flowVersion ? ` react-flow__edge--${flowVersion}` : "") +
(strokeType ? ` ${baseClass}--stroke-${strokeType}` : "") +
(intent ? ` ${intentClassName(intent)}` : "") +
(highlightClassNameSuffix.length > 0
diff --git a/src/extensions/react-flow/edges/EdgeDefaultV12.tsx b/src/extensions/react-flow/edges/EdgeDefaultV12.tsx
index 5ffed2cdc..3ec5d5119 100644
--- a/src/extensions/react-flow/edges/EdgeDefaultV12.tsx
+++ b/src/extensions/react-flow/edges/EdgeDefaultV12.tsx
@@ -1,44 +1,32 @@
-import { memo } from "react";
-import React from "react";
-import { BaseEdge, Edge, EdgeProps, EdgeText, getBezierPath, getEdgeCenter } from "@xyflow/react";
+import React, { memo } from "react";
+import { BaseEdge, Edge, EdgeProps, EdgeText, GetBezierPathParams } from "@xyflow/react";
-import { IntentTypes } from "../../../common/Intent";
import { nodeContentUtils } from "../nodes/NodeContent";
-import { NodeHighlightColor } from "../nodes/sharedTypes";
+import { ReactFlowVersions } from "../versionsupport";
-import { edgeDefaultUtils } from "./EdgeDefault";
+import { EdgeDefaultDataProps, edgeDefaultUtils } from "./EdgeDefault";
+import { getStraightPath } from "./utils";
-export type EdgeDefaultV12DataProps = Record & {
- /**
- * Overwrites the default style how the edge stroke is displayed.
- */
- strokeType?: "solid" | "dashed" | "dotted" | "double" | "doubledashed";
- /**
- * Feedback state of the node.
- */
- intent?: IntentTypes;
- /**
- * Set the color of used highlights to mark the edge.
- */
- highlightColor?: NodeHighlightColor | [NodeHighlightColor, NodeHighlightColor];
- /**
- * Size of the "glow" effect when the edge is hovered.
- */
- pathGlowWidth?: number;
- /*
- * Direction of the SVG path is inversed.
- * This is important for the placement of the markers and the animation movement.
- */
- inversePath?: boolean;
+/**
+ * @deprecated (v26) use EdgeDefaultDataProps
+ */
+export interface EdgeDefaultV12DataProps extends Record, EdgeDefaultDataProps {
/**
- * Callback handler that returns a React element used as edge title.
+ * Set the marker used on the start or end of the edge.
*/
- renderLabel?: (edgeCenter: [number, number, number, number]) => React.ReactNode;
+ markerAppearance?: "arrow-closed" | "none";
+}
+
+/**
+ * @deprecated (v26) use EdgeDefaultProps
+ */
+export type EdgeDefaultV12Props = EdgeProps> & {
/**
- * Properties are forwarded to the internally used SVG `g` element.
- * Data attributes for test ids coud be included here.
+ * Callback handler that returns SVG path and label position of the edge.
*/
- edgeSvgProps?: React.SVGProps;
+ getPath?: (
+ edgeParams: Omit & Record
+ ) => [path: string, labelX: number, labelY: number, offsetX: number, offsetY: number];
};
/**
@@ -62,11 +50,20 @@ export const EdgeDefaultV12 = memo(
labelBgPadding = [5, 5],
labelBgBorderRadius = 3,
data = {},
+ getPath = getStraightPath,
...edgeOriginalProperties
- }: EdgeProps>) => {
- const { pathGlowWidth = 10, highlightColor, renderLabel, edgeSvgProps, intent, inversePath, strokeType } = data;
+ }: EdgeDefaultV12Props) => {
+ const {
+ pathGlowWidth = 10,
+ highlightColor,
+ renderLabel,
+ edgeSvgProps,
+ intent,
+ arrowDirection = "normal",
+ strokeType,
+ } = data;
- const [edgePath, labelX, labelY] = getBezierPath({
+ const [edgePath, labelX, labelY] = getPath({
sourceX,
sourceY,
sourcePosition,
@@ -81,19 +78,12 @@ export const EdgeDefaultV12 = memo(
highlightColor
);
- const edgeCenter = getEdgeCenter({
- sourceX,
- sourceY,
- targetX,
- targetY,
- });
-
const renderedLabel =
renderLabel?.([labelX, labelY, sourceX, targetX]) ??
(label ? (
) : null);
+ const appearance = data.markerAppearance ?? "arrow-closed";
+
+ const marker =
+ appearance !== "none"
+ ? {
+ markerStart:
+ arrowDirection === "inversed" || arrowDirection === "bidirectional"
+ ? `url(#react-flow__marker--${appearance}${intent ? `-${intent}` : "-none"}-reverse)`
+ : undefined,
+ markerEnd:
+ arrowDirection === "normal" || arrowDirection === "bidirectional"
+ ? `url(#react-flow__marker--${appearance}${intent ? `-${intent}` : "-none"})`
+ : undefined,
+ }
+ : {};
+
return (
-
- {highlightColor && (
-
- )}
-
-
-
+ )}
+
{renderedLabel}
);
diff --git a/src/extensions/react-flow/edges/EdgeDefs.tsx b/src/extensions/react-flow/edges/EdgeDefs.tsx
index aa3d2a440..bc77e038b 100644
--- a/src/extensions/react-flow/edges/EdgeDefs.tsx
+++ b/src/extensions/react-flow/edges/EdgeDefs.tsx
@@ -1,5 +1,8 @@
import React from "react";
+/**
+ * @deprecated (v26) use ` `
+ */
export const EdgeDefs = React.memo(() => (
diff --git a/src/extensions/react-flow/edges/EdgeLabel.tsx b/src/extensions/react-flow/edges/EdgeLabel.tsx
index 1faf5fa03..767146a21 100644
--- a/src/extensions/react-flow/edges/EdgeLabel.tsx
+++ b/src/extensions/react-flow/edges/EdgeLabel.tsx
@@ -28,7 +28,7 @@ export interface EdgeLabelProps extends React.HTMLAttributes {
*/
fullWidth?: boolean;
/**
- * Label is diaplayed without a box that comes with borders and background color.
+ * Label is displayed without a box that comes with borders and background color.
*/
loose?: boolean;
/**
diff --git a/src/extensions/react-flow/edges/EdgeNew.tsx b/src/extensions/react-flow/edges/EdgeNew.tsx
new file mode 100644
index 000000000..9c97d34e1
--- /dev/null
+++ b/src/extensions/react-flow/edges/EdgeNew.tsx
@@ -0,0 +1,52 @@
+import React from "react";
+import {
+ ConnectionLineComponentProps,
+ ConnectionLineType,
+} from "@xyflow/react";
+import { EdgeStraight, EdgeStep, EdgeBezier, EdgeDefaultV12Props } from "./../index";
+
+import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
+
+export const EdgeNew = (edgeNewProps: ConnectionLineComponentProps) => {
+
+ const {
+ connectionLineType,
+ fromX,
+ fromY,
+ toX,
+ toY,
+ connectionStatus,
+ fromPosition,
+ toPosition,
+ } = edgeNewProps;
+
+ let EdgeType;
+
+ switch(connectionLineType) {
+ case ConnectionLineType.Step:
+ case ConnectionLineType.SmoothStep:
+ EdgeType = EdgeStep;
+ break;
+ case ConnectionLineType.Bezier:
+ case ConnectionLineType.SimpleBezier:
+ EdgeType = EdgeBezier;
+ break;
+ default:
+ EdgeType = EdgeStraight;
+ }
+
+ return ;
+};
+
diff --git a/src/extensions/react-flow/edges/EdgeStep.tsx b/src/extensions/react-flow/edges/EdgeStep.tsx
index 4e9dfdc76..a0137bded 100644
--- a/src/extensions/react-flow/edges/EdgeStep.tsx
+++ b/src/extensions/react-flow/edges/EdgeStep.tsx
@@ -1,16 +1,51 @@
import React, { memo } from "react";
+import { Edge, EdgeProps, getSmoothStepPath } from "@xyflow/react";
-import { EdgeDefault, EdgeDefaultDataProps, EdgeDefaultProps } from "./EdgeDefault";
+import { ReactFlowVersions, useReactFlowVersion } from "../versionsupport";
+
+import { EdgeDefault, EdgeDefaultV9DataProps, EdgeDefaultV9Props } from "./EdgeDefault";
+import { EdgeDefaultV12DataProps, EdgeDefaultV12Props } from "./EdgeDefaultV12";
import { drawEdgeStep } from "./utils";
-interface EdgeStepDataProps extends EdgeDefaultDataProps {
+interface EdgeStepDataV9Props extends EdgeDefaultV9DataProps {
+ stepCornerRadius?: number;
+}
+interface EdgeStepDataV12Props extends EdgeDefaultV12DataProps {
stepCornerRadius?: number;
}
-export interface EdgeStepProps extends EdgeDefaultProps {
- data?: EdgeStepDataProps;
+/**
+ * @deprecated (v26) v9 support is removed after v25
+ */
+export interface EdgeStepV9Props extends EdgeDefaultV9Props {
+ data?: EdgeStepDataV9Props;
}
+/**
+ * @deprecated (v26) v9 support is removed after v25
+ */
+export interface EdgeStepV12Props extends Omit, EdgeProps> {}
+
+export type EdgeStepProps = EdgeStepV9Props | EdgeStepV12Props;
-export const EdgeStep = memo((edge: EdgeStepProps) => {
- return ;
+/**
+ * This element cannot be used directly, it must be connected via a `edgeTypes` definition.
+ * @see https://reactflow.dev/docs/api/nodes/
+ */
+export const EdgeStep = memo((props: EdgeStepProps) => {
+ const flowVersionCheck = useReactFlowVersion();
+ switch (flowVersionCheck) {
+ case ReactFlowVersions.V9:
+ return ;
+ case ReactFlowVersions.V12:
+ return (
+ {
+ return getSmoothStepPath({ ...params, borderRadius: props.data?.stepCornerRadius ?? 7 });
+ }}
+ />
+ );
+ default:
+ return <>>;
+ }
});
diff --git a/src/extensions/react-flow/edges/EdgeStraight.tsx b/src/extensions/react-flow/edges/EdgeStraight.tsx
new file mode 100644
index 000000000..72685db16
--- /dev/null
+++ b/src/extensions/react-flow/edges/EdgeStraight.tsx
@@ -0,0 +1 @@
+export { EdgeDefault as EdgeStraight } from "./EdgeDefault";
diff --git a/src/extensions/react-flow/edges/_edges.scss b/src/extensions/react-flow/edges/_edges.scss
index 15734c8f9..9583398b6 100644
--- a/src/extensions/react-flow/edges/_edges.scss
+++ b/src/extensions/react-flow/edges/_edges.scss
@@ -10,7 +10,7 @@
path[class*="react-flow__edge"],
rect[class*="react-flow__edge"] {
stroke-opacity: $reactflow-edge-stroke-opacity-default;
- shape-rendering: optimizespeed;
+ shape-rendering: $reactflow-edge-rendering;
}
text[class*="react-flow__edge"] {
@@ -49,16 +49,26 @@
opacity: $reactflow-edge-stroke-opacity-selected;
}
}
+
+ &.selected,
+ &:focus,
+ &:focus-visible {
+ outline: none;
+ }
}
path.react-flow__edge-path {
stroke: currentcolor;
stroke-opacity: $reactflow-edge-stroke-opacity-default;
- stroke-width: 2;
+ stroke-width: $reactflow-edge-stroke-width-default;
+
+ .react-flow__edge:hover & {
+ stroke-width: $reactflow-edge-stroke-width-hover;
+ }
.react-flow__edge.selected & {
stroke: currentcolor;
- stroke-width: 2;
+ stroke-width: $reactflow-edge-stroke-width-selected;
}
}
@@ -72,11 +82,11 @@ path.react-flow__edge-interaction {
}
.react-flow__edge:hover & {
- stroke-opacity: $reactflow-edge-stroke-opacity-hover * 0.2;
+ stroke-opacity: $reactflow-edge-stroke-opacity-hover * $reactflow-edge-stroke-opacity-interaction-ratio;
}
.react-flow__edge.selected & {
- stroke-opacity: $reactflow-edge-stroke-opacity-selected * 0.2;
+ stroke-opacity: $reactflow-edge-stroke-opacity-selected * $reactflow-edge-stroke-opacity-interaction-ratio;
}
}
@@ -90,11 +100,11 @@ path.react-flow__edge-path-glow {
}
.react-flow__edge:hover & {
- stroke-opacity: $reactflow-edge-stroke-opacity-hover * 0.2;
+ stroke-opacity: $reactflow-edge-stroke-opacity-hover * $reactflow-edge-stroke-opacity-interaction-ratio;
}
.react-flow__edge.selected & {
- stroke-opacity: $reactflow-edge-stroke-opacity-selected * 0.2;
+ stroke-opacity: $reactflow-edge-stroke-opacity-selected * $reactflow-edge-stroke-opacity-interaction-ratio;
}
.react-flow__edge.animated & {
@@ -143,8 +153,8 @@ path.react-flow__edge-path--stroke-double {
path.react-flow__edge-path--stroke-doubledashed {
filter: drop-shadow(1px 1px 1px currentcolor) drop-shadow(-1px -1px 1px currentcolor);
stroke: #fff !important;
- stroke-dasharray: 5;
stroke-opacity: 1 !important;
+ stroke-dasharray: 5;
}
// Intent states
@@ -193,8 +203,8 @@ path.react-flow__edge-path-highlight {
drop-shadow(-2px 2px 1px var(--edge-highlight-alternate-color, var(--edge-highlight-default-color)));
fill: none;
stroke: #fff;
- stroke-linecap: round;
stroke-opacity: 1;
+ stroke-linecap: round;
}
.#{$eccgui}-graphviz__edge--highlight-default {
@@ -256,15 +266,19 @@ path.react-flow__edge-path-highlight {
polyline {
fill: currentcolor;
stroke: currentcolor;
+ stroke-width: 1px;
stroke-linecap: square;
stroke-linejoin: miter;
- stroke-width: 1px;
transform: scale(1.75, 0.75);
}
}
// Custom label
+.#{$eccgui}-graphviz__edge-labelobject {
+ overflow: visible;
+}
+
.#{$eccgui}-graphviz__edge-label {
--#{$eccgui}-reactflow-edge-label-color: currentcolor;
--#{$eccgui}-reactflow-edge-label-color-background: #{$card-background-color};
@@ -330,8 +344,8 @@ path.react-flow__edge-path-highlight {
flex-shrink: 1;
margin: 0 $eccgui-size-block-whitespace * 0.25;
overflow: hidden;
- text-align: center;
text-overflow: ellipsis;
+ text-align: center;
white-space: nowrap;
.#{$eccgui}-graphviz__edge-label--fullwidth & {
diff --git a/src/extensions/react-flow/edges/edgeTypes.ts b/src/extensions/react-flow/edges/edgeTypes.ts
deleted file mode 100644
index db14abfb1..000000000
--- a/src/extensions/react-flow/edges/edgeTypes.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- We need to replicate some elements from react flow because they
-
- 1. do not export all sub elements, e.g. edges
- 2. we need to add additional features for better usage
-*/
-
-import { EdgeDefault } from "./EdgeDefault";
-import { EdgeStep } from "./EdgeStep";
-
-/** @deprecated (v25) will be removed without replacement, define it yourself or use ` {
// this is only a mock to get it as sub element in the table
- return <>>;
+ return <>{data.intent}>;
};
export default {
@@ -23,7 +23,7 @@ export default {
},
} as Meta;
-const EdgeDefaultExample = (args: any) => {
+const EdgeDefaultExample = (args: EdgeDefaultProps) => {
const [reactflowInstance, setReactflowInstance] = useState(null);
const [elements, setElements] = useState([] as Elements);
@@ -66,7 +66,7 @@ const EdgeDefaultExample = (args: any) => {
return (
- {
return <>>;
};
-const edgeTypes = {
- default: EdgeDefaultV12,
-};
-const nodeTypes = {
- default: NodeDefaultV12,
-};
export default {
title: "Extensions/React Flow V12/Edge",
component: EdgeDefaultV12,
@@ -76,17 +73,11 @@ const EdgeDefault = (args: Edge) => {
},
position: { x: 600, y: 200 },
},
- ]);
+ ] as Node[]);
const [edges, setEdges, onEdgesChange] = useEdgesState([
{
...args,
- // sourceX: 150,
- // sourceY: 0,
- // targetX: 250,
- // targetY: 0,
- sourcePosition: Position.Left,
- targetPosition: Position.Right,
},
]);
@@ -102,14 +93,12 @@ const EdgeDefault = (args: Edge) => {
);
return (
-
-
-
+ ) => {
+ const path = drawEdgeStraight(params as EdgeDefaultProps);
+ const [labelX, labelY, offsetX, offsetY] = getEdgeCenter({
+ sourceX: params.sourceX,
+ sourceY: params.sourceY,
+ targetX: params.targetX,
+ targetY: params.targetY,
+ });
+ return [path, labelX, labelY, offsetX, offsetY] as [
+ path: string,
+ labelX: number,
+ labelY: number,
+ offsetX: number,
+ offsetY: number
+ ];
+};
+
export const drawEdgeStep = ({
sourceX,
sourceY,
diff --git a/src/extensions/react-flow/handles/HandleDefault.tsx b/src/extensions/react-flow/handles/HandleDefault.tsx
index a12a8a0ed..3d56a9319 100644
--- a/src/extensions/react-flow/handles/HandleDefault.tsx
+++ b/src/extensions/react-flow/handles/HandleDefault.tsx
@@ -1,6 +1,5 @@
import React, { memo } from "react";
-import { Handle as HandleLegacy, HandleProps as ReactFlowHandleLegacyProps } from "react-flow-renderer";
-import { Handle as HandleNext, HandleProps as ReactFlowHandleNextProps } from "react-flow-renderer-lts";
+import { Handle as HandleV9, HandleProps as ReactFlowHandleV9Props } from "react-flow-renderer";
import { Handle as HandleV12, HandleProps as ReactFlowHandleV12Props } from "@xyflow/react";
import { Classes as BlueprintClasses } from "@blueprintjs/core";
@@ -10,6 +9,7 @@ import { TooltipProps } from "../../../index";
import { ReacFlowVersionSupportProps, useReactFlowVersion } from "../versionsupport";
import { HandleContent, HandleContentProps } from "./HandleContent";
+import {Intent} from "@blueprintjs/core/src/common/intent";
export type HandleCategory = "configuration" | "flexible" | "fixed" | "unknown" | "dependency";
@@ -35,33 +35,44 @@ interface HandleExtensionProps
children?: HandleContentProps["children"];
}
-export interface HandleProps extends HandleExtensionProps, ReactFlowHandleLegacyProps {}
-export interface HandleNextProps extends HandleExtensionProps, ReactFlowHandleNextProps {}
+/**
+ * @deprecated (v26) use only `HandleDefaultProps`
+ */
+export interface HandleV9Props extends HandleExtensionProps, ReactFlowHandleV9Props {}
+/**
+ * @deprecated (v26) use only `HandleDefaultProps`
+ */
export interface HandleV12Props extends HandleExtensionProps, ReactFlowHandleV12Props {}
-export type HandleDefaultProps = HandleProps | HandleNextProps | HandleV12Props;
+
+/**
+ * Combined interface, later this will be only a copy of `HandleV12Props`.
+ */
+export type HandleDefaultProps = HandleV9Props | HandleV12Props;
export const HandleDefault = memo(
({ flowVersion, data, tooltip, children, category, intent, ...handleProps }: HandleDefaultProps) => {
const evaluateFlowVersion = useReactFlowVersion();
const flowVersionCheck = flowVersion || evaluateFlowVersion;
- const handleDefaultRef = React.useRef();
+ const handleDefaultRef = React.useRef(null);
const [extendedTooltipDisplayed, setExtendedTooltipDisplayed] = React.useState(false);
- let toolsTarget: HTMLElement[];
+ let toolsTarget: HTMLCollectionOf;
React.useEffect(() => {
- toolsTarget = handleDefaultRef.current.getElementsByClassName(`${eccgui}-graphviz__handletools-target`);
- if (toolsTarget && toolsTarget[0]) {
- // Polyfill for FF that does not support the `:has()` pseudo selector until at least version 119 or 120
- // need to be re-evaluated then
- // @see https://connect.mozilla.org/t5/ideas/when-is-has-css-selector-going-to-be-fully-implemented-in/idi-p/23794
- handleDefaultRef.current.classList.add(`ffpolyfill-has-${eccgui}-graphviz__handletools-target`);
+ if (handleDefaultRef.current) {
+ toolsTarget = handleDefaultRef.current.getElementsByClassName(`${eccgui}-graphviz__handletools-target`);
+ if (toolsTarget && toolsTarget[0]) {
+ // Polyfill for FF that does not support the `:has()` pseudo selector until at least version 119 or 120
+ // need to be re-evaluated then
+ // @see https://connect.mozilla.org/t5/ideas/when-is-has-css-selector-going-to-be-fully-implemented-in/idi-p/23794
+ handleDefaultRef.current.classList.add(`ffpolyfill-has-${eccgui}-graphviz__handletools-target`);
+ }
}
});
const tooltipTitle = tooltip ? { title: tooltip } : {};
- const handleContentTooltipProps = {
+ const handleContentTooltipProps: Partial = {
placement:
handleProps.position === "left" || handleProps.position === "right"
? `${handleProps.position}-end`
@@ -74,39 +85,39 @@ export const HandleDefault = memo(
},
},
},
- intent: intent,
+ intent: intent as Intent,
className: `${eccgui}-graphviz__handle__tooltip-target`,
isOpen: extendedTooltipDisplayed,
- };
+ }
- const handleContentProps = {
+ const handleContentProps = React.useMemo(() => ({
...data,
tooltipProps: {
...handleContentTooltipProps,
...data?.tooltipProps,
} as TooltipProps,
- };
+ }), [intent, category, handleProps.isConnectable])
- const handleContent = {children} ;
+ const handleContent = React.useMemo(() => {children} , [])
let switchTooltipTimerOn: ReturnType;
let switchToolsTimerOff: ReturnType;
- const handleConfig = {
+ const handleConfig = React.useMemo(() => ({
...handleProps,
...tooltipTitle,
- className: intent ? `${intentClassName(intent)} ` : "",
- onClick: (e: any) => {
+ className: intent ? `${intentClassName(intent)} ` : "" + ` ${eccgui}-graphviz__handle ${eccgui}-graphviz__handle--${flowVersionCheck}`,
+ onClick: (e: React.MouseEvent) => {
if (handleProps.onClick) {
handleProps.onClick(e);
}
if (toolsTarget.length > 0 && e.target === handleDefaultRef.current) {
setExtendedTooltipDisplayed(false);
- toolsTarget[0].click();
+ (toolsTarget[0] as HTMLElement).click();
}
},
"data-category": category,
- onMouseEnter: (e: any) => {
+ onMouseEnter: (e: React.MouseEvent) => {
if (switchToolsTimerOff) clearTimeout(switchToolsTimerOff);
if (e.target === handleDefaultRef.current) {
switchTooltipTimerOn = setTimeout(
@@ -118,24 +129,18 @@ export const HandleDefault = memo(
onMouseLeave: () => {
if (switchTooltipTimerOn) clearTimeout(switchTooltipTimerOn);
if (toolsTarget.length > 0 && toolsTarget[0].classList.contains(BlueprintClasses.POPOVER_OPEN)) {
- switchToolsTimerOff = setTimeout(() => toolsTarget[0].click(), 500);
+ switchToolsTimerOff = setTimeout(() => (toolsTarget[0] as HTMLElement).click(), 500);
}
setExtendedTooltipDisplayed(false);
},
- };
+ }), [intent, category, tooltip, handleProps.isConnectable, handleProps.style]);
switch (flowVersionCheck) {
- case "legacy":
- return (
-
- {handleContent}
-
- );
- case "next":
+ case "v9":
return (
-
+
{handleContent}
-
+
);
case "v12":
return (
diff --git a/src/extensions/react-flow/handles/_handles.scss b/src/extensions/react-flow/handles/_handles.scss
index 83f9e489b..77c2b576d 100644
--- a/src/extensions/react-flow/handles/_handles.scss
+++ b/src/extensions/react-flow/handles/_handles.scss
@@ -90,7 +90,7 @@ div.react-flow__handle {
}
&[data-category="dependency"] {
- background-color: color-mix(in srgb, currentcolor 39%, white);
+ background-color: eccgui-color-mix(currentcolor 39%, white);
border-radius: 0;
transform: rotate(45deg);
@@ -118,7 +118,7 @@ div.react-flow__handle {
}
&[data-category="unknown"] {
- background-color: color-mix(in srgb, currentcolor 39%, white);
+ background-color: eccgui-color-mix(currentcolor 39%, white);
}
.react-flow__node:hover &.connectable {
diff --git a/src/extensions/react-flow/handles/stories/HandleDefault.stories.tsx b/src/extensions/react-flow/handles/stories/HandleDefault.stories.tsx
index cb22b7378..11e89f4c0 100644
--- a/src/extensions/react-flow/handles/stories/HandleDefault.stories.tsx
+++ b/src/extensions/react-flow/handles/stories/HandleDefault.stories.tsx
@@ -8,16 +8,15 @@ import { Definitions } from "../../../../common/Intent";
import {
Button,
HandleDefault,
- HandleProps,
+ HandleDefaultProps,
HandleTools,
Menu,
MenuItem,
- ReactFlow,
+ ReactFlowExtended,
SimpleDialog,
} from "./../../../../../index";
-import { edgeTypes } from "./../../edges/edgeTypes";
-const HandleDefaultDataProps = (data: HandleProps["data"]) => {
+const HandleDefaultDataProps = (data: HandleDefaultProps["data"]) => {
// this is only a mock to get it as sub element in the table
return <>{data?.extendedTooltip}>;
};
@@ -66,11 +65,10 @@ const HandleDefaultExample = (args: any) => {
return (
-
diff --git a/src/extensions/react-flow/index.ts b/src/extensions/react-flow/index.ts
index 16e688163..98e3bf6f6 100644
--- a/src/extensions/react-flow/index.ts
+++ b/src/extensions/react-flow/index.ts
@@ -6,17 +6,19 @@ export * from "./nodes/nodeUtils";
export * from "./handles/HandleDefault";
export * from "./handles/HandleContent";
export * from "./handles/HandleTools";
+export * from "./edges/EdgeBezier";
export * from "./edges/EdgeDefault";
+export * from "./edges/EdgeDefaultV12";
+export * from "./edges/EdgeDefs";
export * from "./edges/EdgeStep";
+export * from "./edges/EdgeStraight";
+export * from "./edges/EdgeNew";
export * from "./edges/EdgeTools";
export * from "./edges/EdgeLabel";
export * from "./edges/EdgeDefs";
export * from "./edges/EdgeDefaultV12";
export * from "./markers/ReactFlowMarkers";
export * from "./minimap/MiniMap";
+export * from "./minimap/MiniMapV12";
export * from "./minimap/utils";
-export * from "./versionsupport";
-
-// deprecated exports
-export { nodeTypes } from "./nodes/nodeTypes"; // @deprecated removed in v25
-export { edgeTypes } from "./edges/edgeTypes"; // @deprecated removed in v25
+export * from "./versionsupport";
\ No newline at end of file
diff --git a/src/extensions/react-flow/markers/MarkerArrowClosedInverse.tsx b/src/extensions/react-flow/markers/MarkerArrowClosedInverse.tsx
index 713ee04ee..67bc0db69 100644
--- a/src/extensions/react-flow/markers/MarkerArrowClosedInverse.tsx
+++ b/src/extensions/react-flow/markers/MarkerArrowClosedInverse.tsx
@@ -1,5 +1,8 @@
import React, { FC } from "react";
+/**
+ * @deprecated (v26) only necessary for react flow v9, support will be removed
+ */
export const MarkerArrowClosedInverse: FC = () => {
return (
{
+ /**
+ * Visual appearance of the marker.
+ */
+ appearance?: ReactFlowMarkerAppearance;
+ /**
+ * Feedback state of the marker.
+ * SVG markers are reused by paths but they cannot inherit their state color automatically.
+ */
+ intent?: IntentTypes;
+ /**
+ * If set, then the marker orientation is reversed.
+ * Can be used if a start marker should displayed similar to an end marker.
+ */
+ reverse?: boolean;
+}
+
+const ReactFlowMarker = ({ className, appearance = "arrow-closed", intent, reverse }: ReactFlowMarkerProps) => {
+ const markerDisplay: Record = {
+ "arrow-closed": (
+
+ ),
+ };
+
+ return (
+
+ {markerDisplay[appearance]}
+
+ );
+};
+
const ReactFlowMarkers: FC = () => {
+ const intents = ["none", "primary", "accent", "success", "warning", "danger", "info" ] as IntentTypes[];
+
return (
+ {intents.map((intent) => (
+ <>
+
+
+ >
+ ))}
);
};
-export { MarkerArrowClosedInverse, ReactFlowMarkers };
+export { MarkerArrowClosedInverse, ReactFlowMarkers, ReactFlowMarker };
diff --git a/src/extensions/react-flow/markers/_markers.scss b/src/extensions/react-flow/markers/_markers.scss
new file mode 100644
index 000000000..82f4f6244
--- /dev/null
+++ b/src/extensions/react-flow/markers/_markers.scss
@@ -0,0 +1,31 @@
+marker[id|="react-flow__marker"] {
+ color: var(--marker-intent-color);
+
+ &.#{$eccgui}-intent--none {
+ --marker-intent-color: #{$reactflow-edge-stroke-color-default};
+ }
+
+ &.#{$eccgui}-intent--primary {
+ --marker-intent-color: #{$eccgui-color-primary};
+ }
+
+ &.#{$eccgui}-intent--accent {
+ --marker-intent-color: #{$eccgui-color-accent};
+ }
+
+ &.#{$eccgui}-intent--info {
+ --marker-intent-color: #{$eccgui-color-info-text};
+ }
+
+ &.#{$eccgui}-intent--success {
+ --marker-intent-color: #{$eccgui-color-success-text};
+ }
+
+ &.#{$eccgui}-intent--warning {
+ --marker-intent-color: #{$eccgui-color-warning-text};
+ }
+
+ &.#{$eccgui}-intent--danger {
+ --marker-intent-color: #{$eccgui-color-danger-text};
+ }
+}
diff --git a/src/extensions/react-flow/minimap/MiniMap.stories.tsx b/src/extensions/react-flow/minimap/MiniMap.stories.tsx
index 2663c7330..689a59585 100644
--- a/src/extensions/react-flow/minimap/MiniMap.stories.tsx
+++ b/src/extensions/react-flow/minimap/MiniMap.stories.tsx
@@ -1,32 +1,26 @@
import React, { FC, useCallback, useEffect, useState } from "react";
-import { Background, BackgroundVariant, Elements, FlowElement } from "react-flow-renderer";
-import { OverlaysProvider } from "@blueprintjs/core";
+import { Background, BackgroundVariant, Elements } from "react-flow-renderer";
import { Meta, StoryFn } from "@storybook/react";
import { Default as ReactFlowExample } from "../../../cmem/react-flow/ReactFlow/ReactFlow.stories";
-import { MiniMap as MiniMapElement, MiniMapProps, ReactFlow, ReactFlowProps } from "./../../../../index";
+import { ApplicationContainer, MiniMap, MiniMapProps, ReactFlowExtended } from "./../../../index";
export default {
title: "Extensions/React Flow/MiniMap",
- component: MiniMapElement,
+ component: MiniMap,
argTypes: {},
-} as Meta;
+} as Meta;
const MiniMapExample: FC = (args) => {
const [reactflowInstance, setReactflowInstance] = useState(undefined);
const [elements, setElements] = useState([] as Elements);
- const [edgeTools, setEdgeTools] = useState(<>>);
const nodeExamples = ReactFlowExample.nodeExamples.workflow;
useEffect(() => {
- setElements(nodeExamples as Elements);
+ setElements([...nodeExamples.nodes, ...nodeExamples.edges] as Elements);
}, [args]);
- // Helper methods for nodes and edges
- const isNode = (element: FlowElement & { source?: string }): boolean => !element.source;
- const isEdge = (element: FlowElement & { source?: string }): boolean => !isNode(element);
-
const onLoad = useCallback((rfi) => {
if (!reactflowInstance) {
setReactflowInstance(rfi);
@@ -34,23 +28,23 @@ const MiniMapExample: FC = (args) => {
}, []);
return (
-
-
+
-
+
-
- {edgeTools}
-
+
+
);
};
-const Template: StoryFn = (args) => ;
+let forcedUpdateKey = 0; // @see https://github.com/storybookjs/storybook/issues/13375#issuecomment-1291011856
+const Template: StoryFn = (args) => ;
export const Default = Template.bind({});
Default.args = {
diff --git a/src/extensions/react-flow/minimap/MiniMap.tsx b/src/extensions/react-flow/minimap/MiniMap.tsx
index 5731ebcf9..fd58caf48 100644
--- a/src/extensions/react-flow/minimap/MiniMap.tsx
+++ b/src/extensions/react-flow/minimap/MiniMap.tsx
@@ -1,14 +1,16 @@
import React, { memo, useEffect } from "react";
-import { MiniMap as ReactFlowMiniMap, MiniMapProps as ReactFlowMiniMapProps, OnLoadParams } from "react-flow-renderer";
+import {
+ MiniMap as ReactFlowMiniMapV9,
+ MiniMapProps as ReactFlowMiniMapV9Props,
+ OnLoadParams
+} from "react-flow-renderer";
import { FlowTransform } from "react-flow-renderer/dist/types";
-import { miniMapUtils } from "../minimap/utils";
+import { miniMapUtils } from "./utils";
+import { ReacFlowVersionSupportProps, ReactFlowVersions, useReactFlowVersion } from "../versionsupport";
+import { MiniMapV12, MiniMapV12Props } from "./MiniMapV12";
-export interface MiniMapProps extends ReactFlowMiniMapProps {
- /**
- * React-Flow instance
- */
- flowInstance?: OnLoadParams;
+export interface MiniMapBasicProps {
/**
* Enable navigating the react-flow canvas by dragging and clicking on the mini-map.
*/
@@ -23,6 +25,15 @@ export interface MiniMapProps extends ReactFlowMiniMapProps {
>;
}
+export interface MiniMapV9Props extends MiniMapBasicProps, ReactFlowMiniMapV9Props {
+ /**
+ * React-Flow instance
+ */
+ flowInstance?: OnLoadParams;
+}
+
+export type MiniMapProps = (ReacFlowVersionSupportProps & MiniMapV9Props) | (ReacFlowVersionSupportProps & MiniMapV12Props);
+
interface configParams {
// Key has been pressed down over the mini-map and navigation mode has thus started
navigationOn: boolean;
@@ -40,6 +51,28 @@ let minimapCalcConf: configParams = {
/** An improved mini-map for react-flow that supports navigation via the mini-map. */
export const MiniMap = memo(
+ ({
+ flowVersion,
+ ...otherProps
+ }: MiniMapProps) => {
+ const flowVersionCheck = flowVersion || useReactFlowVersion();
+
+ switch (flowVersionCheck) {
+ case ReactFlowVersions.V9:
+ return ;
+ case ReactFlowVersions.V12:
+ return ;
+ default:
+ return <>>; // cannot exit on its own
+ }
+ }
+);
+
+/**
+ * Mini-map support for for React Flow v9.
+ * @deprecated (v26) will be removed, use when `MiniMap` directly
+ */
+export const MiniMapV9 = memo(
({
flowInstance,
enableNavigation = false,
@@ -49,7 +82,7 @@ export const MiniMap = memo(
nodeStrokeColor = miniMapUtils.borderColor,
wrapperProps,
...minimapProps
- }: MiniMapProps) => {
+ }: MiniMapV9Props) => {
const minimapWrapper = React.useRef(null);
useEffect(() => {
@@ -130,7 +163,7 @@ export const MiniMap = memo(
: wrapperProps?.style
}
>
- {
+}
+
+/**
+ * Mini-map support for for React Flow v12.
+ * @deprecated (v26) will be removed when `MiniMap` supports v12 directly
+ */
+export const MiniMapV12 = memo(
+ ({
+ enableNavigation = false,
+ nodeClassName = miniMapUtils.nodeClassName,
+ nodeColor = miniMapUtils.nodeColor,
+ nodeStrokeColor = miniMapUtils.borderColor,
+ wrapperProps,
+ ...minimapProps
+ }: MiniMapV12Props) => {
+ return (
+
+
+
+ );
+ }
+);
diff --git a/src/extensions/react-flow/minimap/_minimap.scss b/src/extensions/react-flow/minimap/_minimap.scss
index fe613e23b..ecb7e4c67 100644
--- a/src/extensions/react-flow/minimap/_minimap.scss
+++ b/src/extensions/react-flow/minimap/_minimap.scss
@@ -1,3 +1,17 @@
+.react-flow__minimap {
+ right: $eccgui-size-block-whitespace * 0.5 !important;
+ bottom: $eccgui-size-block-whitespace !important;
+ border: solid 1px $eccgui-color-separation-divider;
+
+ & > svg {
+ display: block;
+ }
+}
+
+.react-flow__minimap-mask {
+ fill: rgba($eccgui-color-separation-divider, $eccgui-opacity-muted);
+}
+
.#{$eccgui}-graphviz__minimap__node--default {
&:not([fill]) {
fill: $reactflow-node-background-color;
diff --git a/src/extensions/react-flow/nodes/NodeContent.tsx b/src/extensions/react-flow/nodes/NodeContent.tsx
index ed2e46d53..ea7201808 100644
--- a/src/extensions/react-flow/nodes/NodeContent.tsx
+++ b/src/extensions/react-flow/nodes/NodeContent.tsx
@@ -1,7 +1,6 @@
import React from "react";
-import { Position, useStoreState as getStoreStateFlowLegacy } from "react-flow-renderer";
-import { useStore as getStoreStateFlowNext } from "react-flow-renderer-lts";
-import { useStore as useStoreFlowV12 } from "@xyflow/react";
+import { Position, useStoreState as getStoreStateFlowV9 } from "react-flow-renderer";
+import { useStore as getStoreStateFlowV12 } from "@xyflow/react";
import Color from "color";
import { Resizable } from "re-resizable";
@@ -9,24 +8,18 @@ import { intentClassName, IntentTypes } from "../../../common/Intent";
import { DepictionProps } from "../../../components";
import { ValidIconName } from "../../../components/Icon/canonicalIconNames";
import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
-import { Depiction, HandleDefaultProps, Icon, OverflowText } from "../../../index";
-import { HandleDefault, HandleNextProps, HandleProps, HandleV12Props } from "../handles/HandleDefault";
-import { ReacFlowVersionSupportProps, useReactFlowVersion } from "../versionsupport";
+import { Depiction, Icon, OverflowText } from "../../../index";
+import { ReacFlowVersionSupportProps, ReactFlowVersions, useReactFlowVersion } from "../versionsupport";
+import { HandleDefault, HandleDefaultProps } from "./../handles/HandleDefault";
import { NodeContentExtensionProps } from "./NodeContentExtension";
import { NodeDefaultProps } from "./NodeDefault";
import { NodeHighlightColor } from "./sharedTypes";
-type NodeContentHandleLegacyProps = HandleProps;
-
-type NodeContentHandleNextProps = HandleNextProps;
-
-type NodeContentHandleV12Props = HandleV12Props;
-
-export type NodeContentHandleProps =
- | NodeContentHandleLegacyProps
- | NodeContentHandleNextProps
- | NodeContentHandleV12Props;
+/**
+ * @deprecated (v26) use `HandleDefaultProps`
+ */
+export type NodeContentHandleProps = HandleDefaultProps;
export type NodeDimensions = {
width?: number;
@@ -92,7 +85,7 @@ interface NodeContentData {
footerContent?: React.ReactNode;
}
-export interface NodeContentProps
+export interface NodeContentProps
extends NodeContentData,
ReacFlowVersionSupportProps,
Omit, "content"> {
@@ -144,9 +137,9 @@ export interface NodeContentProps
* Set of defined buttons and icons that can be displayed.
*/
executionButtons?: (
- adjustedContentProps: Partial,
- setAdjustedContentProps: React.Dispatch>>
- ) => React.ReactElement;
+ adjustedContentProps: Partial,
+ setAdjustedContentProps: React.Dispatch>>
+ ) => React.ReactElement>;
/**
* Can be used for permanent action button or context menu.
* It is displayed at the node header right to the label.
@@ -156,7 +149,7 @@ export interface NodeContentProps
* Array of property definition objects for `Handle` components that need to be created for the node.
* @see https://reactflow.dev/docs/api/handle/
*/
- handles?: NodeContentHandleProps[];
+ handles?: HandleDefaultProps[];
/**
* Set the minimal number of handles on left or right side of the node to activate the recalculation of the minimal height of the node.
*/
@@ -169,7 +162,7 @@ export interface NodeContentProps
* Callback function to provide content for the tooltip on a node with a defined `minimalShape`.
* If you do not want a tooltip in this state you need to provide a callback that returns an empty value.
*/
- getMinimalTooltipData?: (node: NodeDefaultProps) => NodeContentData;
+ getMinimalTooltipData?: (node: NodeDefaultProps) => NodeContentData;
/**
* Set if a handle is displayed even if it does not allow a connection to an edge.
*/
@@ -183,8 +176,11 @@ export interface NodeContentProps
*/
introductionTime?: number | IntroductionTime;
- /** Additional data stored in the node. */
- businessData?: NODE_DATA;
+ /**
+ * Additional data stored in the node.
+ * @deprecated (v26) is not used anymore.
+ */
+ businessData?: never;
// we need to forward some ReactFlowNodeProps here
@@ -227,37 +223,20 @@ export interface NodeContentProps
resizeMaxDimensions?: Partial;
}
-interface MemoHandlerLegacyProps extends HandleProps {
- posdirection: string;
- style: React.CSSProperties;
- flowVersion: "legacy";
-}
-
-interface MemoHandlerNextProps extends HandleNextProps {
- posdirection: string;
+type MemoHandlerProps = HandleDefaultProps & {
+ posdirection: "left" | "top";
style: React.CSSProperties;
- flowVersion: "next";
-}
-
-interface MemoHandlerV12Props extends HandleV12Props {
- posdirection: string;
- style: React.CSSProperties;
- flowVersion: "v12";
-}
+};
-type MemoHandlerProps = MemoHandlerLegacyProps | MemoHandlerNextProps | MemoHandlerV12Props;
+type HandleStack = { [key: string]: HandleDefaultProps[] };
const defaultHandles = (flowVersion: ReacFlowVersionSupportProps["flowVersion"]): NodeContentHandleProps[] => {
switch (flowVersion) {
- case "legacy":
- return [{ type: "target" }, { type: "source" }] as NodeContentHandleLegacyProps[];
- case "next":
- return [{ type: "target" }, { type: "source" }] as NodeContentHandleNextProps[];
+ case "v9":
case "v12":
- return [{ type: "target" }, { type: "source" }] as NodeContentHandleV12Props[];
-
+ return [{ type: "target" }, { type: "source" }] as HandleDefaultProps[];
default:
- return [];
+ return [] as HandleDefaultProps[];
}
};
@@ -271,17 +250,17 @@ const getDefaultMinimalTooltipData = (node: any) => {
};
const addHandles = (
- handles: any,
- position: any,
- posDirection: any,
- isConnectable: any,
- nodeStyle: any,
- flowVersion: any = "legacy"
+ handles: HandleStack,
+ position: MemoHandlerProps["position"],
+ posDirection: MemoHandlerProps["posdirection"],
+ isConnectable: MemoHandlerProps["isConnectable"],
+ nodeStyle: MemoHandlerProps["style"],
+ flowVersion: ReacFlowVersionSupportProps["flowVersion"] = ReactFlowVersions.V9
) => {
return handles[position].map((handle: HandleDefaultProps, idx: number) => {
// FIXME: remove? orig v12 change: return handles[position].map((handle: any, idx: any) => {
const { style = {}, ...otherHandleProps } = handle;
- const styleAdditions: { [key: string]: string } = {
+ const styleAdditions: MemoHandlerProps["style"] = {
color: nodeStyle.borderColor ?? undefined,
};
styleAdditions[posDirection] = (100 / (handles[position].length + 1)) * (idx + 1) + "%";
@@ -294,8 +273,10 @@ const addHandles = (
isConnectable: typeof handle.isConnectable !== "undefined" ? handle.isConnectable : isConnectable,
},
};
-
- return ;
+ return (
+
+ );
+ // FIXME: remove? orig v12 change: return ;
});
};
@@ -317,11 +298,12 @@ const MemoHandler = React.memo(
}
);
+const DEFAULT_RESIZE_DIRECTIONS: ResizeDirections = { bottom: true, right: true }
/**
* The `NodeContent` element manages the main view of how a node is displaying which content.
* This element cannot be used directly, all properties must be routed through the `data` property of an `elements` property item inside the `ReactFlow` container.
*/
-export function NodeContent({
+export function NodeContent>({
flowVersion,
iconName,
depiction,
@@ -354,7 +336,7 @@ export function NodeContent({
// resizing
onNodeResize,
nodeDimensions,
- resizeDirections = { bottom: true, right: true },
+ resizeDirections = DEFAULT_RESIZE_DIRECTIONS,
resizeMaxDimensions,
// forwarded props
targetPosition = Position.Left,
@@ -366,11 +348,15 @@ export function NodeContent({
businessData,
// other props for DOM element
...otherDomProps
-}: NodeContentProps) {
+}: NodeContentProps) {
const evaluateFlowVersion = useReactFlowVersion();
const flowVersionCheck = flowVersion || evaluateFlowVersion;
const [introductionDone, setIntroductionDone] = React.useState(false);
+ // ignore some properties for now (remove them later)
+ // if (otherDomProps.businessData) { delete otherDomProps.businessData }
+ // if (otherDomProps.getMinimalTooltipData) { delete otherDomProps.getMinimalTooltipData }
+
const { handles = defaultHandles(flowVersionCheck), ...otherProps } = otherDomProps;
const hasValidResizeDirection = resizeDirections.bottom || resizeDirections.right;
@@ -385,16 +371,13 @@ export function NodeContent({
if (isResizable)
try {
switch (flowVersionCheck) {
- case "legacy":
- [, , zoom] = getStoreStateFlowLegacy((state) => state.transform);
- break;
- case "next":
- [, , zoom] = getStoreStateFlowNext((state) => state.transform);
+ case "v9":
+ [, , zoom] = getStoreStateFlowV9((state) => state.transform);
break;
case "v12":
// we are calling a hook here conditionally. Not recommended, by the flowversion check is
// is basically compile time determined. So we just do it.
- [, , zoom] = useStoreFlowV12((state) => state.transform);
+ [, , zoom] = getStoreStateFlowV12((state) => state.transform);
break;
}
} catch (error) {
@@ -523,19 +506,23 @@ export function NodeContent({
return 0;
})
.forEach((handle) => {
- if ("category" in handle && handle.category === "configuration") {
- handleStack[Position.Top].push(handle);
- } else if (handle.position) {
- handleStack[handle.position].push(handle);
+ let position: HandleDefaultProps["position"] = handle.position;
+
+ // force position regarding special configuration
+ if (handle.category === "configuration") {
+ position = Position.Top;
} else {
const handleType = handle as { type?: string };
if (handleType.type === "target") {
- handleStack[targetPosition].push(handle);
+ position = targetPosition;
}
if (handleType.type === "source") {
- handleStack[sourcePosition].push(handle);
+ position = sourcePosition;
}
}
+
+ handle.position = position;
+ handleStack[position].push(handle);
});
}
const styleExpandDimensions: { [key: string]: string | number } = Object.create(null);
@@ -589,6 +576,7 @@ export function NodeContent({
}}
className={
`${eccgui}-graphviz__node` +
+ ` ${eccgui}-graphviz__node--${flowVersionCheck}` +
` ${eccgui}-graphviz__node--${size}` +
` ${eccgui}-graphviz__node--minimal-${minimalShape}` +
(fullWidth ? ` ${eccgui}-graphviz__node--fullwidth` : "") +
@@ -686,10 +674,38 @@ export function NodeContent({
{!!handles && (
<>
- {addHandles(handleStack, Position.Top, "left", isConnectable, style, flowVersionCheck)}
- {addHandles(handleStack, Position.Right, "top", isConnectable, style, flowVersionCheck)}
- {addHandles(handleStack, Position.Bottom, "left", isConnectable, style, flowVersionCheck)}
- {addHandles(handleStack, Position.Left, "top", isConnectable, style, flowVersionCheck)}
+ {addHandles(
+ handleStack,
+ Position.Top,
+ "left",
+ isConnectable,
+ style as MemoHandlerProps["style"],
+ flowVersionCheck
+ )}
+ {addHandles(
+ handleStack,
+ Position.Right,
+ "top",
+ isConnectable,
+ style as MemoHandlerProps["style"],
+ flowVersionCheck
+ )}
+ {addHandles(
+ handleStack,
+ Position.Bottom,
+ "left",
+ isConnectable,
+ style as MemoHandlerProps["style"],
+ flowVersionCheck
+ )}
+ {addHandles(
+ handleStack,
+ Position.Left,
+ "top",
+ isConnectable,
+ style as MemoHandlerProps["style"],
+ flowVersionCheck
+ )}
>
)}
>
@@ -719,53 +735,59 @@ export function NodeContent({
return validatedHeight;
};
+ const onResize = React.useCallback((_0, _1, _2, d) => {
+ if (nodeContentRef.current) {
+ const nextWidth = resizeDirections.right
+ ? (width ?? originalSize.current.width ?? 0) + d.width
+ : undefined;
+ const nextHeight = resizeDirections.bottom
+ ? (height ?? originalSize.current.height ?? 0) + d.height
+ : undefined;
+ if (nextWidth || nextHeight) {
+ const currentClassNames = nodeContentRef.current.classList;
+ currentClassNames.add("was-resized");
+ }
+ if (nextWidth) {
+ nodeContentRef.current.style.width = `${nextWidth}px`;
+ }
+ if (nextHeight) {
+ nodeContentRef.current.style.height = `${nextHeight}px`;
+ }
+ }
+ }, [resizeDirections, originalSize, width, height])
+
+ const onResizeStop = React.useCallback((_0, _1, _2, d) => {
+ const nextWidth = validateWidth((width ?? originalSize.current.width ?? 0) + d.width);
+ const nextHeight = validateHeight((height ?? originalSize.current.height ?? 0) + d.height);
+ setWidth(nextWidth);
+ setHeight(nextHeight);
+ if (onNodeResize) {
+ onNodeResize({
+ height: nextHeight,
+ width: nextWidth,
+ });
+ }
+ }, [onNodeResize, width, height, originalSize]);
+
+ const resizableSize = React.useMemo(() => ({ height: height ?? "auto", width: width ?? "auto" }), [height, width]);
+ const enableResize = React.useMemo(() => resizeDirections!.bottom && resizeDirections!.right ? { bottomRight: true } : resizeDirections, [resizeDirections]);
+
const resizableNode = () => {
- const size = { height: height ?? "auto", width: width ?? "auto" };
return (
{
- if (nodeContentRef.current) {
- const nextWidth = resizeDirections.right
- ? (width ?? originalSize.current.width ?? 0) + d.width
- : undefined;
- const nextHeight = resizeDirections.bottom
- ? (height ?? originalSize.current.height ?? 0) + d.height
- : undefined;
- if (nextWidth || nextHeight) {
- const currentClassNames = nodeContentRef.current.classList;
- currentClassNames.add("was-resized");
- }
- if (nextWidth) {
- nodeContentRef.current.style.width = `${nextWidth}px`;
- }
- if (nextHeight) {
- nodeContentRef.current.style.height = `${nextHeight}px`;
- }
- }
- }}
- onResizeStop={(_0, _1, _2, d) => {
- const nextWidth = validateWidth((width ?? originalSize.current.width ?? 0) + d.width);
- const nextHeight = validateHeight((height ?? originalSize.current.height ?? 0) + d.height);
- setWidth(nextWidth);
- setHeight(nextHeight);
- if (onNodeResize) {
- onNodeResize({
- height: nextHeight,
- width: nextWidth,
- });
- }
- }}
+ onResize={onResize}
+ onResizeStop={onResizeStop}
>
{nodeContent}
diff --git a/src/extensions/react-flow/nodes/NodeDefault.tsx b/src/extensions/react-flow/nodes/NodeDefault.tsx
index f63974f4b..5b81a076e 100644
--- a/src/extensions/react-flow/nodes/NodeDefault.tsx
+++ b/src/extensions/react-flow/nodes/NodeDefault.tsx
@@ -1,21 +1,25 @@
import React, { memo } from "react";
-import { NodeProps as ReactFlowNodeProps, Position } from "react-flow-renderer";
+import { NodeProps as ReactFlowNodeV9Props } from "react-flow-renderer";
+import { NodeProps as ReactFlowNodeV12Props, Position } from "@xyflow/react";
import { Tooltip } from "../../../index";
import { ReacFlowVersionSupportProps, useReactFlowVersion } from "../versionsupport";
import { NodeContent, NodeContentProps } from "./NodeContent";
-export interface NodeDefaultProps
- extends ReacFlowVersionSupportProps,
- ReactFlowNodeProps {
+interface NodeDefaultExtendedProps extends ReacFlowVersionSupportProps {
/**
* Contains all properties for our implementation of the React-Flow node.
* For details pls see the `NodeContent` element documentation.
*/
- data: NodeContentProps;
+ data: NodeContentProps;
}
+type NodeDefaultV9Props = NodeDefaultExtendedProps & ReactFlowNodeV9Props;
+type NodeDefaultV12Props = NodeDefaultExtendedProps & Omit;
+
+export type NodeDefaultProps = NodeDefaultV9Props | NodeDefaultV12Props;
+
/**
* The `NodeDefault` element manages the display of React-Flow nodes.
* This element cannot be used directly, it must be connected via a `nodeTypes` definition and all properties need to be routed through the `elements` property items inside the `ReactFlow` container.
diff --git a/src/extensions/react-flow/nodes/_nodes.scss b/src/extensions/react-flow/nodes/_nodes.scss
index 87ec1b5a1..a66c953af 100644
--- a/src/extensions/react-flow/nodes/_nodes.scss
+++ b/src/extensions/react-flow/nodes/_nodes.scss
@@ -6,7 +6,7 @@
inset: -6 * $reactflow-node-border-width;
z-index: 0;
content: " ";
- background-color: rgba($reactflow-edge-stroke-color-selected, 0.05);
+ background-color: eccgui-color-rgba($reactflow-edge-stroke-color-selected, 0.05);
border-color: $reactflow-edge-stroke-color-selected;
border-style: dotted;
border-width: 1px;
@@ -29,6 +29,12 @@
box-shadow: none;
}
}
+
+ &.selected,
+ &:focus,
+ &:focus-visible {
+ outline: none;
+ }
}
.#{$eccgui}-graphviz__node {
@@ -47,7 +53,7 @@
border-radius: $reactflow-node-border-radius;
&:hover {
- box-shadow: 0 0 0 6 * $reactflow-node-border-width rgba($reactflow-edge-stroke-color-selected, 0.05);
+ box-shadow: 0 0 0 6 * $reactflow-node-border-width eccgui-color-rgba($reactflow-edge-stroke-color-selected, 0.05);
}
&.was-resized.is-resizable-vertical {
@@ -193,13 +199,13 @@
.#{$eccgui}-graphviz__node__header-label {
display: inline-flex;
- flex-direction: column;
flex-grow: 1;
flex-shrink: 1;
+ flex-direction: column;
margin: 0 $eccgui-size-block-whitespace * 0.25;
overflow: hidden;
- text-align: left;
text-overflow: ellipsis;
+ text-align: left;
white-space: nowrap;
}
@@ -242,24 +248,24 @@
.#{$eccgui}-graphviz__node__resizer--cursorhandles {
position: absolute;
- height: 0;
- width: 0;
- bottom: 0;
right: 0;
- overflow: visible;
+ bottom: 0;
display: none;
+ width: 0;
+ height: 0;
+ overflow: visible;
& > div {
- overflow: visible;
- z-index: 0 !important;
- height: $reactflow-cursor-delimiter-offset * 3 !important;
- width: $reactflow-cursor-delimiter-offset * 3 !important;
top: unset !important;
- left: unset !important;
- bottom: -1 * $reactflow-cursor-delimiter-offset !important;
right: -1 * $reactflow-cursor-delimiter-offset !important;
- border-bottom: $reactflow-node-border-width solid $reactflow-node-border-color;
+ bottom: -1 * $reactflow-cursor-delimiter-offset !important;
+ left: unset !important;
+ z-index: 0 !important;
+ width: $reactflow-cursor-delimiter-offset * 3 !important;
+ height: $reactflow-cursor-delimiter-offset * 3 !important;
+ overflow: visible;
border-right: $reactflow-node-border-width solid $reactflow-node-border-color;
+ border-bottom: $reactflow-node-border-width solid $reactflow-node-border-color;
.#{$eccgui}-graphviz__node__resizer--right:not(.#{$eccgui}-graphviz__node__resizer--bottom) & {
bottom: 0 !important;
@@ -437,8 +443,8 @@
.#{$eccgui}-graphviz__node--introduction-runs {
animation-name: outline;
animation-duration: var(--node-introduction-time);
- animation-play-state: running;
animation-timing-function: linear;
+ animation-play-state: running;
&[data-introduction-animation="landing"] {
animation-name: landing;
@@ -450,48 +456,48 @@
@keyframes landing {
0% {
- filter: blur($eccgui-size-block-whitespace);
outline: solid 0 rgb(0 0 0 / 0%);
outline-offset: 0;
opacity: 0;
+ filter: blur($eccgui-size-block-whitespace);
transform: scale(2);
}
61% {
- filter: blur(0);
outline: solid 0 rgb(0 0 0 / 39%);
outline-offset: 0;
opacity: 1;
+ filter: blur(0);
transform: scale(1);
}
100% {
- filter: blur(0);
outline: solid $eccgui-size-block-whitespace rgb(0 0 0 / 0%);
outline-offset: 2 * $eccgui-size-block-whitespace;
opacity: 1;
+ filter: blur(0);
transform: scale(1);
}
}
@keyframes outline {
0% {
- outline: solid 0 rgba($eccgui-color-accent, 0);
+ outline: solid 0 eccgui-color-rgba($eccgui-color-accent, 0);
outline-offset: 0;
}
9% {
- outline: solid 0.5 * $eccgui-size-block-whitespace rgba($eccgui-color-accent, 0.39);
+ outline: solid 0.5 * $eccgui-size-block-whitespace eccgui-color-rgba($eccgui-color-accent, 0.39);
outline-offset: 0;
}
85% {
- outline: solid 0.5 * $eccgui-size-block-whitespace rgba($eccgui-color-accent, 0.39);
+ outline: solid 0.5 * $eccgui-size-block-whitespace eccgui-color-rgba($eccgui-color-accent, 0.39);
outline-offset: 0;
}
100% {
- outline: solid 0 rgba($eccgui-color-accent, 0);
+ outline: solid 0 eccgui-color-rgba($eccgui-color-accent, 0);
outline-offset: 2 * $eccgui-size-block-whitespace;
}
}
diff --git a/src/extensions/react-flow/nodes/nodeTypes.ts b/src/extensions/react-flow/nodes/nodeTypes.ts
deleted file mode 100644
index 78cb7a17f..000000000
--- a/src/extensions/react-flow/nodes/nodeTypes.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { NodeDefault } from "./NodeDefault";
-
-/** @deprecated (v25) will be removed without replacement, define it yourself or use `): StickyNote => {
+const transformNodeToStickyNode = (node: NodeV9 | NodeV12): StickyNote => {
return {
id: node.id,
content: node.data.businessData.stickyNote!,
@@ -41,7 +49,8 @@ const generateStyleWithColor = (color: string): CSSProperties => {
borderColor: color,
color: colorObj.isLight() ? "#000" : "#fff",
};
- } catch (ex) {
+ } catch {
+ // eslint-disable-next-line no-console
console.warn("Received invalid color for sticky note: " + color);
}
return style;
diff --git a/src/extensions/react-flow/nodes/stories/NodeDefault.stories.tsx b/src/extensions/react-flow/nodes/stories/NodeDefault.stories.tsx
index 43bec8001..8156beef1 100644
--- a/src/extensions/react-flow/nodes/stories/NodeDefault.stories.tsx
+++ b/src/extensions/react-flow/nodes/stories/NodeDefault.stories.tsx
@@ -1,9 +1,8 @@
import React, { useCallback, useEffect, useState } from "react";
-import { Elements } from "react-flow-renderer";
+import { Elements, Node } from "react-flow-renderer";
import { Meta, StoryFn } from "@storybook/react";
import { ReactFlow } from "./../../../../cmem";
-import { NodeContent } from "./../NodeContent";
import { NodeDefault } from "./../NodeDefault";
import { Default as NodeContentExample } from "./NodeContent.stories";
import { nodeTypes } from "./nodeTypes";
@@ -97,10 +96,9 @@ export default {
},
} as Meta;
-const NodeDefaultExample = (args: any) => {
+const NodeDefaultExample = (args: Node) => {
const [reactflowInstance, setReactflowInstance] = useState(null);
const [elements, setElements] = useState([] as Elements);
- //const [edgeTools, setEdgeTools] = useState(<>>);
useEffect(() => {
setElements([args] as Elements);
@@ -126,7 +124,7 @@ const NodeDefaultExample = (args: any) => {
);
};
-const Template: StoryFn = (args) => ;
+const Template: StoryFn = (args) => ;
export const Default = Template.bind({});
Default.args = {
diff --git a/src/extensions/react-flow/versionsupport.ts b/src/extensions/react-flow/versionsupport.ts
index b61414e3a..c0a750014 100644
--- a/src/extensions/react-flow/versionsupport.ts
+++ b/src/extensions/react-flow/versionsupport.ts
@@ -1,27 +1,29 @@
-import { useStoreState as getStoreStateFlowLegacy } from "react-flow-renderer";
-import { useStore as getStoreStateFlowNext } from "react-flow-renderer-lts";
-import { useStore as useStoreFlowV12 } from "@xyflow/react";
+import { useStoreState as getStoreStateFlowV9 } from "react-flow-renderer";
+import { useStore as useStoreStateFlowV12 } from "@xyflow/react";
+
+export const enum ReactFlowVersions {
+ NONE = "none", // mainly here in case some ReactFlow components are used without any react flow containr
+ V9 = "v9",
+ V12 = "v12",
+}
export interface ReacFlowVersionSupportProps {
/**
- * Spevifies the context of the react flow renderer version that is used for the component.
- * @deprecated (v25) `legacy` and `next` will be removed/replaced by `v##` values in future versions
+ * Specifies the context of the react flow renderer version that is used for the component.
*/
- flowVersion?: "v12" | "legacy" | "next" | "none";
+ flowVersion?: ReactFlowVersions.V9 | ReactFlowVersions.V12 | ReactFlowVersions.NONE;
}
export const useReactFlowVersion = () => {
try {
- const [, , zoom] = getStoreStateFlowLegacy((state) => state.transform);
- return zoom ? "legacy" : "none";
- } catch {}
- try {
- const [, , zoom] = getStoreStateFlowNext((state) => state.transform);
- return zoom ? "next" : "none";
+ const [, , zoom] = getStoreStateFlowV9((state) => state.transform);
+ return zoom ? ReactFlowVersions.V9 : ReactFlowVersions.NONE;
+ // eslint-disable-next-line no-empty
} catch {}
try {
- const [, , zoom] = useStoreFlowV12((state) => state.transform);
- return zoom ? "v12" : "none";
+ const [, , zoom] = useStoreStateFlowV12((state) => state.transform);
+ return zoom ? ReactFlowVersions.V12 : ReactFlowVersions.NONE;
+ // eslint-disable-next-line no-empty
} catch {}
- return "none";
+ return ReactFlowVersions.NONE;
};
diff --git a/src/extensions/uppy/_fileupload.scss b/src/extensions/uppy/_fileupload.scss
index b5b01e7b1..dd8598ed5 100644
--- a/src/extensions/uppy/_fileupload.scss
+++ b/src/extensions/uppy/_fileupload.scss
@@ -4,7 +4,7 @@
$eccgui-size-fileupload-border-width: $button-border-width;
$eccgui-size-fileupload-border-radius: $button-border-radius;
-$eccgui-color-fileupload-border: rgba($black, $pt-drop-shadow-opacity);
+$eccgui-color-fileupload-border: eccgui-color-rgba($black, $pt-drop-shadow-opacity);
$eccgui-color-fileupload-background: $eccgui-color-accordion-background-elevated;
$eccgui-color-fileupload-text: inherit;
@@ -36,7 +36,7 @@ $eccgui-color-fileupload-text: inherit;
}
.uppy-DragDrop--isDraggingOver.uppy-DragDrop--isDragDropSupported {
- background-color: rgba($eccgui-color-accent, $eccgui-opacity-ghostly);
+ background-color: eccgui-color-rgba($eccgui-color-accent, $eccgui-opacity-ghostly);
box-shadow: 0 0 $eccgui-size-block-whitespace $eccgui-color-accent inset;
& > * {
diff --git a/src/includes/blueprintjs/_colormap.scss b/src/includes/blueprintjs/_colormap.scss
new file mode 100644
index 000000000..1b961c6fe
--- /dev/null
+++ b/src/includes/blueprintjs/_colormap.scss
@@ -0,0 +1,150 @@
+/**
+ * We map our color palette to the internal color variables of BlueprintJS here.
+ *
+ * blue -> identity info
+ * green -> identity success
+ * orange -> identity warning
+ * red -> identity danger
+ * vermilion -> layout vermilion
+ * rose -> layout pink
+ * violet -> layout violet
+ * indigo -> layout indigo
+ * cerulean -> layout cyan
+ * turquoise -> layout teal
+ * forest -> blueprint green
+ * lime -> layout lime
+ * gold -> extra gold
+ * sepia -> extra bronze
+ */
+
+// Gray scale
+
+$black: eccgui-color-var("identity", "text", "900") !default;
+$dark-gray1: eccgui-color-var("layout", "grey", "900") !default;
+$dark-gray2: eccgui-color-mix(
+ eccgui-color-var("layout", "grey", "900") 80%,
+ eccgui-color-var("layout", "grey", "700")
+) !default;
+$dark-gray3: eccgui-color-mix(
+ eccgui-color-var("layout", "grey", "900") 60%,
+ eccgui-color-var("layout", "grey", "700")
+) !default;
+$dark-gray4: eccgui-color-mix(
+ eccgui-color-var("layout", "grey", "900") 40%,
+ eccgui-color-var("layout", "grey", "700")
+) !default;
+$dark-gray5: eccgui-color-mix(
+ eccgui-color-var("layout", "grey", "900") 20%,
+ eccgui-color-var("layout", "grey", "700")
+) !default;
+$gray1: eccgui-color-mix(
+ eccgui-color-var("layout", "grey", "500") 33%,
+ eccgui-color-var("layout", "grey", "700")
+) !default;
+$gray2: eccgui-color-mix(
+ eccgui-color-var("layout", "grey", "500") 66%,
+ eccgui-color-var("layout", "grey", "700")
+) !default;
+$gray3: eccgui-color-var("layout", "grey", "500") !default;
+$gray4: eccgui-color-mix(
+ eccgui-color-var("layout", "grey", "500") 66%,
+ eccgui-color-var("layout", "grey", "300")
+) !default;
+$gray5: eccgui-color-mix(
+ eccgui-color-var("layout", "grey", "500") 33%,
+ eccgui-color-var("layout", "grey", "300")
+) !default;
+$light-gray1: eccgui-color-mix(
+ eccgui-color-var("layout", "grey", "100") 20%,
+ eccgui-color-var("layout", "grey", "300")
+) !default;
+$light-gray2: eccgui-color-mix(
+ eccgui-color-var("layout", "grey", "100") 40%,
+ eccgui-color-var("layout", "grey", "300")
+) !default;
+$light-gray3: eccgui-color-mix(
+ eccgui-color-var("layout", "grey", "100") 60%,
+ eccgui-color-var("layout", "grey", "300")
+) !default;
+$light-gray4: eccgui-color-mix(
+ eccgui-color-var("layout", "grey", "100") 80%,
+ eccgui-color-var("layout", "grey", "300")
+) !default;
+$light-gray5: eccgui-color-var("layout", "grey", "100") !default;
+$white: eccgui-color-var("identity", "background", "100") !default;
+
+// Core colors
+
+$blue1: eccgui-color-var("semantic", "info", "900") !default;
+$blue2: eccgui-color-var("semantic", "info", "700") !default;
+$blue3: eccgui-color-var("semantic", "info", "500") !default;
+$blue4: eccgui-color-var("semantic", "info", "300") !default;
+$blue5: eccgui-color-var("semantic", "info", "100") !default;
+$green1: eccgui-color-var("semantic", "success", "900") !default;
+$green2: eccgui-color-var("semantic", "success", "700") !default;
+$green3: eccgui-color-var("semantic", "success", "500") !default;
+$green4: eccgui-color-var("semantic", "success", "300") !default;
+$green5: eccgui-color-var("semantic", "success", "100") !default;
+$orange1: eccgui-color-var("semantic", "warning", "900") !default;
+$orange2: eccgui-color-var("semantic", "warning", "700") !default;
+$orange3: eccgui-color-var("semantic", "warning", "500") !default;
+$orange4: eccgui-color-var("semantic", "warning", "300") !default;
+$orange5: eccgui-color-var("semantic", "warning", "100") !default;
+$red1: eccgui-color-var("semantic", "danger", "900") !default;
+$red2: eccgui-color-var("semantic", "danger", "700") !default;
+$red3: eccgui-color-var("semantic", "danger", "500") !default;
+$red4: eccgui-color-var("semantic", "danger", "300") !default;
+$red5: eccgui-color-var("semantic", "danger", "100") !default;
+
+// Extended colors
+
+$vermilion1: eccgui-color-var("layout", "vermilion", "900") !default;
+$vermilion2: eccgui-color-var("layout", "vermilion", "700") !default;
+$vermilion3: eccgui-color-var("layout", "vermilion", "500") !default;
+$vermilion4: eccgui-color-var("layout", "vermilion", "300") !default;
+$vermilion5: eccgui-color-var("layout", "vermilion", "100") !default;
+$rose1: eccgui-color-var("layout", "pink", "900") !default;
+$rose2: eccgui-color-var("layout", "pink", "700") !default;
+$rose3: eccgui-color-var("layout", "pink", "500") !default;
+$rose4: eccgui-color-var("layout", "pink", "300") !default;
+$rose5: eccgui-color-var("layout", "pink", "100") !default;
+$violet1: eccgui-color-var("layout", "violet", "900") !default;
+$violet2: eccgui-color-var("layout", "violet", "700") !default;
+$violet3: eccgui-color-var("layout", "violet", "500") !default;
+$violet4: eccgui-color-var("layout", "violet", "300") !default;
+$violet5: eccgui-color-var("layout", "violet", "100") !default;
+$indigo1: eccgui-color-var("layout", "indigo", "900") !default;
+$indigo2: eccgui-color-var("layout", "indigo", "700") !default;
+$indigo3: eccgui-color-var("layout", "indigo", "500") !default;
+$indigo4: eccgui-color-var("layout", "indigo", "300") !default;
+$indigo5: eccgui-color-var("layout", "indigo", "100") !default;
+$cerulean1: eccgui-color-var("layout", "cyan", "900") !default;
+$cerulean2: eccgui-color-var("layout", "cyan", "700") !default;
+$cerulean3: eccgui-color-var("layout", "cyan", "500") !default;
+$cerulean4: eccgui-color-var("layout", "cyan", "300") !default;
+$cerulean5: eccgui-color-var("layout", "cyan", "100") !default;
+$turquoise1: eccgui-color-var("layout", "teal", "900") !default;
+$turquoise2: eccgui-color-var("layout", "teal", "700") !default;
+$turquoise3: eccgui-color-var("layout", "teal", "500") !default;
+$turquoise4: eccgui-color-var("layout", "teal", "300") !default;
+$turquoise5: eccgui-color-var("layout", "teal", "100") !default;
+$forest1: $green1 !default;
+$forest2: $green2 !default;
+$forest3: $green3 !default;
+$forest4: $green4 !default;
+$forest5: $green5 !default;
+$lime1: eccgui-color-var("layout", "lime", "900") !default;
+$lime2: eccgui-color-var("layout", "lime", "700") !default;
+$lime3: eccgui-color-var("layout", "lime", "500") !default;
+$lime4: eccgui-color-var("layout", "lime", "300") !default;
+$lime5: eccgui-color-var("layout", "lime", "100") !default;
+$gold1: eccgui-color-var("extra", "gold", "900") !default;
+$gold2: eccgui-color-var("extra", "gold", "700") !default;
+$gold3: eccgui-color-var("extra", "gold", "500") !default;
+$gold4: eccgui-color-var("extra", "gold", "300") !default;
+$gold5: eccgui-color-var("extra", "gold", "100") !default;
+$sepia1: eccgui-color-var("extra", "bronze", "900") !default;
+$sepia2: eccgui-color-var("extra", "bronze", "700") !default;
+$sepia3: eccgui-color-var("extra", "bronze", "500") !default;
+$sepia4: eccgui-color-var("extra", "bronze", "300") !default;
+$sepia5: eccgui-color-var("extra", "bronze", "100") !default;
diff --git a/src/includes/blueprintjs/_variables.scss b/src/includes/blueprintjs/_variables.scss
index 8787cac68..4a9903f13 100644
--- a/src/includes/blueprintjs/_variables.scss
+++ b/src/includes/blueprintjs/_variables.scss
@@ -1,21 +1,52 @@
-@use "sass:math";
+/**
+ * Stack of BlueprintJS variables that are necessary to use their framework
+ * - calculate them from own configuration variables here
+ * - see blueprint import for variables that need to be overwritten with other values
+ */
-// Stack of BlueprintJS variables that are necessary to use their framework
-// calculate them from own configuration variables here
-// see blueprint import for variables that need to be overwritten with other values
+@use "sass:math";
$icon-font-path: "~@blueprintjs/icons/resources/icons" !default;
-// Color aliases
+/**
+ * Color aliases
+ *
+ * original: https://github.com/palantir/blueprint/blob/develop/packages/core/src/common/_color-aliases.scss
+ */
$pt-intent-primary: $eccgui-color-accent !default;
$pt-intent-success: $eccgui-color-success-text !default;
$pt-intent-warning: $eccgui-color-warning-text !default;
$pt-intent-danger: $eccgui-color-danger-text !default;
-$pt-outline-color: rgba($eccgui-color-accent, 0.6);
-$pt-text-color: $eccgui-color-application-text !default;
+$pt-app-background-color: $eccgui-color-workspace-background !default;
+$pt-app-secondary-background-color: eccgui-color-var("identity", "background", "300") !default;
+$pt-app-elevated-background-color: eccgui-color-var("identity", "background", "500") !default;
+$pt-outline-color: eccgui-color-rgba($eccgui-color-accent, $eccgui-opacity-muted) !default;
+$pt-focus-indicator-color: eccgui-color-rgba($eccgui-color-accent, $eccgui-opacity-narrow) !default;
+$pt-text-color: $eccgui-color-workspace-text !default;
+$pt-text-color-muted: eccgui-color-var("identity", "text", "500") !default;
+$pt-text-color-disabled: eccgui-color-rgba($eccgui-color-workspace-text, $eccgui-opacity-disabled) !default;
+$pt-heading-color: $pt-text-color !default;
+$pt-link-color: $eccgui-color-accent !default;
+$pt-text-selection-color: eccgui-color-rgba(
+ eccgui-color-var("identity", "accent", "300"),
+ $eccgui-opacity-muted
+) !default;
+$pt-icon-color: $eccgui-color-workspace-text !default;
+$pt-icon-color-hover: $eccgui-color-workspace-text !default;
+$pt-icon-color-disabled: $pt-text-color-disabled !default;
+$pt-icon-color-selected: $pt-intent-primary !default;
+$pt-divider-black: eccgui-color-rgba(eccgui-color-var("identity", "text", "500"), $eccgui-opacity-ghostly) !default;
+$pt-divider-black-muted: eccgui-color-rgba(
+ eccgui-color-var("identity", "text", "300"),
+ $eccgui-opacity-ghostly
+) !default;
+$pt-code-text-color: $pt-text-color !default;
+$pt-code-background-color: $eccgui-color-workspace-background !default;
-// Size aliases
+/**
+ * Size aliases
+ */
// easily the most important variable, so it comes up top
// (so other variables can use it to define themselves)
@@ -26,6 +57,5 @@ $pt-font-size: $eccgui-size-typo-text !default;
$pt-font-size-large: $eccgui-size-typo-subtitle !default;
$pt-font-size-small: $eccgui-size-typo-caption !default;
$pt-line-height: $eccgui-size-typo-text-lineheight !default;
-
$pt-icon-size-standard: 20px !default;
$pt-icon-size-large: 32px !default;
diff --git a/src/includes/carbon-components/_variables.scss b/src/includes/carbon-components/_variables.scss
index dc050b8d8..440dbfcc5 100644
--- a/src/includes/carbon-components/_variables.scss
+++ b/src/includes/carbon-components/_variables.scss
@@ -1,7 +1,12 @@
-@use "sass:math";
+/**
+ * Stack of Carbon variables that are necessary to use their framework
+ * - calculate them from own configuration variables here
+ * - see blueprint import for variables that need to be overwritten with other values
+ */
-// Stack of Carbon variables that are necessary to use their framework
-// TODO: calculate them from own configuration variables, all unchanged variables are commented out
+ @use "sass:math";
+
+// Configuration
$prefix: "cds" !default;
$flex-grid-columns: 16 !default;
@@ -31,6 +36,8 @@ $base-font-size: $eccgui-size-typo-base !default;
@import "~@carbon/react/scss/utilities/convert";
+// Typography
+
$label-01: (
font-size: rem($eccgui-size-typo-caption),
line-height: math.div($eccgui-size-typo-text-lineheight, $eccgui-size-type-levelratio),
@@ -75,6 +82,18 @@ $heading-02: (
font-weight: 600,
line-height: $eccgui-size-typo-text-lineheight * $eccgui-size-type-levelratio,
) !default;
+
+// Sizes
+
+$spacing-05: rem($eccgui-size-inline-whitespace) !default;
+$spacing-09: rem($eccgui-size-block-whitespace * 2 * $eccgui-size-type-levelratio) !default;
+
+// Colors
+// original:
+// - node_modules/@carbon/themes/scss/compat/generated/_tokens.scss
+// - node_modules/@carbon/themes/scss/generated/_tokens.scss
+// FIXME: for some unknown reasons it is not possible to set the $layer* vars here, for example they are used to color the tables
+
$layer-01: transparent !default;
$layer-02: $eccgui-color-workspace-background !default;
$ui-03: $pt-divider-black !default;
@@ -90,16 +109,12 @@ $background-hover: $hover-ui !default;
$layer-hover-01: $hover-ui !default;
$field-hover-01: $hover-ui !default;
$field-hover-02: $hover-ui !default;
-$disabled-02: rgba($text-primary, $eccgui-opacity-disabled) !default;
+$disabled-02: eccgui-color-rgba($text-primary, $eccgui-opacity-disabled) !default;
$text-disabled: $disabled-02 !default;
$icon-disabled: $disabled-02 !default;
$button-disabled: $disabled-02 !default;
$border-disabled: $disabled-02 !default;
-$spacing-05: rem($eccgui-size-inline-whitespace) !default;
-$spacing-09: rem($eccgui-size-block-whitespace * 2 * $eccgui-size-type-levelratio) !default;
$data-table-zebra-color: $layer-02 !default;
-// FIXME: for some unknown reasons it is not possible to set the $layer* vars here, for example they are used to color the tables
-
// fetch some imports even earlier than normally necessary to have them ready before auto-included by library elements
@import "./../../components/Button/button";
diff --git a/src/index.scss b/src/index.scss
index c0ff9fd7e..f67071123 100644
--- a/src/index.scss
+++ b/src/index.scss
@@ -1,3 +1,11 @@
+// == library prefix for variables and selectors ===============================
+
+@import "./configuration/libprefix";
+
+// == load helper functions ====================================================
+
+@import "./common/scss/color-functions";
+
// == load default configuration ===============================================
@import "./configuration/variables";
@@ -16,6 +24,9 @@
// calculate blueprintjs configuration
@import "./includes/blueprintjs/variables";
+// map our palette to BLueprint colors
+@import "./includes/blueprintjs/colormap";
+
// load blueprintjs requisists
@import "./includes/blueprintjs/requisits";
diff --git a/src/index.ts b/src/index.ts
index 99fa9d865..b6b9e8c56 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -3,7 +3,6 @@ import { Classes as BlueprintClasses } from "@blueprintjs/core";
import { ClassNames as IntentClassNames } from "./common/Intent";
import * as Skeleton from "./components/Skeleton/classnames";
import * as TypographyClassNames from "./components/Typography/classnames";
-import * as LegacyReplacements from "./legacy-replacements";
const ClassNames = {
Blueprint: BlueprintClasses,
@@ -18,4 +17,4 @@ export * from "./components";
export * from "./extensions";
export * from "./cmem";
-export { ClassNames, LegacyReplacements };
+export { ClassNames };
diff --git a/src/legacy-replacements/Button/AffirmativeButton.tsx b/src/legacy-replacements/Button/AffirmativeButton.tsx
deleted file mode 100644
index 734f32701..000000000
--- a/src/legacy-replacements/Button/AffirmativeButton.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from "react";
-
-import { ButtonReplacement } from "./Button";
-
-/** @deprecated (v25) all legacy component support will be removed, switch to ` ` */
-export function AffirmativeButtonReplacement({ children, ...otherProps }: any) {
- return (
-
- {children}
-
- );
-}
diff --git a/src/legacy-replacements/Button/Button.tsx b/src/legacy-replacements/Button/Button.tsx
deleted file mode 100644
index 7cbe6c182..000000000
--- a/src/legacy-replacements/Button/Button.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import React from "react";
-
-import Button from "../../components/Button/Button";
-
-export const iconMappings: { [key: string]: any } = {
- edit: "item-edit",
- delete: "item-remove",
- expand_more: "toggler-showmore",
- expand_less: "toggler-showless",
- arrow_nextpage: "navigation-forth",
- arrow_back: "navigation-back",
-};
-
-/** @deprecated (v25) all legacy component support will be removed, switch to ` ` */
-export function ButtonReplacement({
- children,
- className,
- fabSize,
- iconName,
- tooltip,
- progress,
- disabled = false,
- affirmative = false,
- dismissive = true,
- disruptive = false,
- raised = false,
- colored = false,
- ...otherProps
-}: any) {
- if (process.env.NODE_ENV === "development") {
- const debugMsg = [
- "This button element is a adhoc replacement for a legacy element. Usage is deprecated, please use a standard element (Button).",
- ];
- if (typeof otherProps.accent !== "undefined") {
- debugMsg.push("Button 'accent' property is not supported on legacy replacement element.");
- delete otherProps.accent;
- }
- if (typeof otherProps.badge !== "undefined") {
- debugMsg.push("Button 'badge' property is not supported on legacy replacement element.");
- delete otherProps.badge;
- }
- if (typeof otherProps.ripple !== "undefined") {
- debugMsg.push("Button 'ripple' property is not supported on legacy replacement element.");
- delete otherProps.ripple;
- }
- if (typeof progress !== "undefined") {
- debugMsg.push(
- "Button 'progress' property is not fully supported on legacy replacement element, it only shows a loading spinner in the button."
- );
- }
- // eslint-disable-next-line no-console
- debugMsg.forEach((element) => console.debug(element));
- }
- if (typeof otherProps.accent !== "undefined") {
- delete otherProps.accent;
- }
- if (typeof otherProps.badge !== "undefined") {
- delete otherProps.badge;
- }
- if (typeof otherProps.ripple !== "undefined") {
- delete otherProps.ripple;
- }
- return (
-
- {children}
-
- );
-}
diff --git a/src/legacy-replacements/Button/DismissiveButton.tsx b/src/legacy-replacements/Button/DismissiveButton.tsx
deleted file mode 100644
index 99516317f..000000000
--- a/src/legacy-replacements/Button/DismissiveButton.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from "react";
-
-import { ButtonReplacement } from "./Button";
-
-/** @deprecated (v25) all legacy component support will be removed, switch to ` ` */
-export function DismissiveButtonReplacement({ children, ...otherProps }: any) {
- return (
-
- {children}
-
- );
-}
diff --git a/src/legacy-replacements/Button/DisruptiveButton.tsx b/src/legacy-replacements/Button/DisruptiveButton.tsx
deleted file mode 100644
index ceb25aa46..000000000
--- a/src/legacy-replacements/Button/DisruptiveButton.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from "react";
-
-import { ButtonReplacement } from "./Button";
-
-/** @deprecated (v25) all legacy component support will be removed, switch to ` ` */
-export function DisruptiveButtonReplacement({ children, ...otherProps }: any) {
- return (
-
- {children}
-
- );
-}
diff --git a/src/legacy-replacements/Checkbox/Checkbox.tsx b/src/legacy-replacements/Checkbox/Checkbox.tsx
deleted file mode 100644
index b9940aca1..000000000
--- a/src/legacy-replacements/Checkbox/Checkbox.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import React from "react";
-
-import Checkbox from "../../components/Checkbox/Checkbox";
-
-const extendedOnChangeBoolean = (onChangeFn: any, event: any) => {
- if (typeof onChangeFn === "function") {
- onChangeFn({
- event,
- name: event.target.name,
- value: event.target.checked,
- rawValue: event.target.value,
- });
- }
-};
-
-/** @deprecated (v25) all legacy component support will be removed, switch to ` ` */
-export function CheckboxReplacement({
- children = null,
- checked = false,
- className = null,
- disabled = false,
- label = null,
- onChange,
- ...otherProps
-}: any) {
- if (process.env.NODE_ENV === "development") {
- const debugMsg = [
- "This checkbox element is a adhoc replacement for a legacy element. Usage is deprecated, please use a standard element (Checkbox).",
- ];
- if (typeof otherProps.ripple !== "undefined") {
- debugMsg.push("Checkbox 'ripple' property is not supported on legacy replacement element.");
- delete otherProps.ripple;
- }
- if (typeof otherProps.hideLabel !== "undefined") {
- debugMsg.push("Checkbox 'hideLabel' property is not supported on legacy replacement element.");
- delete otherProps.hideLabel;
- }
- // eslint-disable-next-line no-console
- debugMsg.forEach((element) => console.debug(element));
- }
- if (typeof otherProps.ripple !== "undefined") {
- delete otherProps.ripple;
- }
- if (typeof otherProps.hideLabel !== "undefined") {
- delete otherProps.hideLabel;
- }
- return (
-
- {label}
- {children}
-
- );
-}
diff --git a/src/legacy-replacements/Radio/RadioButton.tsx b/src/legacy-replacements/Radio/RadioButton.tsx
deleted file mode 100644
index d8cb0b334..000000000
--- a/src/legacy-replacements/Radio/RadioButton.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from "react";
-
-import RadioButton from "../../components/RadioButton/RadioButton";
-
-/** @deprecated (v25) all legacy component support will be removed, switch to ` ` */
-export function RadioButtonReplacement({ children, label, ...otherProps }: any) {
- if (process.env.NODE_ENV === "development") {
- const debugMsg = [
- "This radio element is a adhoc replacement for a legacy element. Usage is deprecated, please use a standard element (RadioButton).",
- ];
- if (typeof otherProps.ripple !== "undefined") {
- debugMsg.push("Radio 'ripple' property is not supported on legacy replacement element.");
- delete otherProps.ripple;
- }
- if (typeof otherProps.hideLabel !== "undefined") {
- debugMsg.push("Radio 'hideLabel' property is not supported on legacy replacement element.");
- delete otherProps.hideLabel;
- }
- if (typeof label !== "undefined") {
- debugMsg.push("Radio 'label' property is not supported exactly like at the legacy element.");
- }
- // eslint-disable-next-line no-console
- debugMsg.forEach((element) => console.debug(element));
- }
- if (typeof otherProps.ripple !== "undefined") {
- delete otherProps.ripple;
- }
- if (typeof otherProps.hideLabel !== "undefined") {
- delete otherProps.hideLabel;
- }
- return (
-
- {label}
- {children}
-
- );
-}
diff --git a/src/legacy-replacements/Tabs/Tabs.stories.tsx b/src/legacy-replacements/Tabs/Tabs.stories.tsx
deleted file mode 100644
index aa0806ff0..000000000
--- a/src/legacy-replacements/Tabs/Tabs.stories.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from "react";
-import { Meta, StoryFn } from "@storybook/react";
-
-import { Tabs } from "./../../legacy-replacements";
-
-export default {
- title: "Legacy/Tabs",
- component: Tabs,
- argTypes: {
- },
-} as Meta;
-
-const TemplateDeprecated: StoryFn = (args) => ;
-
-export const DeprecatedUsage = TemplateDeprecated.bind({});
-DeprecatedUsage.args = {
- prefixTabNames: "deprecatedtabs",
- activeTab: "deprecatedtab1",
- tabs: [
- {
- tabId: "deprecatedtab1",
- tabTitle: "Tab title 1",
- tabContent: "Tab content 1",
- },
- {
- tabId: "deprecatedtab2",
- tabTitle: "Tab title 2",
- tabContent: "Tab content 2",
- },
- {
- tabId: "deprecatedtab3",
- tabTitle: "Tab title 3",
- tabContent: "Tab content 3",
- },
- ],
-};
diff --git a/src/legacy-replacements/Tabs/Tabs.tsx b/src/legacy-replacements/Tabs/Tabs.tsx
deleted file mode 100644
index 4892debb7..000000000
--- a/src/legacy-replacements/Tabs/Tabs.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import React from "react";
-import { Tab, Tabs as BlueprintTabs, TabsProps as BlueprintTabsProps } from "@blueprintjs/core";
-
-import { CLASSPREFIX as eccgui } from "../../configuration/constants";
-
-// legacy interface
-interface LegacyTabsProps extends Omit {
- activeTab: string;
- tabs: DeprecatedTabProps[];
- onTabClick?: ({ props }: any) => void;
- prefixTabNames: string;
- allowScrollbars?: boolean;
- /**
- * If controlled usage is enable then a `onTabClick` handler is ncessary to control tab panel content and `activeTab` updates.
- */
- controlled?: boolean;
-}
-
-/** @deprecated (v25) all legacy component support will be removed */
-export interface DeprecatedTabProps {
- tabId: string;
- tabTitle: React.ReactNode;
- tabContent?: JSX.Element;
- dontShrink?: boolean;
- className?: string;
-}
-
-const createDeprecatedTab = ({
- tabId,
- tabTitle,
- tabContent,
- dontShrink = false,
- ...otherTabProps
-}: DeprecatedTabProps) => {
- const extraStyles = dontShrink ? { style: { flexShrink: 0 } } : {};
- return ;
-};
-
-/** @deprecated (v25) all legacy component support will be removed, switch to ` ` */
-export function TabsReplacement({
- activeTab,
- tabs = [],
- onTabClick,
- controlled = false,
- prefixTabNames,
- className = "",
- allowScrollbars,
- ...restProps
-}: LegacyTabsProps) {
- const usagetype = controlled ? { selectedTabId: activeTab } : { defaultSelectedTabId: activeTab };
- return (
-
- {tabs.map((tab) => {
- return createDeprecatedTab({
- className: `${prefixTabNames}-header-${tab.tabId}`,
- ...tab,
- });
- })}
-
- );
-}
diff --git a/src/legacy-replacements/TextField/TextField.tsx b/src/legacy-replacements/TextField/TextField.tsx
deleted file mode 100644
index 1501156ca..000000000
--- a/src/legacy-replacements/TextField/TextField.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import React from "react";
-
-import { FieldItem, IconButton, TextArea, TextField } from "./../../index";
-
-const extendedOnChange = (onChangeFn: any, event: any) => {
- if (typeof onChangeFn === "function") {
- onChangeFn({
- event,
- name: event.target.name,
- value: event.target.value,
- rawValue: event.target.value,
- });
- }
-};
-
-/** @deprecated (v25) all legacy component support will be removed, switch to ` `, ``, ` ` */
-export function TextFieldReplacement({
- className,
- disabled = false,
- error,
- inputClassName,
- label,
- multiline = false,
- onChange,
- onClearValue,
- // reducedSize = false,
- required = false,
- stretch = true,
- value,
- ...otherProps
-}: any) {
- if (process.env.NODE_ENV === "development") {
- const debugMsg = [
- "This textfield element is a adhoc replacement for a legacy element. Usage is deprecated, please use a standard elements (FieldItem, TextField, TextArea).",
- ];
- if (typeof otherProps.reducedSize !== "undefined") {
- debugMsg.push("TextField 'reducedSize' property is currently not supported on legacy replacement element.");
- delete otherProps.reducedSize;
- }
- // eslint-disable-next-line no-console
- debugMsg.forEach((element) => console.debug(element));
- }
- if (typeof otherProps.reducedSize !== "undefined") {
- delete otherProps.reducedSize;
- }
-
- const InputElement = multiline ? TextArea : TextField;
-
- const fieldProperties = {
- className: className,
- messageText: error,
- labelProps: label ? { text: label } : {},
- };
-
- const inputProperties: { [key: string]: any } = {
- className: inputClassName,
- fullWidth: stretch,
- value: value,
- required: required,
- onChange: extendedOnChange.bind(null, onChange),
- };
-
- if (multiline) {
- delete inputProperties.fullWidth;
- }
-
- if (multiline === false && !!onClearValue && !!value) {
- inputProperties["rightElement"] = (
-
- );
- }
-
- const sharedProperties = {
- hasStateDanger: error ? true : false,
- disabled: disabled,
- };
-
- return !!error || !!label ? (
-
-
-
- ) : (
-
- );
-}
diff --git a/src/legacy-replacements/index.ts b/src/legacy-replacements/index.ts
deleted file mode 100644
index 7239a7597..000000000
--- a/src/legacy-replacements/index.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export { ButtonReplacement as Button } from "./Button/Button";
-export { AffirmativeButtonReplacement as AffirmativeButton } from "./Button/AffirmativeButton";
-export { DismissiveButtonReplacement as DismissiveButton } from "./Button/DismissiveButton";
-export { DisruptiveButtonReplacement as DisruptiveButton } from "./Button/DisruptiveButton";
-export { ButtonReplacement as ProgressButton } from "./Button/Button";
-export { CheckboxReplacement as Checkbox } from "./Checkbox/Checkbox";
-export { RadioButtonReplacement as Radio } from "./Radio/RadioButton";
-export { TabsReplacement as Tabs } from "./Tabs/Tabs";
-export { TextFieldReplacement as TextField } from "./TextField/TextField";
-
-export type { DeprecatedTabProps } from "./Tabs/Tabs";
diff --git a/yarn.lock b/yarn.lock
index 4671b72c5..022500e5a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1104,7 +1104,7 @@
pirates "^4.0.6"
source-map-support "^0.5.16"
-"@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.7", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.9", "@babel/runtime@^7.24.5", "@babel/runtime@^7.24.7", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
+"@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.7", "@babel/runtime@^7.17.8", "@babel/runtime@^7.24.5", "@babel/runtime@^7.24.7", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
version "7.27.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.0.tgz#fbee7cf97c709518ecc1f590984481d5460d4762"
integrity sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==
@@ -1375,7 +1375,7 @@
"@lezer/common" "^1.0.2"
"@lezer/css" "^1.1.7"
-"@codemirror/lang-html@^6.0.0":
+"@codemirror/lang-html@^6.0.0", "@codemirror/lang-html@^6.4.9":
version "6.4.9"
resolved "https://registry.yarnpkg.com/@codemirror/lang-html/-/lang-html-6.4.9.tgz#d586f2cc9c341391ae07d1d7c545990dfa069727"
integrity sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==
@@ -1924,50 +1924,50 @@
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98"
integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
-"@jest/console@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/console/-/console-30.0.5.tgz#d7d027c2db5c64c20a973b7f3e57b49956d6c335"
- integrity sha512-xY6b0XiL0Nav3ReresUarwl2oIz1gTnxGbGpho9/rbUWsLH0f1OD/VT84xs8c7VmH7MChnLb0pag6PhZhAdDiA==
+"@jest/console@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/console/-/console-30.2.0.tgz#c52fcd5b58fdd2e8eb66b2fd8ae56f2f64d05b28"
+ integrity sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==
dependencies:
- "@jest/types" "30.0.5"
+ "@jest/types" "30.2.0"
"@types/node" "*"
chalk "^4.1.2"
- jest-message-util "30.0.5"
- jest-util "30.0.5"
+ jest-message-util "30.2.0"
+ jest-util "30.2.0"
slash "^3.0.0"
-"@jest/core@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/core/-/core-30.0.5.tgz#b5778922d2928f676636e3ec199829554e61e452"
- integrity sha512-fKD0OulvRsXF1hmaFgHhVJzczWzA1RXMMo9LTPuFXo9q/alDbME3JIyWYqovWsUBWSoBcsHaGPSLF9rz4l9Qeg==
+"@jest/core@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/core/-/core-30.2.0.tgz#813d59faa5abd5510964a8b3a7b17cc77b775275"
+ integrity sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==
dependencies:
- "@jest/console" "30.0.5"
+ "@jest/console" "30.2.0"
"@jest/pattern" "30.0.1"
- "@jest/reporters" "30.0.5"
- "@jest/test-result" "30.0.5"
- "@jest/transform" "30.0.5"
- "@jest/types" "30.0.5"
+ "@jest/reporters" "30.2.0"
+ "@jest/test-result" "30.2.0"
+ "@jest/transform" "30.2.0"
+ "@jest/types" "30.2.0"
"@types/node" "*"
ansi-escapes "^4.3.2"
chalk "^4.1.2"
ci-info "^4.2.0"
exit-x "^0.2.2"
graceful-fs "^4.2.11"
- jest-changed-files "30.0.5"
- jest-config "30.0.5"
- jest-haste-map "30.0.5"
- jest-message-util "30.0.5"
+ jest-changed-files "30.2.0"
+ jest-config "30.2.0"
+ jest-haste-map "30.2.0"
+ jest-message-util "30.2.0"
jest-regex-util "30.0.1"
- jest-resolve "30.0.5"
- jest-resolve-dependencies "30.0.5"
- jest-runner "30.0.5"
- jest-runtime "30.0.5"
- jest-snapshot "30.0.5"
- jest-util "30.0.5"
- jest-validate "30.0.5"
- jest-watcher "30.0.5"
+ jest-resolve "30.2.0"
+ jest-resolve-dependencies "30.2.0"
+ jest-runner "30.2.0"
+ jest-runtime "30.2.0"
+ jest-snapshot "30.2.0"
+ jest-util "30.2.0"
+ jest-validate "30.2.0"
+ jest-watcher "30.2.0"
micromatch "^4.0.8"
- pretty-format "30.0.5"
+ pretty-format "30.2.0"
slash "^3.0.0"
"@jest/diff-sequences@30.0.1":
@@ -1975,35 +1975,35 @@
resolved "https://registry.yarnpkg.com/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz#0ededeae4d071f5c8ffe3678d15f3a1be09156be"
integrity sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==
-"@jest/environment-jsdom-abstract@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/environment-jsdom-abstract/-/environment-jsdom-abstract-30.0.5.tgz#7299cca59b3e84547ca3d1bbd4e7d36b4b44d426"
- integrity sha512-gpWwiVxZunkoglP8DCnT3As9x5O8H6gveAOpvaJd2ATAoSh7ZSSCWbr9LQtUMvr8WD3VjG9YnDhsmkCK5WN1rQ==
+"@jest/environment-jsdom-abstract@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/environment-jsdom-abstract/-/environment-jsdom-abstract-30.2.0.tgz#1313f9b3b509c31298c241203161b36622865181"
+ integrity sha512-kazxw2L9IPuZpQ0mEt9lu9Z98SqR74xcagANmMBU16X0lS23yPc0+S6hGLUz8kVRlomZEs/5S/Zlpqwf5yu6OQ==
dependencies:
- "@jest/environment" "30.0.5"
- "@jest/fake-timers" "30.0.5"
- "@jest/types" "30.0.5"
+ "@jest/environment" "30.2.0"
+ "@jest/fake-timers" "30.2.0"
+ "@jest/types" "30.2.0"
"@types/jsdom" "^21.1.7"
"@types/node" "*"
- jest-mock "30.0.5"
- jest-util "30.0.5"
+ jest-mock "30.2.0"
+ jest-util "30.2.0"
-"@jest/environment@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-30.0.5.tgz#eaaae0403c7d3f8414053c2224acc3011e1c3a1b"
- integrity sha512-aRX7WoaWx1oaOkDQvCWImVQ8XNtdv5sEWgk4gxR6NXb7WBUnL5sRak4WRzIQRZ1VTWPvV4VI4mgGjNL9TeKMYA==
+"@jest/environment@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-30.2.0.tgz#1e673cdb8b93ded707cf6631b8353011460831fa"
+ integrity sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==
dependencies:
- "@jest/fake-timers" "30.0.5"
- "@jest/types" "30.0.5"
+ "@jest/fake-timers" "30.2.0"
+ "@jest/types" "30.2.0"
"@types/node" "*"
- jest-mock "30.0.5"
+ jest-mock "30.2.0"
-"@jest/expect-utils@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-30.0.5.tgz#9d42e4b8bc80367db30abc6c42b2cb14073f66fc"
- integrity sha512-F3lmTT7CXWYywoVUGTCmom0vXq3HTTkaZyTAzIy+bXSBizB7o5qzlC9VCtq0arOa8GqmNsbg/cE9C6HLn7Szew==
+"@jest/expect-utils@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-30.2.0.tgz#4f95413d4748454fdb17404bf1141827d15e6011"
+ integrity sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==
dependencies:
- "@jest/get-type" "30.0.1"
+ "@jest/get-type" "30.1.0"
"@jest/expect-utils@^29.7.0":
version "29.7.0"
@@ -2012,40 +2012,40 @@
dependencies:
jest-get-type "^29.6.3"
-"@jest/expect@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-30.0.5.tgz#2bbd101df4869f5d171c3cfee881f810f1525005"
- integrity sha512-6udac8KKrtTtC+AXZ2iUN/R7dp7Ydry+Fo6FPFnDG54wjVMnb6vW/XNlf7Xj8UDjAE3aAVAsR4KFyKk3TCXmTA==
+"@jest/expect@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-30.2.0.tgz#9a5968499bb8add2bbb09136f69f7df5ddbf3185"
+ integrity sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==
dependencies:
- expect "30.0.5"
- jest-snapshot "30.0.5"
+ expect "30.2.0"
+ jest-snapshot "30.2.0"
-"@jest/fake-timers@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-30.0.5.tgz#c028a9465a44b7744cb2368196bed89ce13c7054"
- integrity sha512-ZO5DHfNV+kgEAeP3gK3XlpJLL4U3Sz6ebl/n68Uwt64qFFs5bv4bfEEjyRGK5uM0C90ewooNgFuKMdkbEoMEXw==
+"@jest/fake-timers@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-30.2.0.tgz#0941ddc28a339b9819542495b5408622dc9e94ec"
+ integrity sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==
dependencies:
- "@jest/types" "30.0.5"
+ "@jest/types" "30.2.0"
"@sinonjs/fake-timers" "^13.0.0"
"@types/node" "*"
- jest-message-util "30.0.5"
- jest-mock "30.0.5"
- jest-util "30.0.5"
+ jest-message-util "30.2.0"
+ jest-mock "30.2.0"
+ jest-util "30.2.0"
-"@jest/get-type@30.0.1":
- version "30.0.1"
- resolved "https://registry.yarnpkg.com/@jest/get-type/-/get-type-30.0.1.tgz#0d32f1bbfba511948ad247ab01b9007724fc9f52"
- integrity sha512-AyYdemXCptSRFirI5EPazNxyPwAL0jXt3zceFjaj8NFiKP9pOi0bfXonf6qkf82z2t3QWPeLCWWw4stPBzctLw==
+"@jest/get-type@30.1.0":
+ version "30.1.0"
+ resolved "https://registry.yarnpkg.com/@jest/get-type/-/get-type-30.1.0.tgz#4fcb4dc2ebcf0811be1c04fd1cb79c2dba431cbc"
+ integrity sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==
-"@jest/globals@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-30.0.5.tgz#ca70e0ac08ab40417cf8cd92bcb76116c2ccca63"
- integrity sha512-7oEJT19WW4oe6HR7oLRvHxwlJk2gev0U9px3ufs8sX9PoD1Eza68KF0/tlN7X0dq/WVsBScXQGgCldA1V9Y/jA==
+"@jest/globals@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-30.2.0.tgz#2f4b696d5862664b89c4ee2e49ae24d2bb7e0988"
+ integrity sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==
dependencies:
- "@jest/environment" "30.0.5"
- "@jest/expect" "30.0.5"
- "@jest/types" "30.0.5"
- jest-mock "30.0.5"
+ "@jest/environment" "30.2.0"
+ "@jest/expect" "30.2.0"
+ "@jest/types" "30.2.0"
+ jest-mock "30.2.0"
"@jest/pattern@30.0.1":
version "30.0.1"
@@ -2055,16 +2055,16 @@
"@types/node" "*"
jest-regex-util "30.0.1"
-"@jest/reporters@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-30.0.5.tgz#b83585e6448d390a8d92a641c567f1655976d5c6"
- integrity sha512-mafft7VBX4jzED1FwGC1o/9QUM2xebzavImZMeqnsklgcyxBto8mV4HzNSzUrryJ+8R9MFOM3HgYuDradWR+4g==
+"@jest/reporters@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-30.2.0.tgz#a36b28fcbaf0c4595250b108e6f20e363348fd91"
+ integrity sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==
dependencies:
"@bcoe/v8-coverage" "^0.2.3"
- "@jest/console" "30.0.5"
- "@jest/test-result" "30.0.5"
- "@jest/transform" "30.0.5"
- "@jest/types" "30.0.5"
+ "@jest/console" "30.2.0"
+ "@jest/test-result" "30.2.0"
+ "@jest/transform" "30.2.0"
+ "@jest/types" "30.2.0"
"@jridgewell/trace-mapping" "^0.3.25"
"@types/node" "*"
chalk "^4.1.2"
@@ -2077,9 +2077,9 @@
istanbul-lib-report "^3.0.0"
istanbul-lib-source-maps "^5.0.0"
istanbul-reports "^3.1.3"
- jest-message-util "30.0.5"
- jest-util "30.0.5"
- jest-worker "30.0.5"
+ jest-message-util "30.2.0"
+ jest-util "30.2.0"
+ jest-worker "30.2.0"
slash "^3.0.0"
string-length "^4.0.2"
v8-to-istanbul "^9.0.1"
@@ -2098,12 +2098,12 @@
dependencies:
"@sinclair/typebox" "^0.27.8"
-"@jest/snapshot-utils@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/snapshot-utils/-/snapshot-utils-30.0.5.tgz#e23a0e786f174e8cff7f150c1cfbdc9cb7cc81a4"
- integrity sha512-XcCQ5qWHLvi29UUrowgDFvV4t7ETxX91CbDczMnoqXPOIcZOxyNdSjm6kV5XMc8+HkxfRegU/MUmnTbJRzGrUQ==
+"@jest/snapshot-utils@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz#387858eb90c2f98f67bff327435a532ac5309fbe"
+ integrity sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==
dependencies:
- "@jest/types" "30.0.5"
+ "@jest/types" "30.2.0"
chalk "^4.1.2"
graceful-fs "^4.2.11"
natural-compare "^1.4.0"
@@ -2117,42 +2117,42 @@
callsites "^3.1.0"
graceful-fs "^4.2.11"
-"@jest/test-result@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-30.0.5.tgz#064c5210c24d5ea192fb02ceddad3be1cfa557c8"
- integrity sha512-wPyztnK0gbDMQAJZ43tdMro+qblDHH1Ru/ylzUo21TBKqt88ZqnKKK2m30LKmLLoKtR2lxdpCC/P3g1vfKcawQ==
+"@jest/test-result@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-30.2.0.tgz#9c0124377fb7996cdffb86eda3dbc56eacab363d"
+ integrity sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==
dependencies:
- "@jest/console" "30.0.5"
- "@jest/types" "30.0.5"
+ "@jest/console" "30.2.0"
+ "@jest/types" "30.2.0"
"@types/istanbul-lib-coverage" "^2.0.6"
collect-v8-coverage "^1.0.2"
-"@jest/test-sequencer@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-30.0.5.tgz#c6dba8fc3c386dd793c087626e8508ff1ead19f4"
- integrity sha512-Aea/G1egWoIIozmDD7PBXUOxkekXl7ueGzrsGGi1SbeKgQqCYCIf+wfbflEbf2LiPxL8j2JZGLyrzZagjvW4YQ==
+"@jest/test-sequencer@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz#bf0066bc72e176d58f5dfa7f212b6e7eee44f221"
+ integrity sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==
dependencies:
- "@jest/test-result" "30.0.5"
+ "@jest/test-result" "30.2.0"
graceful-fs "^4.2.11"
- jest-haste-map "30.0.5"
+ jest-haste-map "30.2.0"
slash "^3.0.0"
-"@jest/transform@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-30.0.5.tgz#f8ca2e9f7466b77b406807d3bef1f6790dd384e4"
- integrity sha512-Vk8amLQCmuZyy6GbBht1Jfo9RSdBtg7Lks+B0PecnjI8J+PCLQPGh7uI8Q/2wwpW2gLdiAfiHNsmekKlywULqg==
+"@jest/transform@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-30.2.0.tgz#54bef1a4510dcbd58d5d4de4fe2980a63077ef2a"
+ integrity sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==
dependencies:
"@babel/core" "^7.27.4"
- "@jest/types" "30.0.5"
+ "@jest/types" "30.2.0"
"@jridgewell/trace-mapping" "^0.3.25"
- babel-plugin-istanbul "^7.0.0"
+ babel-plugin-istanbul "^7.0.1"
chalk "^4.1.2"
convert-source-map "^2.0.0"
fast-json-stable-stringify "^2.1.0"
graceful-fs "^4.2.11"
- jest-haste-map "30.0.5"
+ jest-haste-map "30.2.0"
jest-regex-util "30.0.1"
- jest-util "30.0.5"
+ jest-util "30.2.0"
micromatch "^4.0.8"
pirates "^4.0.7"
slash "^3.0.0"
@@ -2179,10 +2179,10 @@
slash "^3.0.0"
write-file-atomic "^4.0.2"
-"@jest/types@30.0.5":
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/@jest/types/-/types-30.0.5.tgz#29a33a4c036e3904f1cfd94f6fe77f89d2e1cc05"
- integrity sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==
+"@jest/types@30.2.0":
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/@jest/types/-/types-30.2.0.tgz#1c678a7924b8f59eafd4c77d56b6d0ba976d62b8"
+ integrity sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==
dependencies:
"@jest/pattern" "30.0.1"
"@jest/schemas" "30.0.5"
@@ -2979,99 +2979,18 @@
dependencies:
"@types/node" "*"
-"@types/d3-array@*":
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.2.1.tgz#1f6658e3d2006c4fceac53fde464166859f8b8c5"
- integrity sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==
-
-"@types/d3-axis@*":
- version "3.0.6"
- resolved "https://registry.yarnpkg.com/@types/d3-axis/-/d3-axis-3.0.6.tgz#e760e5765b8188b1defa32bc8bb6062f81e4c795"
- integrity sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==
- dependencies:
- "@types/d3-selection" "*"
-
-"@types/d3-brush@*":
- version "3.0.6"
- resolved "https://registry.yarnpkg.com/@types/d3-brush/-/d3-brush-3.0.6.tgz#c2f4362b045d472e1b186cdbec329ba52bdaee6c"
- integrity sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==
- dependencies:
- "@types/d3-selection" "*"
-
-"@types/d3-chord@*":
- version "3.0.6"
- resolved "https://registry.yarnpkg.com/@types/d3-chord/-/d3-chord-3.0.6.tgz#1706ca40cf7ea59a0add8f4456efff8f8775793d"
- integrity sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==
-
"@types/d3-color@*":
version "3.1.3"
resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.3.tgz#368c961a18de721da8200e80bf3943fb53136af2"
integrity sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==
-"@types/d3-contour@*":
- version "3.0.6"
- resolved "https://registry.yarnpkg.com/@types/d3-contour/-/d3-contour-3.0.6.tgz#9ada3fa9c4d00e3a5093fed0356c7ab929604231"
- integrity sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==
- dependencies:
- "@types/d3-array" "*"
- "@types/geojson" "*"
-
-"@types/d3-delaunay@*":
- version "6.0.4"
- resolved "https://registry.yarnpkg.com/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz#185c1a80cc807fdda2a3fe960f7c11c4a27952e1"
- integrity sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==
-
-"@types/d3-dispatch@*":
- version "3.0.6"
- resolved "https://registry.yarnpkg.com/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz#096efdf55eb97480e3f5621ff9a8da552f0961e7"
- integrity sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==
-
-"@types/d3-drag@*", "@types/d3-drag@^3.0.7":
+"@types/d3-drag@^3.0.7":
version "3.0.7"
resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-3.0.7.tgz#b13aba8b2442b4068c9a9e6d1d82f8bcea77fc02"
integrity sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==
dependencies:
"@types/d3-selection" "*"
-"@types/d3-dsv@*":
- version "3.0.7"
- resolved "https://registry.yarnpkg.com/@types/d3-dsv/-/d3-dsv-3.0.7.tgz#0a351f996dc99b37f4fa58b492c2d1c04e3dac17"
- integrity sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==
-
-"@types/d3-ease@*":
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-3.0.2.tgz#e28db1bfbfa617076f7770dd1d9a48eaa3b6c51b"
- integrity sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==
-
-"@types/d3-fetch@*":
- version "3.0.7"
- resolved "https://registry.yarnpkg.com/@types/d3-fetch/-/d3-fetch-3.0.7.tgz#c04a2b4f23181aa376f30af0283dbc7b3b569980"
- integrity sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==
- dependencies:
- "@types/d3-dsv" "*"
-
-"@types/d3-force@*":
- version "3.0.10"
- resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-3.0.10.tgz#6dc8fc6e1f35704f3b057090beeeb7ac674bff1a"
- integrity sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==
-
-"@types/d3-format@*":
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/@types/d3-format/-/d3-format-3.0.4.tgz#b1e4465644ddb3fdf3a263febb240a6cd616de90"
- integrity sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==
-
-"@types/d3-geo@*":
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-3.1.0.tgz#b9e56a079449174f0a2c8684a9a4df3f60522440"
- integrity sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==
- dependencies:
- "@types/geojson" "*"
-
-"@types/d3-hierarchy@*":
- version "3.1.7"
- resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz#6023fb3b2d463229f2d680f9ac4b47466f71f17b"
- integrity sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==
-
"@types/d3-interpolate@*":
version "3.0.4"
resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz#412b90e84870285f2ff8a846c6eb60344f12a41c"
@@ -3079,73 +2998,19 @@
dependencies:
"@types/d3-color" "*"
-"@types/d3-path@*":
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-3.1.1.tgz#f632b380c3aca1dba8e34aa049bcd6a4af23df8a"
- integrity sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==
-
-"@types/d3-polygon@*":
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/@types/d3-polygon/-/d3-polygon-3.0.2.tgz#dfae54a6d35d19e76ac9565bcb32a8e54693189c"
- integrity sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==
-
-"@types/d3-quadtree@*":
- version "3.0.6"
- resolved "https://registry.yarnpkg.com/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz#d4740b0fe35b1c58b66e1488f4e7ed02952f570f"
- integrity sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==
-
-"@types/d3-random@*":
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/@types/d3-random/-/d3-random-3.0.3.tgz#ed995c71ecb15e0cd31e22d9d5d23942e3300cfb"
- integrity sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==
-
-"@types/d3-scale-chromatic@*":
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz#dc6d4f9a98376f18ea50bad6c39537f1b5463c39"
- integrity sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==
-
-"@types/d3-scale@*":
- version "4.0.9"
- resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.9.tgz#57a2f707242e6fe1de81ad7bfcccaaf606179afb"
- integrity sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==
- dependencies:
- "@types/d3-time" "*"
-
"@types/d3-selection@*", "@types/d3-selection@^3.0.10":
version "3.0.11"
resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.11.tgz#bd7a45fc0a8c3167a631675e61bc2ca2b058d4a3"
integrity sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==
-"@types/d3-shape@*":
- version "3.1.7"
- resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.7.tgz#2b7b423dc2dfe69c8c93596e673e37443348c555"
- integrity sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==
- dependencies:
- "@types/d3-path" "*"
-
-"@types/d3-time-format@*":
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/@types/d3-time-format/-/d3-time-format-4.0.3.tgz#d6bc1e6b6a7db69cccfbbdd4c34b70632d9e9db2"
- integrity sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==
-
-"@types/d3-time@*":
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.4.tgz#8472feecd639691450dd8000eb33edd444e1323f"
- integrity sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==
-
-"@types/d3-timer@*":
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.2.tgz#70bbda77dc23aa727413e22e214afa3f0e852f70"
- integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==
-
-"@types/d3-transition@*", "@types/d3-transition@^3.0.8":
+"@types/d3-transition@^3.0.8":
version "3.0.9"
resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.9.tgz#1136bc57e9ddb3c390dccc9b5ff3b7d2b8d94706"
integrity sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==
dependencies:
"@types/d3-selection" "*"
-"@types/d3-zoom@*", "@types/d3-zoom@^3.0.8":
+"@types/d3-zoom@^3.0.8":
version "3.0.8"
resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-3.0.8.tgz#dccb32d1c56b1e1c6e0f1180d994896f038bc40b"
integrity sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==
@@ -3153,42 +3018,6 @@
"@types/d3-interpolate" "*"
"@types/d3-selection" "*"
-"@types/d3@^7.4.0":
- version "7.4.3"
- resolved "https://registry.yarnpkg.com/@types/d3/-/d3-7.4.3.tgz#d4550a85d08f4978faf0a4c36b848c61eaac07e2"
- integrity sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==
- dependencies:
- "@types/d3-array" "*"
- "@types/d3-axis" "*"
- "@types/d3-brush" "*"
- "@types/d3-chord" "*"
- "@types/d3-color" "*"
- "@types/d3-contour" "*"
- "@types/d3-delaunay" "*"
- "@types/d3-dispatch" "*"
- "@types/d3-drag" "*"
- "@types/d3-dsv" "*"
- "@types/d3-ease" "*"
- "@types/d3-fetch" "*"
- "@types/d3-force" "*"
- "@types/d3-format" "*"
- "@types/d3-geo" "*"
- "@types/d3-hierarchy" "*"
- "@types/d3-interpolate" "*"
- "@types/d3-path" "*"
- "@types/d3-polygon" "*"
- "@types/d3-quadtree" "*"
- "@types/d3-random" "*"
- "@types/d3-scale" "*"
- "@types/d3-scale-chromatic" "*"
- "@types/d3-selection" "*"
- "@types/d3-shape" "*"
- "@types/d3-time" "*"
- "@types/d3-time-format" "*"
- "@types/d3-timer" "*"
- "@types/d3-transition" "*"
- "@types/d3-zoom" "*"
-
"@types/debug@^4.0.0":
version "4.1.12"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917"
@@ -3229,11 +3058,6 @@
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8"
integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==
-"@types/geojson@*":
- version "7946.0.16"
- resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.16.tgz#8ebe53d69efada7044454e3305c19017d97ced2a"
- integrity sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==
-
"@types/graceful-fs@^4.1.3":
version "4.1.9"
resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4"
@@ -3255,6 +3079,11 @@
dependencies:
"@types/unist" "*"
+"@types/he@^1.2.3":
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/@types/he/-/he-1.2.3.tgz#c33ca3096f30cbd5d68d78211572de3f9adff75a"
+ integrity sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA==
+
"@types/hoist-non-react-statics@^3.3.0":
version "3.3.6"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz#6bba74383cdab98e8db4e20ce5b4a6b98caed010"
@@ -3319,13 +3148,6 @@
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.16.tgz#94ae78fab4a38d73086e962d0b65c30d816bfb0a"
integrity sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==
-"@types/mdast@^3.0.0":
- version "3.0.15"
- resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.15.tgz#49c524a263f30ffa28b71ae282f813ed000ab9f5"
- integrity sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==
- dependencies:
- "@types/unist" "^2"
-
"@types/mdast@^4.0.0", "@types/mdast@^4.0.1", "@types/mdast@^4.0.3":
version "4.0.4"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6"
@@ -3363,7 +3185,7 @@
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239"
integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==
-"@types/prop-types@*", "@types/prop-types@^15.0.0":
+"@types/prop-types@*":
version "15.7.14"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.14.tgz#1433419d73b2a7ebfc6918dcefd2ec0d5cd698f2"
integrity sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==
@@ -3406,11 +3228,6 @@
"@types/scheduler" "^0.16"
csstype "^3.0.2"
-"@types/resize-observer-browser@^0.1.7":
- version "0.1.11"
- resolved "https://registry.yarnpkg.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.11.tgz#d3c98d788489d8376b7beac23863b1eebdd3c13c"
- integrity sha512-cNw5iH8JkMkb3QkCoe7DaZiawbDQEUX8t7iuQaRTyLOyQCR2h+ibBD4GJt7p5yhUHrlOeL7ZtbxNHeipqNsBzQ==
-
"@types/resolve@^1.20.2":
version "1.20.6"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.6.tgz#e6e60dad29c2c8c206c026e6dd8d6d1bdda850b8"
@@ -4134,15 +3951,15 @@ babel-core@^7.0.0-bridge.0:
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece"
integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==
-babel-jest@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-30.0.5.tgz#7cc7dd03d0d613125d458521f635b8c2361e89cc"
- integrity sha512-mRijnKimhGDMsizTvBTWotwNpzrkHr+VvZUQBof2AufXKB8NXrL1W69TG20EvOz7aevx6FTJIaBuBkYxS8zolg==
+babel-jest@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-30.2.0.tgz#fd44a1ec9552be35ead881f7381faa7d8f3b95ac"
+ integrity sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==
dependencies:
- "@jest/transform" "30.0.5"
+ "@jest/transform" "30.2.0"
"@types/babel__core" "^7.20.5"
- babel-plugin-istanbul "^7.0.0"
- babel-preset-jest "30.0.1"
+ babel-plugin-istanbul "^7.0.1"
+ babel-preset-jest "30.2.0"
chalk "^4.1.2"
graceful-fs "^4.2.11"
slash "^3.0.0"
@@ -4179,10 +3996,10 @@ babel-plugin-istanbul@^6.1.1:
istanbul-lib-instrument "^5.0.4"
test-exclude "^6.0.0"
-babel-plugin-istanbul@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.0.tgz#629a178f63b83dc9ecee46fd20266283b1f11280"
- integrity sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==
+babel-plugin-istanbul@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz#d8b518c8ea199364cf84ccc82de89740236daf92"
+ integrity sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
"@istanbuljs/load-nyc-config" "^1.0.0"
@@ -4190,13 +4007,11 @@ babel-plugin-istanbul@^7.0.0:
istanbul-lib-instrument "^6.0.2"
test-exclude "^6.0.0"
-babel-plugin-jest-hoist@30.0.1:
- version "30.0.1"
- resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.0.1.tgz#f271b2066d2c1fb26a863adb8e13f85b06247125"
- integrity sha512-zTPME3pI50NsFW8ZBaVIOeAxzEY7XHlmWeXXu9srI+9kNfzCUTy8MFan46xOGZY8NZThMqq+e3qZUKsvXbasnQ==
+babel-plugin-jest-hoist@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz#94c250d36b43f95900f3a219241e0f4648191ce2"
+ integrity sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==
dependencies:
- "@babel/template" "^7.27.2"
- "@babel/types" "^7.27.3"
"@types/babel__core" "^7.20.5"
babel-plugin-jest-hoist@^29.6.3:
@@ -4254,7 +4069,7 @@ babel-preset-current-node-syntax@^1.0.0:
"@babel/plugin-syntax-private-property-in-object" "^7.14.5"
"@babel/plugin-syntax-top-level-await" "^7.14.5"
-babel-preset-current-node-syntax@^1.1.0:
+babel-preset-current-node-syntax@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz#20730d6cdc7dda5d89401cab10ac6a32067acde6"
integrity sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==
@@ -4275,13 +4090,13 @@ babel-preset-current-node-syntax@^1.1.0:
"@babel/plugin-syntax-private-property-in-object" "^7.14.5"
"@babel/plugin-syntax-top-level-await" "^7.14.5"
-babel-preset-jest@30.0.1:
- version "30.0.1"
- resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-30.0.1.tgz#7d28db9531bce264e846c8483d54236244b8ae88"
- integrity sha512-+YHejD5iTWI46cZmcc/YtX4gaKBtdqCHCVfuVinizVpbmyjO3zYmeuyFdfA8duRqQZfgCAMlsfmkVbJ+e2MAJw==
+babel-preset-jest@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz#04717843e561347781d6d7f69c81e6bcc3ed11ce"
+ integrity sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==
dependencies:
- babel-plugin-jest-hoist "30.0.1"
- babel-preset-current-node-syntax "^1.1.0"
+ babel-plugin-jest-hoist "30.2.0"
+ babel-preset-current-node-syntax "^1.2.0"
babel-preset-jest@^29.6.3:
version "29.6.3"
@@ -5278,11 +5093,6 @@ diff@^4.0.1:
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
-diff@^5.0.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531"
- integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==
-
dir-glob@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@@ -5924,17 +5734,17 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2:
dependencies:
homedir-polyfill "^1.0.1"
-expect@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/expect/-/expect-30.0.5.tgz#c23bf193c5e422a742bfd2990ad990811de41a5a"
- integrity sha512-P0te2pt+hHI5qLJkIR+iMvS+lYUZml8rKKsohVHAGY+uClp9XVbdyYNJOIjSRpHVp8s8YqxJCiHUkSYZGr8rtQ==
+expect@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/expect/-/expect-30.2.0.tgz#d4013bed267013c14bc1199cec8aa57cee9b5869"
+ integrity sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==
dependencies:
- "@jest/expect-utils" "30.0.5"
- "@jest/get-type" "30.0.1"
- jest-matcher-utils "30.0.5"
- jest-message-util "30.0.5"
- jest-mock "30.0.5"
- jest-util "30.0.5"
+ "@jest/expect-utils" "30.2.0"
+ "@jest/get-type" "30.1.0"
+ jest-matcher-utils "30.2.0"
+ jest-message-util "30.2.0"
+ jest-mock "30.2.0"
+ jest-util "30.2.0"
expect@^29.0.0:
version "29.7.0"
@@ -6711,11 +6521,6 @@ hast-util-to-text@^4.0.0:
hast-util-is-element "^3.0.0"
unist-util-find-after "^5.0.0"
-hast-util-whitespace@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz#0ec64e257e6fc216c7d14c8a1b74d27d650b4557"
- integrity sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==
-
hast-util-whitespace@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz#7778ed9d3c92dd9e8c5c8f648a49c21fc51cb621"
@@ -7002,11 +6807,6 @@ ini@^1.3.4, ini@^1.3.5:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
-inline-style-parser@0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1"
- integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==
-
inline-style-parser@0.2.4:
version "0.2.4"
resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.4.tgz#f4af5fe72e612839fcd453d989a586566d695f22"
@@ -7119,11 +6919,6 @@ is-boolean-object@^1.2.1:
call-bound "^1.0.3"
has-tostringtag "^1.0.2"
-is-buffer@^2.0.0:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
- integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
-
is-callable@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
@@ -7465,96 +7260,96 @@ jackspeak@^3.1.2:
optionalDependencies:
"@pkgjs/parseargs" "^0.11.0"
-jest-changed-files@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-30.0.5.tgz#ec448f83bd9caa894dd7da8707f207c356a19924"
- integrity sha512-bGl2Ntdx0eAwXuGpdLdVYVr5YQHnSZlQ0y9HVDu565lCUAe9sj6JOtBbMmBBikGIegne9piDDIOeiLVoqTkz4A==
+jest-changed-files@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-30.2.0.tgz#602266e478ed554e1e1469944faa7efd37cee61c"
+ integrity sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==
dependencies:
execa "^5.1.1"
- jest-util "30.0.5"
+ jest-util "30.2.0"
p-limit "^3.1.0"
-jest-circus@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-30.0.5.tgz#9b4d44feb56c7ffe14411ad7fc08af188c5d4da7"
- integrity sha512-h/sjXEs4GS+NFFfqBDYT7y5Msfxh04EwWLhQi0F8kuWpe+J/7tICSlswU8qvBqumR3kFgHbfu7vU6qruWWBPug==
+jest-circus@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-30.2.0.tgz#98b8198b958748a2f322354311023d1d02e7603f"
+ integrity sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==
dependencies:
- "@jest/environment" "30.0.5"
- "@jest/expect" "30.0.5"
- "@jest/test-result" "30.0.5"
- "@jest/types" "30.0.5"
+ "@jest/environment" "30.2.0"
+ "@jest/expect" "30.2.0"
+ "@jest/test-result" "30.2.0"
+ "@jest/types" "30.2.0"
"@types/node" "*"
chalk "^4.1.2"
co "^4.6.0"
dedent "^1.6.0"
is-generator-fn "^2.1.0"
- jest-each "30.0.5"
- jest-matcher-utils "30.0.5"
- jest-message-util "30.0.5"
- jest-runtime "30.0.5"
- jest-snapshot "30.0.5"
- jest-util "30.0.5"
+ jest-each "30.2.0"
+ jest-matcher-utils "30.2.0"
+ jest-message-util "30.2.0"
+ jest-runtime "30.2.0"
+ jest-snapshot "30.2.0"
+ jest-util "30.2.0"
p-limit "^3.1.0"
- pretty-format "30.0.5"
+ pretty-format "30.2.0"
pure-rand "^7.0.0"
slash "^3.0.0"
stack-utils "^2.0.6"
-jest-cli@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-30.0.5.tgz#c3fbfdabd1a5c428429476f915a1ba6d0774cc50"
- integrity sha512-Sa45PGMkBZzF94HMrlX4kUyPOwUpdZasaliKN3mifvDmkhLYqLLg8HQTzn6gq7vJGahFYMQjXgyJWfYImKZzOw==
+jest-cli@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-30.2.0.tgz#1780f8e9d66bf84a10b369aea60aeda7697dcc67"
+ integrity sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==
dependencies:
- "@jest/core" "30.0.5"
- "@jest/test-result" "30.0.5"
- "@jest/types" "30.0.5"
+ "@jest/core" "30.2.0"
+ "@jest/test-result" "30.2.0"
+ "@jest/types" "30.2.0"
chalk "^4.1.2"
exit-x "^0.2.2"
import-local "^3.2.0"
- jest-config "30.0.5"
- jest-util "30.0.5"
- jest-validate "30.0.5"
+ jest-config "30.2.0"
+ jest-util "30.2.0"
+ jest-validate "30.2.0"
yargs "^17.7.2"
-jest-config@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-30.0.5.tgz#567cf39b595229b786506a496c22e222d5e8d480"
- integrity sha512-aIVh+JNOOpzUgzUnPn5FLtyVnqc3TQHVMupYtyeURSb//iLColiMIR8TxCIDKyx9ZgjKnXGucuW68hCxgbrwmA==
+jest-config@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-30.2.0.tgz#29df8c50e2ad801cc59c406b50176c18c362a90b"
+ integrity sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==
dependencies:
"@babel/core" "^7.27.4"
- "@jest/get-type" "30.0.1"
+ "@jest/get-type" "30.1.0"
"@jest/pattern" "30.0.1"
- "@jest/test-sequencer" "30.0.5"
- "@jest/types" "30.0.5"
- babel-jest "30.0.5"
+ "@jest/test-sequencer" "30.2.0"
+ "@jest/types" "30.2.0"
+ babel-jest "30.2.0"
chalk "^4.1.2"
ci-info "^4.2.0"
deepmerge "^4.3.1"
glob "^10.3.10"
graceful-fs "^4.2.11"
- jest-circus "30.0.5"
- jest-docblock "30.0.1"
- jest-environment-node "30.0.5"
+ jest-circus "30.2.0"
+ jest-docblock "30.2.0"
+ jest-environment-node "30.2.0"
jest-regex-util "30.0.1"
- jest-resolve "30.0.5"
- jest-runner "30.0.5"
- jest-util "30.0.5"
- jest-validate "30.0.5"
+ jest-resolve "30.2.0"
+ jest-runner "30.2.0"
+ jest-util "30.2.0"
+ jest-validate "30.2.0"
micromatch "^4.0.8"
parse-json "^5.2.0"
- pretty-format "30.0.5"
+ pretty-format "30.2.0"
slash "^3.0.0"
strip-json-comments "^3.1.1"
-jest-diff@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-30.0.5.tgz#b40f81e0c0d13e5b81c4d62b0d0dfa6a524ee0fd"
- integrity sha512-1UIqE9PoEKaHcIKvq2vbibrCog4Y8G0zmOxgQUVEiTqwR5hJVMCoDsN1vFvI5JvwD37hjueZ1C4l2FyGnfpE0A==
+jest-diff@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-30.2.0.tgz#e3ec3a6ea5c5747f605c9e874f83d756cba36825"
+ integrity sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==
dependencies:
"@jest/diff-sequences" "30.0.1"
- "@jest/get-type" "30.0.1"
+ "@jest/get-type" "30.1.0"
chalk "^4.1.2"
- pretty-format "30.0.5"
+ pretty-format "30.2.0"
jest-diff@^29.7.0:
version "29.7.0"
@@ -7566,66 +7361,66 @@ jest-diff@^29.7.0:
jest-get-type "^29.6.3"
pretty-format "^29.7.0"
-jest-docblock@30.0.1:
- version "30.0.1"
- resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-30.0.1.tgz#545ff59f2fa88996bd470dba7d3798a8421180b1"
- integrity sha512-/vF78qn3DYphAaIc3jy4gA7XSAz167n9Bm/wn/1XhTLW7tTBIzXtCJpb/vcmc73NIIeeohCbdL94JasyXUZsGA==
+jest-docblock@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-30.2.0.tgz#42cd98d69f887e531c7352309542b1ce4ee10256"
+ integrity sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==
dependencies:
detect-newline "^3.1.0"
-jest-each@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-30.0.5.tgz#5962264ff246cd757ba44db096c1bc5b4835173e"
- integrity sha512-dKjRsx1uZ96TVyejD3/aAWcNKy6ajMaN531CwWIsrazIqIoXI9TnnpPlkrEYku/8rkS3dh2rbH+kMOyiEIv0xQ==
+jest-each@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-30.2.0.tgz#39e623ae71641c2ac3ee69b3ba3d258fce8e768d"
+ integrity sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==
dependencies:
- "@jest/get-type" "30.0.1"
- "@jest/types" "30.0.5"
+ "@jest/get-type" "30.1.0"
+ "@jest/types" "30.2.0"
chalk "^4.1.2"
- jest-util "30.0.5"
- pretty-format "30.0.5"
+ jest-util "30.2.0"
+ pretty-format "30.2.0"
-jest-environment-jsdom@^30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-30.0.5.tgz#36351cc8a14fcd54945da0beb029af493d7d5764"
- integrity sha512-BmnDEoAH+jEjkPrvE9DTKS2r3jYSJWlN/r46h0/DBUxKrkgt2jAZ5Nj4wXLAcV1KWkRpcFqA5zri9SWzJZ1cCg==
+jest-environment-jsdom@^30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-30.2.0.tgz#e95e0921ed22be974f1d8a324766d12b1844cb2c"
+ integrity sha512-zbBTiqr2Vl78pKp/laGBREYzbZx9ZtqPjOK4++lL4BNDhxRnahg51HtoDrk9/VjIy9IthNEWdKVd7H5bqBhiWQ==
dependencies:
- "@jest/environment" "30.0.5"
- "@jest/environment-jsdom-abstract" "30.0.5"
+ "@jest/environment" "30.2.0"
+ "@jest/environment-jsdom-abstract" "30.2.0"
"@types/jsdom" "^21.1.7"
"@types/node" "*"
jsdom "^26.1.0"
-jest-environment-node@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-30.0.5.tgz#6a98dd80e0384ead67ed05643381395f6cda93c9"
- integrity sha512-ppYizXdLMSvciGsRsMEnv/5EFpvOdXBaXRBzFUDPWrsfmog4kYrOGWXarLllz6AXan6ZAA/kYokgDWuos1IKDA==
+jest-environment-node@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-30.2.0.tgz#3def7980ebd2fd86e74efd4d2e681f55ab38da0f"
+ integrity sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==
dependencies:
- "@jest/environment" "30.0.5"
- "@jest/fake-timers" "30.0.5"
- "@jest/types" "30.0.5"
+ "@jest/environment" "30.2.0"
+ "@jest/fake-timers" "30.2.0"
+ "@jest/types" "30.2.0"
"@types/node" "*"
- jest-mock "30.0.5"
- jest-util "30.0.5"
- jest-validate "30.0.5"
+ jest-mock "30.2.0"
+ jest-util "30.2.0"
+ jest-validate "30.2.0"
jest-get-type@^29.6.3:
version "29.6.3"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1"
integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==
-jest-haste-map@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-30.0.5.tgz#fdd0daa322b02eb34267854cff2859fae21e92a6"
- integrity sha512-dkmlWNlsTSR0nH3nRfW5BKbqHefLZv0/6LCccG0xFCTWcJu8TuEwG+5Cm75iBfjVoockmO6J35o5gxtFSn5xeg==
+jest-haste-map@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-30.2.0.tgz#808e3889f288603ac70ff0ac047598345a66022e"
+ integrity sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==
dependencies:
- "@jest/types" "30.0.5"
+ "@jest/types" "30.2.0"
"@types/node" "*"
anymatch "^3.1.3"
fb-watchman "^2.0.2"
graceful-fs "^4.2.11"
jest-regex-util "30.0.1"
- jest-util "30.0.5"
- jest-worker "30.0.5"
+ jest-util "30.2.0"
+ jest-worker "30.2.0"
micromatch "^4.0.8"
walker "^1.0.8"
optionalDependencies:
@@ -7650,23 +7445,23 @@ jest-haste-map@^29.7.0:
optionalDependencies:
fsevents "^2.3.2"
-jest-leak-detector@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-30.0.5.tgz#00cfd2b323f48d8f4416b0a3e05fcf4c51f18864"
- integrity sha512-3Uxr5uP8jmHMcsOtYMRB/zf1gXN3yUIc+iPorhNETG54gErFIiUhLvyY/OggYpSMOEYqsmRxmuU4ZOoX5jpRFg==
+jest-leak-detector@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz#292fdca7b7c9cf594e1e570ace140b01d8beb736"
+ integrity sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==
dependencies:
- "@jest/get-type" "30.0.1"
- pretty-format "30.0.5"
+ "@jest/get-type" "30.1.0"
+ pretty-format "30.2.0"
-jest-matcher-utils@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-30.0.5.tgz#dff3334be58faea4a5e1becc228656fbbfc2467d"
- integrity sha512-uQgGWt7GOrRLP1P7IwNWwK1WAQbq+m//ZY0yXygyfWp0rJlksMSLQAA4wYQC3b6wl3zfnchyTx+k3HZ5aPtCbQ==
+jest-matcher-utils@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz#69a0d4c271066559ec8b0d8174829adc3f23a783"
+ integrity sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==
dependencies:
- "@jest/get-type" "30.0.1"
+ "@jest/get-type" "30.1.0"
chalk "^4.1.2"
- jest-diff "30.0.5"
- pretty-format "30.0.5"
+ jest-diff "30.2.0"
+ pretty-format "30.2.0"
jest-matcher-utils@^29.7.0:
version "29.7.0"
@@ -7678,18 +7473,18 @@ jest-matcher-utils@^29.7.0:
jest-get-type "^29.6.3"
pretty-format "^29.7.0"
-jest-message-util@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-30.0.5.tgz#dd12ffec91dd3fa6a59cbd538a513d8e239e070c"
- integrity sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA==
+jest-message-util@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-30.2.0.tgz#fc97bf90d11f118b31e6131e2b67fc4f39f92152"
+ integrity sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==
dependencies:
"@babel/code-frame" "^7.27.1"
- "@jest/types" "30.0.5"
+ "@jest/types" "30.2.0"
"@types/stack-utils" "^2.0.3"
chalk "^4.1.2"
graceful-fs "^4.2.11"
micromatch "^4.0.8"
- pretty-format "30.0.5"
+ pretty-format "30.2.0"
slash "^3.0.0"
stack-utils "^2.0.6"
@@ -7708,14 +7503,14 @@ jest-message-util@^29.7.0:
slash "^3.0.0"
stack-utils "^2.0.3"
-jest-mock@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-30.0.5.tgz#ef437e89212560dd395198115550085038570bdd"
- integrity sha512-Od7TyasAAQX/6S+QCbN6vZoWOMwlTtzzGuxJku1GhGanAjz9y+QsQkpScDmETvdc9aSXyJ/Op4rhpMYBWW91wQ==
+jest-mock@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-30.2.0.tgz#69f991614eeb4060189459d3584f710845bff45e"
+ integrity sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==
dependencies:
- "@jest/types" "30.0.5"
+ "@jest/types" "30.2.0"
"@types/node" "*"
- jest-util "30.0.5"
+ jest-util "30.2.0"
jest-pnp-resolver@^1.2.3:
version "1.2.3"
@@ -7732,117 +7527,117 @@ jest-regex-util@^29.6.3:
resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52"
integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==
-jest-resolve-dependencies@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-30.0.5.tgz#53be4c51d296c84a0e75608e7b77b6fe92dbac29"
- integrity sha512-/xMvBR4MpwkrHW4ikZIWRttBBRZgWK4d6xt3xW1iRDSKt4tXzYkMkyPfBnSCgv96cpkrctfXs6gexeqMYqdEpw==
+jest-resolve-dependencies@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz#3370e2c0b49cc560f6a7e8ec3a59dd99525e1a55"
+ integrity sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==
dependencies:
jest-regex-util "30.0.1"
- jest-snapshot "30.0.5"
+ jest-snapshot "30.2.0"
-jest-resolve@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-30.0.5.tgz#f52f91600070b7073db465dc553eee5471ea8e06"
- integrity sha512-d+DjBQ1tIhdz91B79mywH5yYu76bZuE96sSbxj8MkjWVx5WNdt1deEFRONVL4UkKLSrAbMkdhb24XN691yDRHg==
+jest-resolve@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-30.2.0.tgz#2e2009cbd61e8f1f003355d5ec87225412cebcd7"
+ integrity sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==
dependencies:
chalk "^4.1.2"
graceful-fs "^4.2.11"
- jest-haste-map "30.0.5"
+ jest-haste-map "30.2.0"
jest-pnp-resolver "^1.2.3"
- jest-util "30.0.5"
- jest-validate "30.0.5"
+ jest-util "30.2.0"
+ jest-validate "30.2.0"
slash "^3.0.0"
unrs-resolver "^1.7.11"
-jest-runner@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-30.0.5.tgz#5cbaaf85964246da4f65d697f186846f23cd9b5a"
- integrity sha512-JcCOucZmgp+YuGgLAXHNy7ualBx4wYSgJVWrYMRBnb79j9PD0Jxh0EHvR5Cx/r0Ce+ZBC4hCdz2AzFFLl9hCiw==
- dependencies:
- "@jest/console" "30.0.5"
- "@jest/environment" "30.0.5"
- "@jest/test-result" "30.0.5"
- "@jest/transform" "30.0.5"
- "@jest/types" "30.0.5"
+jest-runner@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-30.2.0.tgz#c62b4c3130afa661789705e13a07bdbcec26a114"
+ integrity sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==
+ dependencies:
+ "@jest/console" "30.2.0"
+ "@jest/environment" "30.2.0"
+ "@jest/test-result" "30.2.0"
+ "@jest/transform" "30.2.0"
+ "@jest/types" "30.2.0"
"@types/node" "*"
chalk "^4.1.2"
emittery "^0.13.1"
exit-x "^0.2.2"
graceful-fs "^4.2.11"
- jest-docblock "30.0.1"
- jest-environment-node "30.0.5"
- jest-haste-map "30.0.5"
- jest-leak-detector "30.0.5"
- jest-message-util "30.0.5"
- jest-resolve "30.0.5"
- jest-runtime "30.0.5"
- jest-util "30.0.5"
- jest-watcher "30.0.5"
- jest-worker "30.0.5"
+ jest-docblock "30.2.0"
+ jest-environment-node "30.2.0"
+ jest-haste-map "30.2.0"
+ jest-leak-detector "30.2.0"
+ jest-message-util "30.2.0"
+ jest-resolve "30.2.0"
+ jest-runtime "30.2.0"
+ jest-util "30.2.0"
+ jest-watcher "30.2.0"
+ jest-worker "30.2.0"
p-limit "^3.1.0"
source-map-support "0.5.13"
-jest-runtime@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-30.0.5.tgz#d6a7e22687264240d1786d6f7682ac6a2872e552"
- integrity sha512-7oySNDkqpe4xpX5PPiJTe5vEa+Ak/NnNz2bGYZrA1ftG3RL3EFlHaUkA1Cjx+R8IhK0Vg43RML5mJedGTPNz3A==
+jest-runtime@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-30.2.0.tgz#395ea792cde048db1b0cd1a92dc9cb9f1921bf8a"
+ integrity sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==
dependencies:
- "@jest/environment" "30.0.5"
- "@jest/fake-timers" "30.0.5"
- "@jest/globals" "30.0.5"
+ "@jest/environment" "30.2.0"
+ "@jest/fake-timers" "30.2.0"
+ "@jest/globals" "30.2.0"
"@jest/source-map" "30.0.1"
- "@jest/test-result" "30.0.5"
- "@jest/transform" "30.0.5"
- "@jest/types" "30.0.5"
+ "@jest/test-result" "30.2.0"
+ "@jest/transform" "30.2.0"
+ "@jest/types" "30.2.0"
"@types/node" "*"
chalk "^4.1.2"
cjs-module-lexer "^2.1.0"
collect-v8-coverage "^1.0.2"
glob "^10.3.10"
graceful-fs "^4.2.11"
- jest-haste-map "30.0.5"
- jest-message-util "30.0.5"
- jest-mock "30.0.5"
+ jest-haste-map "30.2.0"
+ jest-message-util "30.2.0"
+ jest-mock "30.2.0"
jest-regex-util "30.0.1"
- jest-resolve "30.0.5"
- jest-snapshot "30.0.5"
- jest-util "30.0.5"
+ jest-resolve "30.2.0"
+ jest-snapshot "30.2.0"
+ jest-util "30.2.0"
slash "^3.0.0"
strip-bom "^4.0.0"
-jest-snapshot@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-30.0.5.tgz#6600716eef2e6d8ea1dd788ae4385f3a2791b11f"
- integrity sha512-T00dWU/Ek3LqTp4+DcW6PraVxjk28WY5Ua/s+3zUKSERZSNyxTqhDXCWKG5p2HAJ+crVQ3WJ2P9YVHpj1tkW+g==
+jest-snapshot@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-30.2.0.tgz#266fbbb4b95fc4665ce6f32f1f38eeb39f4e26d0"
+ integrity sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==
dependencies:
"@babel/core" "^7.27.4"
"@babel/generator" "^7.27.5"
"@babel/plugin-syntax-jsx" "^7.27.1"
"@babel/plugin-syntax-typescript" "^7.27.1"
"@babel/types" "^7.27.3"
- "@jest/expect-utils" "30.0.5"
- "@jest/get-type" "30.0.1"
- "@jest/snapshot-utils" "30.0.5"
- "@jest/transform" "30.0.5"
- "@jest/types" "30.0.5"
- babel-preset-current-node-syntax "^1.1.0"
+ "@jest/expect-utils" "30.2.0"
+ "@jest/get-type" "30.1.0"
+ "@jest/snapshot-utils" "30.2.0"
+ "@jest/transform" "30.2.0"
+ "@jest/types" "30.2.0"
+ babel-preset-current-node-syntax "^1.2.0"
chalk "^4.1.2"
- expect "30.0.5"
+ expect "30.2.0"
graceful-fs "^4.2.11"
- jest-diff "30.0.5"
- jest-matcher-utils "30.0.5"
- jest-message-util "30.0.5"
- jest-util "30.0.5"
- pretty-format "30.0.5"
+ jest-diff "30.2.0"
+ jest-matcher-utils "30.2.0"
+ jest-message-util "30.2.0"
+ jest-util "30.2.0"
+ pretty-format "30.2.0"
semver "^7.7.2"
synckit "^0.11.8"
-jest-util@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-30.0.5.tgz#035d380c660ad5f1748dff71c4105338e05f8669"
- integrity sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==
+jest-util@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-30.2.0.tgz#5142adbcad6f4e53c2776c067a4db3c14f913705"
+ integrity sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==
dependencies:
- "@jest/types" "30.0.5"
+ "@jest/types" "30.2.0"
"@types/node" "*"
chalk "^4.1.2"
ci-info "^4.2.0"
@@ -7861,40 +7656,40 @@ jest-util@^29.7.0:
graceful-fs "^4.2.9"
picomatch "^2.2.3"
-jest-validate@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-30.0.5.tgz#d26fd218b8d566bff48fd98880b8ea94fd0d8456"
- integrity sha512-ouTm6VFHaS2boyl+k4u+Qip4TSH7Uld5tyD8psQ8abGgt2uYYB8VwVfAHWHjHc0NWmGGbwO5h0sCPOGHHevefw==
+jest-validate@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-30.2.0.tgz#273eaaed4c0963b934b5b31e96289edda6e0a2ef"
+ integrity sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==
dependencies:
- "@jest/get-type" "30.0.1"
- "@jest/types" "30.0.5"
+ "@jest/get-type" "30.1.0"
+ "@jest/types" "30.2.0"
camelcase "^6.3.0"
chalk "^4.1.2"
leven "^3.1.0"
- pretty-format "30.0.5"
+ pretty-format "30.2.0"
-jest-watcher@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-30.0.5.tgz#90db6e3f582b88085bde58f7555cbdd3a1beb10d"
- integrity sha512-z9slj/0vOwBDBjN3L4z4ZYaA+pG56d6p3kTUhFRYGvXbXMWhXmb/FIxREZCD06DYUwDKKnj2T80+Pb71CQ0KEg==
+jest-watcher@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-30.2.0.tgz#f9c055de48e18c979e7756a3917e596e2d69b07b"
+ integrity sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==
dependencies:
- "@jest/test-result" "30.0.5"
- "@jest/types" "30.0.5"
+ "@jest/test-result" "30.2.0"
+ "@jest/types" "30.2.0"
"@types/node" "*"
ansi-escapes "^4.3.2"
chalk "^4.1.2"
emittery "^0.13.1"
- jest-util "30.0.5"
+ jest-util "30.2.0"
string-length "^4.0.2"
-jest-worker@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-30.0.5.tgz#0b85cbab10610303e8d84e214f94d8f052c3cd04"
- integrity sha512-ojRXsWzEP16NdUuBw/4H/zkZdHOa7MMYCk4E430l+8fELeLg/mqmMlRhjL7UNZvQrDmnovWZV4DxX03fZF48fQ==
+jest-worker@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-30.2.0.tgz#fd5c2a36ff6058ec8f74366ec89538cc99539d26"
+ integrity sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==
dependencies:
"@types/node" "*"
"@ungap/structured-clone" "^1.3.0"
- jest-util "30.0.5"
+ jest-util "30.2.0"
merge-stream "^2.0.0"
supports-color "^8.1.1"
@@ -7917,15 +7712,15 @@ jest-worker@^29.7.0:
merge-stream "^2.0.0"
supports-color "^8.0.0"
-jest@^30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/jest/-/jest-30.0.5.tgz#ee62729fb77829790d67c660d852350fbde315ce"
- integrity sha512-y2mfcJywuTUkvLm2Lp1/pFX8kTgMO5yyQGq/Sk/n2mN7XWYp4JsCZ/QXW34M8YScgk8bPZlREH04f6blPnoHnQ==
+jest@^30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/jest/-/jest-30.2.0.tgz#9f0a71e734af968f26952b5ae4b724af82681630"
+ integrity sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==
dependencies:
- "@jest/core" "30.0.5"
- "@jest/types" "30.0.5"
+ "@jest/core" "30.2.0"
+ "@jest/types" "30.2.0"
import-local "^3.2.0"
- jest-cli "30.0.5"
+ jest-cli "30.2.0"
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
@@ -8100,11 +7895,6 @@ kleur@^3.0.3:
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
-kleur@^4.0.3:
- version "4.1.5"
- resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780"
- integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==
-
klona@^2.0.4:
version "2.0.6"
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22"
@@ -8385,15 +8175,6 @@ mdast-util-definition-list@^2.0.0:
micromark-extension-definition-list "^2.0.0"
unist-builder "^4.0.0"
-mdast-util-definitions@^5.0.0:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz#9910abb60ac5d7115d6819b57ae0bcef07a3f7a7"
- integrity sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==
- dependencies:
- "@types/mdast" "^3.0.0"
- "@types/unist" "^2.0.0"
- unist-util-visit "^4.0.0"
-
mdast-util-find-and-replace@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz#70a3174c894e14df722abf43bc250cbae44b11df"
@@ -8404,24 +8185,6 @@ mdast-util-find-and-replace@^3.0.0:
unist-util-is "^6.0.0"
unist-util-visit-parents "^6.0.0"
-mdast-util-from-markdown@^1.0.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz#9421a5a247f10d31d2faed2a30df5ec89ceafcf0"
- integrity sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==
- dependencies:
- "@types/mdast" "^3.0.0"
- "@types/unist" "^2.0.0"
- decode-named-character-reference "^1.0.0"
- mdast-util-to-string "^3.1.0"
- micromark "^3.0.0"
- micromark-util-decode-numeric-character-reference "^1.0.0"
- micromark-util-decode-string "^1.0.0"
- micromark-util-normalize-identifier "^1.0.0"
- micromark-util-symbol "^1.0.0"
- micromark-util-types "^1.0.0"
- unist-util-stringify-position "^3.0.0"
- uvu "^0.5.0"
-
mdast-util-from-markdown@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz#4850390ca7cf17413a9b9a0fbefcd1bc0eb4160a"
@@ -8555,20 +8318,6 @@ mdast-util-phrasing@^4.0.0, mdast-util-phrasing@^4.1.0:
"@types/mdast" "^4.0.0"
unist-util-is "^6.0.0"
-mdast-util-to-hast@^12.1.0:
- version "12.3.0"
- resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz#045d2825fb04374e59970f5b3f279b5700f6fb49"
- integrity sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==
- dependencies:
- "@types/hast" "^2.0.0"
- "@types/mdast" "^3.0.0"
- mdast-util-definitions "^5.0.0"
- micromark-util-sanitize-uri "^1.1.0"
- trim-lines "^3.0.0"
- unist-util-generated "^2.0.0"
- unist-util-position "^4.0.0"
- unist-util-visit "^4.0.0"
-
mdast-util-to-hast@^13.0.0, mdast-util-to-hast@^13.0.2:
version "13.2.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz#5ca58e5b921cc0a3ded1bc02eed79a4fe4fe41f4"
@@ -8599,13 +8348,6 @@ mdast-util-to-markdown@^2.0.0, mdast-util-to-markdown@^2.1.0:
unist-util-visit "^5.0.0"
zwitch "^2.0.0"
-mdast-util-to-string@^3.1.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz#66f7bb6324756741c5f47a53557f0cbf16b6f789"
- integrity sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==
- dependencies:
- "@types/mdast" "^3.0.0"
-
mdast-util-to-string@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz#7a5121475556a04e7eddeb67b264aae79d312814"
@@ -8652,28 +8394,6 @@ merge2@^1.3.0, merge2@^1.4.1:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
-micromark-core-commonmark@^1.0.1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz#1386628df59946b2d39fb2edfd10f3e8e0a75bb8"
- integrity sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==
- dependencies:
- decode-named-character-reference "^1.0.0"
- micromark-factory-destination "^1.0.0"
- micromark-factory-label "^1.0.0"
- micromark-factory-space "^1.0.0"
- micromark-factory-title "^1.0.0"
- micromark-factory-whitespace "^1.0.0"
- micromark-util-character "^1.0.0"
- micromark-util-chunked "^1.0.0"
- micromark-util-classify-character "^1.0.0"
- micromark-util-html-tag-name "^1.0.0"
- micromark-util-normalize-identifier "^1.0.0"
- micromark-util-resolve-all "^1.0.0"
- micromark-util-subtokenize "^1.0.0"
- micromark-util-symbol "^1.0.0"
- micromark-util-types "^1.0.1"
- uvu "^0.5.0"
-
micromark-core-commonmark@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz#c691630e485021a68cf28dbc2b2ca27ebf678cd4"
@@ -8788,15 +8508,6 @@ micromark-extension-gfm@^3.0.0:
micromark-util-combine-extensions "^2.0.0"
micromark-util-types "^2.0.0"
-micromark-factory-destination@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz#eb815957d83e6d44479b3df640f010edad667b9f"
- integrity sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==
- dependencies:
- micromark-util-character "^1.0.0"
- micromark-util-symbol "^1.0.0"
- micromark-util-types "^1.0.0"
-
micromark-factory-destination@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz#8fef8e0f7081f0474fbdd92deb50c990a0264639"
@@ -8806,16 +8517,6 @@ micromark-factory-destination@^2.0.0:
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
-micromark-factory-label@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz#cc95d5478269085cfa2a7282b3de26eb2e2dec68"
- integrity sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==
- dependencies:
- micromark-util-character "^1.0.0"
- micromark-util-symbol "^1.0.0"
- micromark-util-types "^1.0.0"
- uvu "^0.5.0"
-
micromark-factory-label@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz#5267efa97f1e5254efc7f20b459a38cb21058ba1"
@@ -8826,14 +8527,6 @@ micromark-factory-label@^2.0.0:
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
-micromark-factory-space@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz#c8f40b0640a0150751d3345ed885a080b0d15faf"
- integrity sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==
- dependencies:
- micromark-util-character "^1.0.0"
- micromark-util-types "^1.0.0"
-
micromark-factory-space@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz#36d0212e962b2b3121f8525fc7a3c7c029f334fc"
@@ -8842,16 +8535,6 @@ micromark-factory-space@^2.0.0:
micromark-util-character "^2.0.0"
micromark-util-types "^2.0.0"
-micromark-factory-title@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz#dd0fe951d7a0ac71bdc5ee13e5d1465ad7f50ea1"
- integrity sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==
- dependencies:
- micromark-factory-space "^1.0.0"
- micromark-util-character "^1.0.0"
- micromark-util-symbol "^1.0.0"
- micromark-util-types "^1.0.0"
-
micromark-factory-title@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz#237e4aa5d58a95863f01032d9ee9b090f1de6e94"
@@ -8862,16 +8545,6 @@ micromark-factory-title@^2.0.0:
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
-micromark-factory-whitespace@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz#798fb7489f4c8abafa7ca77eed6b5745853c9705"
- integrity sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==
- dependencies:
- micromark-factory-space "^1.0.0"
- micromark-util-character "^1.0.0"
- micromark-util-symbol "^1.0.0"
- micromark-util-types "^1.0.0"
-
micromark-factory-whitespace@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz#06b26b2983c4d27bfcc657b33e25134d4868b0b1"
@@ -8882,14 +8555,6 @@ micromark-factory-whitespace@^2.0.0:
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
-micromark-util-character@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.2.0.tgz#4fedaa3646db249bc58caeb000eb3549a8ca5dcc"
- integrity sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==
- dependencies:
- micromark-util-symbol "^1.0.0"
- micromark-util-types "^1.0.0"
-
micromark-util-character@^2.0.0, micromark-util-character@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-2.1.1.tgz#2f987831a40d4c510ac261e89852c4e9703ccda6"
@@ -8898,13 +8563,6 @@ micromark-util-character@^2.0.0, micromark-util-character@^2.0.1:
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
-micromark-util-chunked@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz#37a24d33333c8c69a74ba12a14651fd9ea8a368b"
- integrity sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==
- dependencies:
- micromark-util-symbol "^1.0.0"
-
micromark-util-chunked@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz#47fbcd93471a3fccab86cff03847fc3552db1051"
@@ -8912,15 +8570,6 @@ micromark-util-chunked@^2.0.0:
dependencies:
micromark-util-symbol "^2.0.0"
-micromark-util-classify-character@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz#6a7f8c8838e8a120c8e3c4f2ae97a2bff9190e9d"
- integrity sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==
- dependencies:
- micromark-util-character "^1.0.0"
- micromark-util-symbol "^1.0.0"
- micromark-util-types "^1.0.0"
-
micromark-util-classify-character@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz#d399faf9c45ca14c8b4be98b1ea481bced87b629"
@@ -8930,14 +8579,6 @@ micromark-util-classify-character@^2.0.0:
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
-micromark-util-combine-extensions@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz#192e2b3d6567660a85f735e54d8ea6e3952dbe84"
- integrity sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==
- dependencies:
- micromark-util-chunked "^1.0.0"
- micromark-util-types "^1.0.0"
-
micromark-util-combine-extensions@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz#2a0f490ab08bff5cc2fd5eec6dd0ca04f89b30a9"
@@ -8946,13 +8587,6 @@ micromark-util-combine-extensions@^2.0.0:
micromark-util-chunked "^2.0.0"
micromark-util-types "^2.0.0"
-micromark-util-decode-numeric-character-reference@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz#b1e6e17009b1f20bc652a521309c5f22c85eb1c6"
- integrity sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==
- dependencies:
- micromark-util-symbol "^1.0.0"
-
micromark-util-decode-numeric-character-reference@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz#fcf15b660979388e6f118cdb6bf7d79d73d26fe5"
@@ -8960,16 +8594,6 @@ micromark-util-decode-numeric-character-reference@^2.0.0:
dependencies:
micromark-util-symbol "^2.0.0"
-micromark-util-decode-string@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz#dc12b078cba7a3ff690d0203f95b5d5537f2809c"
- integrity sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==
- dependencies:
- decode-named-character-reference "^1.0.0"
- micromark-util-character "^1.0.0"
- micromark-util-decode-numeric-character-reference "^1.0.0"
- micromark-util-symbol "^1.0.0"
-
micromark-util-decode-string@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz#6cb99582e5d271e84efca8e61a807994d7161eb2"
@@ -8980,33 +8604,16 @@ micromark-util-decode-string@^2.0.0:
micromark-util-decode-numeric-character-reference "^2.0.0"
micromark-util-symbol "^2.0.0"
-micromark-util-encode@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz#92e4f565fd4ccb19e0dcae1afab9a173bbeb19a5"
- integrity sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==
-
micromark-util-encode@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz#0d51d1c095551cfaac368326963cf55f15f540b8"
integrity sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==
-micromark-util-html-tag-name@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz#48fd7a25826f29d2f71479d3b4e83e94829b3588"
- integrity sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==
-
micromark-util-html-tag-name@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz#e40403096481986b41c106627f98f72d4d10b825"
integrity sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==
-micromark-util-normalize-identifier@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz#7a73f824eb9f10d442b4d7f120fecb9b38ebf8b7"
- integrity sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==
- dependencies:
- micromark-util-symbol "^1.0.0"
-
micromark-util-normalize-identifier@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz#c30d77b2e832acf6526f8bf1aa47bc9c9438c16d"
@@ -9014,13 +8621,6 @@ micromark-util-normalize-identifier@^2.0.0:
dependencies:
micromark-util-symbol "^2.0.0"
-micromark-util-resolve-all@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz#4652a591ee8c8fa06714c9b54cd6c8e693671188"
- integrity sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==
- dependencies:
- micromark-util-types "^1.0.0"
-
micromark-util-resolve-all@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz#e1a2d62cdd237230a2ae11839027b19381e31e8b"
@@ -9028,15 +8628,6 @@ micromark-util-resolve-all@^2.0.0:
dependencies:
micromark-util-types "^2.0.0"
-micromark-util-sanitize-uri@^1.0.0, micromark-util-sanitize-uri@^1.1.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz#613f738e4400c6eedbc53590c67b197e30d7f90d"
- integrity sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==
- dependencies:
- micromark-util-character "^1.0.0"
- micromark-util-encode "^1.0.0"
- micromark-util-symbol "^1.0.0"
-
micromark-util-sanitize-uri@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz#ab89789b818a58752b73d6b55238621b7faa8fd7"
@@ -9046,16 +8637,6 @@ micromark-util-sanitize-uri@^2.0.0:
micromark-util-encode "^2.0.0"
micromark-util-symbol "^2.0.0"
-micromark-util-subtokenize@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz#941c74f93a93eaf687b9054aeb94642b0e92edb1"
- integrity sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==
- dependencies:
- micromark-util-chunked "^1.0.0"
- micromark-util-symbol "^1.0.0"
- micromark-util-types "^1.0.0"
- uvu "^0.5.0"
-
micromark-util-subtokenize@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz#d8ade5ba0f3197a1cf6a2999fbbfe6357a1a19ee"
@@ -9066,49 +8647,16 @@ micromark-util-subtokenize@^2.0.0:
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
-micromark-util-symbol@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz#813cd17837bdb912d069a12ebe3a44b6f7063142"
- integrity sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==
-
micromark-util-symbol@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz#e5da494e8eb2b071a0d08fb34f6cefec6c0a19b8"
integrity sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==
-micromark-util-types@^1.0.0, micromark-util-types@^1.0.1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.1.0.tgz#e6676a8cae0bb86a2171c498167971886cb7e283"
- integrity sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==
-
micromark-util-types@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.2.tgz#f00225f5f5a0ebc3254f96c36b6605c4b393908e"
integrity sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==
-micromark@^3.0.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.2.0.tgz#1af9fef3f995ea1ea4ac9c7e2f19c48fd5c006e9"
- integrity sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==
- dependencies:
- "@types/debug" "^4.0.0"
- debug "^4.0.0"
- decode-named-character-reference "^1.0.0"
- micromark-core-commonmark "^1.0.1"
- micromark-factory-space "^1.0.0"
- micromark-util-character "^1.0.0"
- micromark-util-chunked "^1.0.0"
- micromark-util-combine-extensions "^1.0.0"
- micromark-util-decode-numeric-character-reference "^1.0.0"
- micromark-util-encode "^1.0.0"
- micromark-util-normalize-identifier "^1.0.0"
- micromark-util-resolve-all "^1.0.0"
- micromark-util-sanitize-uri "^1.0.0"
- micromark-util-subtokenize "^1.0.0"
- micromark-util-symbol "^1.0.0"
- micromark-util-types "^1.0.1"
- uvu "^0.5.0"
-
micromark@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/micromark/-/micromark-4.0.2.tgz#91395a3e1884a198e62116e33c9c568e39936fdb"
@@ -9238,11 +8786,6 @@ mlly@^1.7.4:
pkg-types "^1.3.0"
ufo "^1.5.4"
-mri@^1.1.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
- integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==
-
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
@@ -9967,10 +9510,10 @@ pretty-error@^4.0.0:
lodash "^4.17.20"
renderkid "^3.0.0"
-pretty-format@30.0.5:
- version "30.0.5"
- resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-30.0.5.tgz#e001649d472800396c1209684483e18a4d250360"
- integrity sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==
+pretty-format@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-30.2.0.tgz#2d44fe6134529aed18506f6d11509d8a62775ebe"
+ integrity sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==
dependencies:
"@jest/schemas" "30.0.5"
ansi-styles "^5.2.0"
@@ -10024,7 +9567,7 @@ prompts@^2.4.0:
kleur "^3.0.3"
sisteransi "^1.0.5"
-prop-types@^15.0.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
+prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -10164,20 +9707,6 @@ react-fast-compare@^3.0.1, react-fast-compare@^3.2.2:
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==
-"react-flow-renderer-lts@npm:react-flow-renderer@^10.3.17":
- version "10.3.17"
- resolved "https://registry.yarnpkg.com/react-flow-renderer/-/react-flow-renderer-10.3.17.tgz#06d6ecef5559ba5d3e64d2c8dcb74c43071d62b1"
- integrity sha512-bywiqVErlh5kCDqw3x0an5Ur3mT9j9CwJsDwmhmz4i1IgYM1a0SPqqEhClvjX+s5pU4nHjmVaGXWK96pwsiGcQ==
- dependencies:
- "@babel/runtime" "^7.18.9"
- "@types/d3" "^7.4.0"
- "@types/resize-observer-browser" "^0.1.7"
- classcat "^5.0.3"
- d3-drag "^3.0.0"
- d3-selection "^3.0.0"
- d3-zoom "^3.0.0"
- zustand "^3.7.2"
-
react-flow-renderer@9.7.4:
version "9.7.4"
resolved "https://registry.yarnpkg.com/react-flow-renderer/-/react-flow-renderer-9.7.4.tgz#11394c05ca953b650e2017d056c075fd3df9075c"
@@ -10230,27 +9759,6 @@ react-lorem-ipsum@^1.4.9:
resolved "https://registry.yarnpkg.com/react-lorem-ipsum/-/react-lorem-ipsum-1.4.10.tgz#b5a0dee81d2dc3c96123f85d4bcff3405441d2ff"
integrity sha512-PCEuauLZTGJkm++oxJeUycEgQOBg3qmmD7pn5sUyq9e0OvvNbW32RKQsSgalAYGUIbS91UkDgxvt6iHVAsqYJw==
-"react-markdown-deprecated@npm:react-markdown@^8.0.7":
- version "8.0.7"
- resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.7.tgz#c8dbd1b9ba5f1c5e7e5f2a44de465a3caafdf89b"
- integrity sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==
- dependencies:
- "@types/hast" "^2.0.0"
- "@types/prop-types" "^15.0.0"
- "@types/unist" "^2.0.0"
- comma-separated-tokens "^2.0.0"
- hast-util-whitespace "^2.0.0"
- prop-types "^15.0.0"
- property-information "^6.0.0"
- react-is "^18.0.0"
- remark-parse "^10.0.0"
- remark-rehype "^10.0.0"
- space-separated-tokens "^2.0.0"
- style-to-object "^0.4.0"
- unified "^10.0.0"
- unist-util-visit "^4.0.0"
- vfile "^5.0.0"
-
react-markdown@^10.1.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-10.1.0.tgz#e22bc20faddbc07605c15284255653c0f3bad5ca"
@@ -10528,15 +10036,6 @@ remark-gfm@^4.0.1:
remark-stringify "^11.0.0"
unified "^11.0.0"
-remark-parse@^10.0.0:
- version "10.0.2"
- resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.2.tgz#ca241fde8751c2158933f031a4e3efbaeb8bc262"
- integrity sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==
- dependencies:
- "@types/mdast" "^3.0.0"
- mdast-util-from-markdown "^1.0.0"
- unified "^10.0.0"
-
remark-parse@^11.0.0:
version "11.0.0"
resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-11.0.0.tgz#aa60743fcb37ebf6b069204eb4da304e40db45a1"
@@ -10547,16 +10046,6 @@ remark-parse@^11.0.0:
micromark-util-types "^2.0.0"
unified "^11.0.0"
-remark-rehype@^10.0.0:
- version "10.1.0"
- resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-10.1.0.tgz#32dc99d2034c27ecaf2e0150d22a6dcccd9a6279"
- integrity sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==
- dependencies:
- "@types/hast" "^2.0.0"
- "@types/mdast" "^3.0.0"
- mdast-util-to-hast "^12.1.0"
- unified "^10.0.0"
-
remark-rehype@^11.0.0:
version "11.1.2"
resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-11.1.2.tgz#2addaadda80ca9bd9aa0da763e74d16327683b37"
@@ -10697,13 +10186,6 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
-sade@^1.7.3:
- version "1.8.1"
- resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701"
- integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==
- dependencies:
- mri "^1.1.0"
-
safe-array-concat@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3"
@@ -11279,13 +10761,6 @@ style-to-object@1.0.8:
dependencies:
inline-style-parser "0.2.4"
-style-to-object@^0.4.0:
- version "0.4.4"
- resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.4.tgz#266e3dfd56391a7eefb7770423612d043c3f33ec"
- integrity sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==
- dependencies:
- inline-style-parser "0.1.1"
-
stylelint-config-recess-order@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/stylelint-config-recess-order/-/stylelint-config-recess-order-6.0.0.tgz#5954333b0fa992a4218c6636c66186983a1051d9"
@@ -11781,19 +11256,6 @@ unicorn-magic@^0.3.0:
resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.3.0.tgz#4efd45c85a69e0dd576d25532fbfa22aa5c8a104"
integrity sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==
-unified@^10.0.0:
- version "10.1.2"
- resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df"
- integrity sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==
- dependencies:
- "@types/unist" "^2.0.0"
- bail "^2.0.0"
- extend "^3.0.0"
- is-buffer "^2.0.0"
- is-plain-obj "^4.0.0"
- trough "^2.0.0"
- vfile "^5.0.0"
-
unified@^11.0.0, unified@^11.0.5:
version "11.0.5"
resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.5.tgz#f66677610a5c0a9ee90cab2b8d4d66037026d9e1"
@@ -11822,23 +11284,11 @@ unist-util-find-after@^5.0.0:
"@types/unist" "^3.0.0"
unist-util-is "^6.0.0"
-unist-util-generated@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.1.tgz#e37c50af35d3ed185ac6ceacb6ca0afb28a85cae"
- integrity sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==
-
unist-util-is@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797"
integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==
-unist-util-is@^5.0.0:
- version "5.2.1"
- resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-5.2.1.tgz#b74960e145c18dcb6226bc57933597f5486deae9"
- integrity sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==
- dependencies:
- "@types/unist" "^2.0.0"
-
unist-util-is@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-6.0.0.tgz#b775956486aff107a9ded971d996c173374be424"
@@ -11846,13 +11296,6 @@ unist-util-is@^6.0.0:
dependencies:
"@types/unist" "^3.0.0"
-unist-util-position@^4.0.0:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-4.0.4.tgz#93f6d8c7d6b373d9b825844645877c127455f037"
- integrity sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==
- dependencies:
- "@types/unist" "^2.0.0"
-
unist-util-position@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-5.0.0.tgz#678f20ab5ca1207a97d7ea8a388373c9cf896be4"
@@ -11860,13 +11303,6 @@ unist-util-position@^5.0.0:
dependencies:
"@types/unist" "^3.0.0"
-unist-util-stringify-position@^3.0.0:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz#03ad3348210c2d930772d64b489580c13a7db39d"
- integrity sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==
- dependencies:
- "@types/unist" "^2.0.0"
-
unist-util-stringify-position@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz#449c6e21a880e0855bf5aabadeb3a740314abac2"
@@ -11882,14 +11318,6 @@ unist-util-visit-parents@^3.0.0:
"@types/unist" "^2.0.0"
unist-util-is "^4.0.0"
-unist-util-visit-parents@^5.1.1:
- version "5.1.3"
- resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz#b4520811b0ca34285633785045df7a8d6776cfeb"
- integrity sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==
- dependencies:
- "@types/unist" "^2.0.0"
- unist-util-is "^5.0.0"
-
unist-util-visit-parents@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz#4d5f85755c3b8f0dc69e21eca5d6d82d22162815"
@@ -11907,15 +11335,6 @@ unist-util-visit@^2.0.3:
unist-util-is "^4.0.0"
unist-util-visit-parents "^3.0.0"
-unist-util-visit@^4.0.0:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-4.1.2.tgz#125a42d1eb876283715a3cb5cceaa531828c72e2"
- integrity sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==
- dependencies:
- "@types/unist" "^2.0.0"
- unist-util-is "^5.0.0"
- unist-util-visit-parents "^5.1.1"
-
unist-util-visit@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-5.0.0.tgz#a7de1f31f72ffd3519ea71814cccf5fd6a9217d6"
@@ -12073,16 +11492,6 @@ uuid@^9.0.0:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
-uvu@^0.5.0:
- version "0.5.6"
- resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df"
- integrity sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==
- dependencies:
- dequal "^2.0.0"
- diff "^5.0.0"
- kleur "^4.0.3"
- sade "^1.7.3"
-
v8-compile-cache-lib@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
@@ -12105,14 +11514,6 @@ vfile-location@^5.0.0:
"@types/unist" "^3.0.0"
vfile "^6.0.0"
-vfile-message@^3.0.0:
- version "3.1.4"
- resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.1.4.tgz#15a50816ae7d7c2d1fa87090a7f9f96612b59dea"
- integrity sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==
- dependencies:
- "@types/unist" "^2.0.0"
- unist-util-stringify-position "^3.0.0"
-
vfile-message@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.2.tgz#c883c9f677c72c166362fd635f21fc165a7d1181"
@@ -12121,16 +11522,6 @@ vfile-message@^4.0.0:
"@types/unist" "^3.0.0"
unist-util-stringify-position "^4.0.0"
-vfile@^5.0.0:
- version "5.3.7"
- resolved "https://registry.yarnpkg.com/vfile/-/vfile-5.3.7.tgz#de0677e6683e3380fafc46544cfe603118826ab7"
- integrity sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==
- dependencies:
- "@types/unist" "^2.0.0"
- is-buffer "^2.0.0"
- unist-util-stringify-position "^3.0.0"
- vfile-message "^3.0.0"
-
vfile@^6.0.0:
version "6.0.3"
resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.3.tgz#3652ab1c496531852bf55a6bac57af981ebc38ab"
@@ -12503,11 +11894,6 @@ yocto-queue@^1.0.0, yocto-queue@^1.1.1:
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.2.1.tgz#36d7c4739f775b3cbc28e6136e21aa057adec418"
integrity sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==
-zustand@^3.7.2:
- version "3.7.2"
- resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.7.2.tgz#7b44c4f4a5bfd7a8296a3957b13e1c346f42514d"
- integrity sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==
-
zustand@^4.4.0:
version "4.5.6"
resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.5.6.tgz#6857d52af44874a79fb3408c9473f78367255c96"