diff --git a/.prettierrc b/.prettierrc index 0bb3c2f..f0e87a2 100644 --- a/.prettierrc +++ b/.prettierrc @@ -4,5 +4,15 @@ "trailingComma": "none", "semi": true, "useTabs": true, - "arrowParens": "avoid" + "arrowParens": "avoid", + "overrides": [ + { + "files": "*.md", + "options": { + "useTabs": false, + "tabWidth": 2, + "trailingComma": "all" + } + } + ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e3569d..95dbc93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.37.0 + +This version introduces a small internal refactor that allows exposing new events in the Designer class: `onRootComponentUpdated` and `onPreferencesChanged`. + # 0.36.0 This version introduces a change to the `onDefinitionChanged` event. Previously, the payload of this event was the workflow definition itself. Now, the payload has been extended to the following structure: @@ -15,10 +19,12 @@ This change is NOT backward compatible. If you are using the `onDefinitionChange ```ts // before -designer.onDefinitionChanged((definition) => { /* ... */ }); +designer.onDefinitionChanged(definition => { + /* ... */ +}); // now -designer.onDefinitionChanged((event) => { +designer.onDefinitionChanged(event => { const definition = event.definition; // ... }); @@ -61,12 +67,14 @@ const configuration = { steps: { canUnselectStep: (step, parentSequence) => { return areChangesSaved() === true; - }, - }, + } + } // ... }; -designer.onStepUnselectionBlocked((targetStepId) => { /* ... */ }); +designer.onStepUnselectionBlocked(targetStepId => { + /* ... */ +}); ``` Please note that you should NOT use `window.confirm()` or other blocking functions inside the `canUnselectStep` callback, as this callback may be invoked multiple times during drag operations. To handle this correctly, implement your own UI logic to notify the user about any required actions before unselection can proceed. Please check [this example](https://nocode-js.github.io/sequential-workflow-designer/react-app/#save-required-editor). @@ -105,7 +113,7 @@ import { StepsDesignerExtension } from 'sequential-workflow-designer'; const extensions = [ StepsDesignerExtension.create({ switch: { - branchNamesResolver: (step) => Object.keys(step.branches) + branchNamesResolver: step => Object.keys(step.branches) } }) ]; @@ -210,7 +218,9 @@ This version introduces a new function in the `Designer` class: `updateLayout()` This release updates the CSS selectors for the toolbox, allowing you to adjust its width with a single CSS override. ```css -.sqd-toolbox { width: 170px !important; } +.sqd-toolbox { + width: 170px !important; +} ``` # 0.22.1 @@ -277,8 +287,8 @@ Fixed the bug with refreshing the state modifier dependencies. ## 0.19.0 -* Added the `isSelectable` callback to the `StepsConfiguration` interface. Now it's possible to disable the selection of steps. -* Deleted deprecated methods and interfaces. +- Added the `isSelectable` callback to the `StepsConfiguration` interface. Now it's possible to disable the selection of steps. +- Deleted deprecated methods and interfaces. ## 0.18.5 @@ -290,7 +300,9 @@ This version removes the features introduced in the previous release. We noticed ```ts function appendStep() { - const newStep: Step = { /* ... */ }; + const newStep: Step = { + /* ... */ + }; const newDefinition = ObjectCloner.deepClone(designer.getDefinition()); newDefinition.sequence.push(newStep); @@ -330,7 +342,9 @@ This version finally renames the "global editor" into the "root editor". This ch const configuration = { editors: { // globalEditorProvider: () => {}, is not supported anymore, use `rootEditorProvider` instead. - rootEditorProvider: (definition, rootContext, isReadonly) => { /* ... */ }, + rootEditorProvider: (definition, rootContext, isReadonly) => { + /* ... */ + } // ... } }; @@ -350,8 +364,7 @@ This version also renames the `sqd-global-editor` class of the root editor into ```html - + ``` ## 0.16.10 @@ -367,7 +380,7 @@ This version adds a possibility to disable keyboard shortcuts. Additionally you ```js // Disabled shortcuts const configuration = { - keyboard: false, + keyboard: false // ... }; ``` @@ -405,7 +418,7 @@ This version introduces the `isAutoSelectDisabled` option. Now it's possible to ```js const configuration = { steps: { - isAutoSelectDisabled: true, + isAutoSelectDisabled: true // ... } }; @@ -416,7 +429,7 @@ Additionally, this version introduces possibility to initialize the designer wit ```js const configuration = { undoStackSize: 10, - undoStack: myUndoStack, + undoStack: myUndoStack // ... }; ``` @@ -436,9 +449,7 @@ This version adds: `isReadonly`, `selectedStepId`, `uidGenerator`, `isToolboxCol This version adds the `onSelectedStepIdChanged` event to the Angular package. ```html - - + ``` ## 0.16.1 @@ -469,8 +480,8 @@ Please note that the `designer.css`, `designer-light.css`, and `designer-dark.cs ### Breaking Changes -* The `sqd-grid-path` class of the line grid is renamed to `sqd-line-grid-path`. -* Selectors in the `designer.css`, `designer-light.css` and `designer-dark.css` files have been changed. +- The `sqd-grid-path` class of the line grid is renamed to `sqd-line-grid-path`. +- Selectors in the `designer.css`, `designer-light.css` and `designer-dark.css` files have been changed. ## 0.14.2 @@ -498,7 +509,7 @@ This version introduces the context menu, providing a new and interactive way to ```ts const configuration = { - contextMenu: false, + contextMenu: false // ... }; ``` @@ -510,8 +521,8 @@ const configuration = { steps: { isDuplicable: (step, parentSequence) => { return true; - }, - }, + } + } // ... }; ``` @@ -531,7 +542,9 @@ Now it's possible to configure the size of grid cells. The default size is `48` We have added a third parameter, `definition`, to the step editor provider. ```js -function stepEditorProvider(step, stepContext, definition) { /* ... */ } +function stepEditorProvider(step, stepContext, definition) { + /* ... */ +} ``` ## 0.13.4 @@ -546,26 +559,26 @@ designer.getStepParents('eb4f481ee1b90c6e3fc9b42dd010d2a5'); This version introduces 4 new features: -* The custom label provider for the toolbox. By default, the toolbox displays a label of a step from the `name` field. You may override this behaviour and pass own label provider now. +- The custom label provider for the toolbox. By default, the toolbox displays a label of a step from the `name` field. You may override this behaviour and pass own label provider now. ```js const configuration = { toolbox: { - labelProvider: (step) => `** ${step.name} **`, + labelProvider: step => `** ${step.name} **` // ... - }, + } // ... }; ``` -* Control the collapse of the toolbox. +- Control the collapse of the toolbox. ```js const configuration = { toolbox: { - isCollapsed: true, // or false + isCollapsed: true // or false // ... - }, + } // ... }; @@ -573,14 +586,14 @@ designer.isToolboxCollapsed(); // returns true or false designer.setIsToolboxCollapsed(true); ``` -* Control the collapse of the editor. +- Control the collapse of the editor. ```js const configuration = { editors: { - isCollapsed: true, // or false + isCollapsed: true // or false // ... - }, + } // ... }; @@ -588,11 +601,11 @@ designer.isEditorCollapsed(); // returns true or false designer.setIsEditorCollapsed(true); ``` -* It's possible now to replace the default unique identifier generator by a custom one. +- It's possible now to replace the default unique identifier generator by a custom one. ```js const configuration = { - uidGenerator: () => Math.random().toString(), + uidGenerator: () => Math.random().toString() // ... }; ``` @@ -629,9 +642,9 @@ The designer has allowed only the validation of the steps so far. The root of th ### Breaking Changes -* The `validator` property in the `steps` group of the configuration is deleted. Use the `step` property in the `validator` group instead. -* The step validator has a new parameter: `definition`. -* Added the root validator. +- The `validator` property in the `steps` group of the configuration is deleted. Use the `step` property in the `validator` group instead. +- The step validator has a new parameter: `definition`. +- Added the root validator. ```js const configuration = { @@ -650,22 +663,22 @@ const configuration = { ### Breaking Changes -* This version introduces a few changes in the `customActionHandler` handler: - * the first parameter is an object now, previously it was a string. To read action type you need to read the `type` property from the object. - * the `step` parameter is nullable now, - * we added a `context` parameter that allows to notify about changes in the definition. -* Added new classes for label components: `sqd-label-primary` and `sqd-label-secondary`. +- This version introduces a few changes in the `customActionHandler` handler: + - the first parameter is an object now, previously it was a string. To read action type you need to read the `type` property from the object. + - the `step` parameter is nullable now, + - we added a `context` parameter that allows to notify about changes in the definition. +- Added new classes for label components: `sqd-label-primary` and `sqd-label-secondary`. ## 0.10.2 -* Fixed the bug with moving the viewport by the scroll wheel button. -* Added a simple animation to placeholders during dragging. +- Fixed the bug with moving the viewport by the scroll wheel button. +- Added a simple animation to placeholders during dragging. ## 0.10.1 -* Fixed the bug with the auto-hide feature in the smart editor. -* Fixed the bug with rendering wide components in the sequence component. -* Fixed the bug with dragging when the designer is attached to a scrolled page. +- Fixed the bug with the auto-hide feature in the smart editor. +- Fixed the bug with rendering wide components in the sequence component. +- Fixed the bug with dragging when the designer is attached to a scrolled page. ## 0.10.0 @@ -674,7 +687,7 @@ Refactored the step component interface. Extracted the logic of the step validat Additionally, now it's possible manually refreshing the validation from outside of the designer. The validation is a special case of a badge. To refresh the validation you need to call the `updateBadges` method. ```ts -designer.updateBadges(); +designer.updateBadges(); ``` ## 0.9.2 @@ -695,7 +708,7 @@ This version changes the main configuration. The "isHidden" properties are prohi const configuration = { toolbox: false, editors: false, - controlBar: false, + controlBar: false // ... }; ``` @@ -705,13 +718,19 @@ To display components you need to set a proper value. ```js const configuration = { toolbox: { - groups: [ /* ... */ ] + groups: [ + /* ... */ + ] }, editors: { - globalEditorProvider: () => { /* ... */ }, - stepEditorProvider: () => { /* ... */ }, + globalEditorProvider: () => { + /* ... */ + }, + stepEditorProvider: () => { + /* ... */ + } }, - controlBar: true, + controlBar: true // ... }; ``` @@ -724,13 +743,13 @@ The `controlBar` property is required from now. This change applies for the `seq Changed format of bundles: -* `sequential-workflow-designer` to UMD, ESM and CommonJS, -* `sequential-workflow-designer-react` to ESM and CommonJS. +- `sequential-workflow-designer` to UMD, ESM and CommonJS, +- `sequential-workflow-designer-react` to ESM and CommonJS. ## 0.8.0 -* This release introduces a better support for TypeScript. -* The model of the workflow definition is moved from the `sequential-workflow-designer` package to the `sequential-workflow-model` package. By this it's possible to create a common package with your workflow model and use it for the front-end and back-end applications at the same time. The `sequential-workflow-designer` package exports definition types as before, but these types come from the `sequential-workflow-model` package. You don't have to include the `sequential-workflow-model` package to your project if you don't need it. You can read more about this approach [here](https://nocode-js.com/docs/sequential-workflow-designer/sharing-types-between-frontend-and-backend). +- This release introduces a better support for TypeScript. +- The model of the workflow definition is moved from the `sequential-workflow-designer` package to the `sequential-workflow-model` package. By this it's possible to create a common package with your workflow model and use it for the front-end and back-end applications at the same time. The `sequential-workflow-designer` package exports definition types as before, but these types come from the `sequential-workflow-model` package. You don't have to include the `sequential-workflow-model` package to your project if you don't need it. You can read more about this approach [here](https://nocode-js.com/docs/sequential-workflow-designer/sharing-types-between-frontend-and-backend). #### Breaking Changes @@ -740,13 +759,13 @@ Changed format of bundles: ## 0.7.0 -* The step validator has two parameters from now: `step` and `parentSequence`. -* Added new editing restrictions: `isDraggable` and `isDeletable`. +- The step validator has two parameters from now: `step` and `parentSequence`. +- Added new editing restrictions: `isDraggable` and `isDeletable`. #### Breaking Changes -* Refactored step components by introducing the `StepContext` interface. -* Renamed `.sqd-step-start-stop*` CSS selectors to `.sqd-root-start-stop*`. +- Refactored step components by introducing the `StepContext` interface. +- Renamed `.sqd-step-start-stop*` CSS selectors to `.sqd-root-start-stop*`. ## 0.6.0 @@ -754,7 +773,7 @@ Fixed support for touchpad. #### Breaking Changes -* Redesigned the `DesignerExtension` interface. This change increases the extensibility of the designer. +- Redesigned the `DesignerExtension` interface. This change increases the extensibility of the designer. ## 0.5.4 @@ -762,8 +781,8 @@ This version introduces the first release of the [Sequential Workflow Designer f ## 0.5.3 -* The disabled drag mode doesn't block the step selecting anymore. -* Replaced custom shapes by icons from the `Icons` class for `StartStopComponentView`. +- The disabled drag mode doesn't block the step selecting anymore. +- Replaced custom shapes by icons from the `Icons` class for `StartStopComponentView`. ## 0.5.2 @@ -771,19 +790,19 @@ This version introduces the first release of the [Sequential Workflow Designer f ## 0.5.1 -* Fixed calculation of label width in the switch step. -* Added an exclamation mark to the warning icon. +- Fixed calculation of label width in the switch step. +- Added an exclamation mark to the warning icon. ## 0.5.0 -* Fixed losing the disabled state during dragging. -* Fixed steps rendering with long labels. -* Added to the global editor and the step editor the common class: `sqd-editor`. +- Fixed losing the disabled state during dragging. +- Fixed steps rendering with long labels. +- Added to the global editor and the step editor the common class: `sqd-editor`. #### Breaking Changes -* Changed a behavior of the default zoom. From now the designer shows a whole flow at the start. -* Zoom is aligned to the predefined constants. +- Changed a behavior of the default zoom. From now the designer shows a whole flow at the start. +- Zoom is aligned to the predefined constants. ## 0.4.0 @@ -791,8 +810,8 @@ This version brings rendering speed improvements. Check the `stress-test.html` e #### Breaking Changes -* Replaced all icons to material icons. -* Normalized step CSS classes. All components have the `sqd-step--` prefix from now. +- Replaced all icons to material icons. +- Normalized step CSS classes. All components have the `sqd-step--` prefix from now. ## 0.3.0 @@ -802,7 +821,8 @@ This version introduces new build formats (ESM, UMD) of the package. #### Breaking Changes -* Default export of the `Designer` class is removed. Now you should import directly the `Designer` class. +- Default export of the `Designer` class is removed. Now you should import directly the `Designer` class. + ```ts import { Designer } from 'sequential-workflow-designer'; Designer.create(/* ... */); @@ -813,27 +833,30 @@ This version introduces new build formats (ESM, UMD) of the package. ```html ``` -* The package now contains two type of build: ESM and UMD. ESM build is located in the `lib` folder. UMD build is located in the `dist` folder. That means the URL to the CDN is also changed. - + +- The package now contains two type of build: ESM and UMD. ESM build is located in the `lib` folder. UMD build is located in the `dist` folder. That means the URL to the CDN is also changed. + ```html ``` -* Static method `Designer.utils.nextId()` is deleted. You should use the `next()` from the `Uid` class. Example: + +- Static method `Designer.utils.nextId()` is deleted. You should use the `next()` from the `Uid` class. Example: ```ts import { Uid } from 'sequential-workflow-designer'; Uid.next(); ``` -* Static method `Designer.utils.getParents()` is deleted. You should use the `getStepParents()` method from the `Designer` class. Example: +- Static method `Designer.utils.getParents()` is deleted. You should use the `getStepParents()` method from the `Designer` class. Example: ```ts designer.getStepParents(needleStep); ``` -* The `ComponentType` is not an enum anymore. It's a type (`string`). This change doesn't affect serialized JSONs. + +- The `ComponentType` is not an enum anymore. It's a type (`string`). This change doesn't affect serialized JSONs. ## 0.2.3 @@ -849,7 +872,7 @@ Support undo and redo. This feature is disabled by default. To enable it add the ```js const config = { - undoStackSize: 10, + undoStackSize: 10 // ... }; ``` @@ -891,11 +914,11 @@ const config = { The `type` of a step cannot contain special characters from now. Check [the type validator](src/core/type-validator.ts). -* ✅ `someType` -* ✅ `some-type` -* ✅ `some_type` -* ❌ `some type` -* ❌ `someType!` +- ✅ `someType` +- ✅ `some-type` +- ✅ `some_type` +- ❌ `some type` +- ❌ `someType!` By this, we could add the `type` to an element's class on the SVG canvas. That allows to customize components by CSS. Check [this example](examples/code-generator.html). diff --git a/README.md b/README.md index 8a9dbc9..75c3c3a 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,16 @@ [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fb4rtaz%2Fsequential-workflow-designer%2Fbadge%3Fref%3Dmain&style=flat-square)](https://actions-badge.atrox.dev/b4rtaz/sequential-workflow-designer/goto?ref=main) [![License: MIT](https://img.shields.io/badge/license-MIT-green?style=flat-square)](/LICENSE) [![View this project on NPM](https://img.shields.io/npm/v/sequential-workflow-designer.svg?style=flat-square)](https://npmjs.org/package/sequential-workflow-designer) -Sequential workflow designer with 0 external dependencies for web applications. It's written in pure TypeScript and uses SVG for rendering. This designer is not associated with any workflow engine. It's full generic. You may create any kind application by this, from graphical programming languages to workflow builders. +Sequential workflow designer with no external dependencies for web applications. It is written in pure TypeScript and uses SVG for rendering. This designer is not associated with any workflow engine, it is fully generic. You can use it to create any kind of application, from graphical programming languages to workflow builders. Features: -* 0 external dependencies, -* fully generic and configurable, -* use light/dark/soft themes or customize easily, -* compatible with modern browsers and mobile devices, -* the definition is stored as JSON, -* supports [Angular](./angular/designer/), [React](./react/) and [Svelte](./svelte/). +- No external dependencies +- Fully generic and configurable +- Supports light, dark, and soft themes, with easy customization +- Compatible with modern browsers and mobile devices +- Definitions are stored as JSON +- Supports [Angular](./angular/designer/), [React](./react/) and [Svelte](./svelte/). 📝 Check the [documentation](https://nocode-js.com/docs/category/sequential-workflow-designer) for more details. @@ -21,51 +21,51 @@ Features: ## 👀 Examples -* [⏩ Live Testing](https://nocode-js.github.io/sequential-workflow-designer/examples/live-testing.html) -* [💥 Triggers](https://nocode-js.github.io/sequential-workflow-designer/examples/triggers.html) -* [❎ Fullscreen](https://nocode-js.github.io/sequential-workflow-designer/examples/fullscreen.html) -* [🌅 Image Filter](https://nocode-js.github.io/sequential-workflow-designer/examples/image-filter.html) -* [🔴 Particles](https://nocode-js.github.io/sequential-workflow-designer/examples/particles.html) -* [🌍 Internationalization](https://nocode-js.github.io/sequential-workflow-designer/examples/i18n.html) -* [⛅ Light Dark](https://nocode-js.github.io/sequential-workflow-designer/examples/light-dark.html) -* [🤖 Code Generator](https://nocode-js.github.io/sequential-workflow-designer/examples/code-generator.html) -* [🌻 Rendering Test](https://nocode-js.github.io/sequential-workflow-designer/examples/rendering-test.html) -* [🚄 Stress Test](https://nocode-js.github.io/sequential-workflow-designer/examples/stress-test.html) -* [🚪 Editing Restrictions](https://nocode-js.github.io/sequential-workflow-designer/examples/editing-restrictions.html) -* [📜 Scrollable Page](https://nocode-js.github.io/sequential-workflow-designer/examples/scrollable-page.html) -* [🌵 Multi-Conditional Switch](https://nocode-js.github.io/sequential-workflow-designer/examples/multi-conditional-switch.html) -* [🌀 Auto-Select](https://nocode-js.github.io/sequential-workflow-designer/examples/auto-select.html) -* [Angular Demo](https://nocode-js.github.io/sequential-workflow-designer/angular-app/) -* [React Demo](https://nocode-js.github.io/sequential-workflow-designer/react-app/) -* [Svelte Demo](https://nocode-js.github.io/sequential-workflow-designer/svelte-app/) +- [⏩ Live Testing](https://nocode-js.github.io/sequential-workflow-designer/examples/live-testing.html) +- [💥 Triggers](https://nocode-js.github.io/sequential-workflow-designer/examples/triggers.html) +- [❎ Fullscreen](https://nocode-js.github.io/sequential-workflow-designer/examples/fullscreen.html) +- [🌅 Image Filter](https://nocode-js.github.io/sequential-workflow-designer/examples/image-filter.html) +- [🔴 Particles](https://nocode-js.github.io/sequential-workflow-designer/examples/particles.html) +- [🌍 Internationalization](https://nocode-js.github.io/sequential-workflow-designer/examples/i18n.html) +- [⛅ Light Dark](https://nocode-js.github.io/sequential-workflow-designer/examples/light-dark.html) +- [🤖 Code Generator](https://nocode-js.github.io/sequential-workflow-designer/examples/code-generator.html) +- [🌻 Rendering Test](https://nocode-js.github.io/sequential-workflow-designer/examples/rendering-test.html) +- [🚄 Stress Test](https://nocode-js.github.io/sequential-workflow-designer/examples/stress-test.html) +- [🚪 Editing Restrictions](https://nocode-js.github.io/sequential-workflow-designer/examples/editing-restrictions.html) +- [📜 Scrollable Page](https://nocode-js.github.io/sequential-workflow-designer/examples/scrollable-page.html) +- [🌵 Multi-Conditional Switch](https://nocode-js.github.io/sequential-workflow-designer/examples/multi-conditional-switch.html) +- [🌀 Auto-Select](https://nocode-js.github.io/sequential-workflow-designer/examples/auto-select.html) +- [Angular Demo](https://nocode-js.github.io/sequential-workflow-designer/angular-app/) +- [React Demo](https://nocode-js.github.io/sequential-workflow-designer/react-app/) +- [Svelte Demo](https://nocode-js.github.io/sequential-workflow-designer/svelte-app/) Pro: -* [🤩 Pro Components](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/pro-components.html) -* [🍬 Custom Theme Flat](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/custom-theme-flat.html) -* [🌹 Custom Step Types](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/custom-step-types.html) -* [📺 Popup Editor](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/popup-editor.html) -* [🔽 Collapsible Region](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/collapsible-region.html) -* [💼 Copy Paste](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/copy-paste.html) -* [👈 Goto](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/goto.html) -* [📁 Folders](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/folders.html) -* [⭕ Wheel Mode](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/wheel-mode.html) -* [💠 Grid](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/grid.html) -* [🐭 Minimal Root Component](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/minimal-root-component.html) -* [🦁 External UI Components](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/external-ui-components.html) -* [👋 Custom Dragged Component](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/custom-dragged-component.html) -* [🔰 Badges](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/badges.html) -* [🎩 Custom Viewport](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/custom-viewport.html) -* [👊 Double Click](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/double-click.html) -* [🛎 Clickable Placeholder](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/clickable-placeholder.html) -* [📮 Conditional Placeholders](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/conditional-placeholders.html) -* [React Pro Demo](https://nocode-js.com/examples/sequential-workflow-designer-pro/react-pro-app/build/index.html) -* [Angular Pro Demo](https://nocode-js.com/examples/sequential-workflow-designer-pro/angular-pro-app/angular-app/index.html) +- [🤩 Pro Components](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/pro-components.html) +- [🍬 Custom Theme Flat](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/custom-theme-flat.html) +- [🌹 Custom Step Types](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/custom-step-types.html) +- [📺 Popup Editor](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/popup-editor.html) +- [🔽 Collapsible Region](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/collapsible-region.html) +- [💼 Copy Paste](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/copy-paste.html) +- [👈 Goto](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/goto.html) +- [📁 Folders](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/folders.html) +- [⭕ Wheel Mode](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/wheel-mode.html) +- [💠 Grid](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/grid.html) +- [🐭 Minimal Root Component](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/minimal-root-component.html) +- [🦁 External UI Components](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/external-ui-components.html) +- [👋 Custom Dragged Component](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/custom-dragged-component.html) +- [🔰 Badges](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/badges.html) +- [🎩 Custom Viewport](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/custom-viewport.html) +- [👊 Double Click](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/double-click.html) +- [🛎 Clickable Placeholder](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/clickable-placeholder.html) +- [📮 Conditional Placeholders](https://nocode-js.com/examples/sequential-workflow-designer-pro/webpack-pro-app/public/conditional-placeholders.html) +- [React Pro Demo](https://nocode-js.com/examples/sequential-workflow-designer-pro/react-pro-app/build/index.html) +- [Angular Pro Demo](https://nocode-js.com/examples/sequential-workflow-designer-pro/angular-pro-app/angular-app/index.html) ## 👩‍💻 Integrations -* [⛽ Sequential Workflow Editor](https://github.com/nocode-js/sequential-workflow-editor) - Powerful step editor builder. Don't write step editors manually, build them. -* [🚚 Sequential Workflow Machine](https://github.com/nocode-js/sequential-workflow-machine) - Workflow engine for browser and NodeJS apps, powered by the xstate library. +- [⛽ Sequential Workflow Editor](https://github.com/nocode-js/sequential-workflow-editor) - Powerful step editor builder. Don't write step editors manually, build them. +- [🚚 Sequential Workflow Machine](https://github.com/nocode-js/sequential-workflow-machine) - Workflow engine for browser and NodeJS apps, powered by the xstate library. ## 🚀 Installation @@ -105,11 +105,12 @@ Add the below code to your head section in HTML document. ```html -... - - - - + ... + + + + + ``` Call the designer by: @@ -129,12 +130,12 @@ const placeholder = document.getElementById('placeholder'); const definition = { properties: { - 'myProperty': 'my-value', + myProperty: 'my-value', // root properties... }, sequence: [ // steps... - ] + ], }; const configuration = { @@ -156,7 +157,7 @@ const configuration = { return step.properties['isDeletable']; }, isDuplicable: (step, parentSequence) => { - return true; + return true; }, canInsertStep: (step, targetSequence, targetIndex) => { return targetSequence.length < 5; @@ -166,7 +167,7 @@ const configuration = { }, canDeleteStep: (step, parentSequence) => { return step.name !== 'x'; - } + }, }, validator: { @@ -175,9 +176,9 @@ const configuration = { step: (step, parentSequence, definition) => { return /^[a-z]+$/.test(step.name); }, - root: (definition) => { + root: definition => { return definition.properties['memory'] > 256; - } + }, }, toolbox: { @@ -187,15 +188,15 @@ const configuration = { name: 'Files', steps: [ // steps for the toolbox's group - ] + ], }, { name: 'Notification', steps: [ // steps for the toolbox's group - ] - } - ] + ], + }, + ], }, editors: { @@ -209,7 +210,7 @@ const configuration = { const editor = document.createElement('div'); // ... return editor; - } + }, }, controlBar: true, @@ -217,7 +218,7 @@ const configuration = { }; const designer = Designer.create(placeholder, definition, configuration); -designer.onDefinitionChanged.subscribe((event) => { +designer.onDefinitionChanged.subscribe(event => { // ... }); ``` @@ -231,7 +232,7 @@ const configuration = { controlBar: false, contextMenu: false, // ... -} +}; ``` ## 💡 License diff --git a/angular/designer/package.json b/angular/designer/package.json index 2e2a3ef..7d5cc10 100644 --- a/angular/designer/package.json +++ b/angular/designer/package.json @@ -1,7 +1,7 @@ { "name": "sequential-workflow-designer-angular", "description": "Angular wrapper for Sequential Workflow Designer component.", - "version": "0.36.0", + "version": "0.37.0", "author": { "name": "NoCode JS", "url": "https://nocode-js.com/" @@ -15,7 +15,7 @@ "peerDependencies": { "@angular/common": "12 - 20", "@angular/core": "12 - 20", - "sequential-workflow-designer": "^0.36.0" + "sequential-workflow-designer": "^0.37.0" }, "dependencies": { "tslib": "^2.3.0" diff --git a/demos/angular-app/package.json b/demos/angular-app/package.json index 7ffee87..713ffb6 100644 --- a/demos/angular-app/package.json +++ b/demos/angular-app/package.json @@ -26,8 +26,8 @@ "@angular/platform-browser-dynamic": "^17.3.9", "@angular/router": "^17.3.9", "rxjs": "~7.8.0", - "sequential-workflow-designer": "^0.36.0", - "sequential-workflow-designer-angular": "^0.36.0", + "sequential-workflow-designer": "^0.37.0", + "sequential-workflow-designer-angular": "^0.37.0", "tslib": "^2.3.0", "zone.js": "~0.14.6" }, diff --git a/demos/angular-app/yarn.lock b/demos/angular-app/yarn.lock index 3259b72..22ee73a 100644 --- a/demos/angular-app/yarn.lock +++ b/demos/angular-app/yarn.lock @@ -6744,17 +6744,17 @@ send@0.18.0: range-parser "~1.2.1" statuses "2.0.1" -sequential-workflow-designer-angular@^0.36.0: - version "0.36.0" - resolved "https://registry.yarnpkg.com/sequential-workflow-designer-angular/-/sequential-workflow-designer-angular-0.36.0.tgz#61039bded475be409e82eb720e3899e95835aabb" - integrity sha512-qVO3usmb0Ms2OeKdz+7M4sPKIya5P2JpUMtoNVdVXqE+Kr3gTXqxqFIrBX70U70MvCpGmmkvBXyf8w5VQVmzww== +sequential-workflow-designer-angular@^0.37.0: + version "0.37.0" + resolved "https://registry.yarnpkg.com/sequential-workflow-designer-angular/-/sequential-workflow-designer-angular-0.37.0.tgz#4b2719e44c7dd7c61d7f4eb0c18357eb4af07dff" + integrity sha512-OPyAZWkB7EjILICdsRlyKoqrkRepTD4NRh4m/FxEW1r6hWF0zSw5pIySiR4Q28KzHaV99dLHptX0U7/g7lK8cQ== dependencies: tslib "^2.3.0" -sequential-workflow-designer@^0.36.0: - version "0.36.0" - resolved "https://registry.yarnpkg.com/sequential-workflow-designer/-/sequential-workflow-designer-0.36.0.tgz#43e87d2e3890080dac5870342aa0ceda5ae43300" - integrity sha512-XZYkOC5+9iw0mDOR/D5IngfSyydfclMzZGrS/ZcQQOezchBGLVo8tYq34dxGphILafbU6ywb4Cj3tx1xZiZwoQ== +sequential-workflow-designer@^0.37.0: + version "0.37.0" + resolved "https://registry.yarnpkg.com/sequential-workflow-designer/-/sequential-workflow-designer-0.37.0.tgz#49229a6dd9771de56d1649796b8a2a954f2ba248" + integrity sha512-5YWGW+LNEstma95LcwsqXMC9kDhCbvjUslEnkUBZRnulHIBqlCESGjBhU9/VT1Vr4zg1906ZIAjhl84ghiuVHQ== dependencies: sequential-workflow-model "^0.2.0" diff --git a/demos/react-app/package.json b/demos/react-app/package.json index 584653b..6911e56 100644 --- a/demos/react-app/package.json +++ b/demos/react-app/package.json @@ -6,8 +6,8 @@ "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", - "sequential-workflow-designer": "^0.36.0", - "sequential-workflow-designer-react": "^0.36.0" + "sequential-workflow-designer": "^0.37.0", + "sequential-workflow-designer-react": "^0.37.0" }, "devDependencies": { "@types/jest": "^29.2.5", diff --git a/demos/svelte-app/package.json b/demos/svelte-app/package.json index 80cec7a..90ba803 100644 --- a/demos/svelte-app/package.json +++ b/demos/svelte-app/package.json @@ -16,8 +16,8 @@ "eslint": "eslint ./src --ext .ts" }, "dependencies": { - "sequential-workflow-designer": "^0.36.0", - "sequential-workflow-designer-svelte": "^0.36.0" + "sequential-workflow-designer": "^0.37.0", + "sequential-workflow-designer-svelte": "^0.37.0" }, "devDependencies": { "@sveltejs/adapter-static": "^2.0.3", diff --git a/designer/package.json b/designer/package.json index d07685c..b5aecf7 100644 --- a/designer/package.json +++ b/designer/package.json @@ -1,7 +1,7 @@ { "name": "sequential-workflow-designer", "description": "Customizable no-code component for building flow-based programming applications.", - "version": "0.36.0", + "version": "0.37.0", "type": "module", "main": "./lib/esm/index.js", "types": "./lib/index.d.ts", diff --git a/designer/src/api/editor-renderer.spec.ts b/designer/src/api/editor-renderer.spec.ts index 8a86f2e..e744f75 100644 --- a/designer/src/api/editor-renderer.spec.ts +++ b/designer/src/api/editor-renderer.spec.ts @@ -2,6 +2,7 @@ import { DesignerState } from '../designer-state'; import { EditorRenderer } from './editor-renderer'; import { Definition, DefinitionWalker, Step } from '../definition'; import { DefinitionChangeType } from '../designer-configuration'; +import { MemoryPreferenceStorage } from '../core/memory-preference-storage'; const step: Step = { componentType: 'task', @@ -23,7 +24,7 @@ describe('EditorRenderer', () => { beforeEach(() => { walker = new DefinitionWalker(); - state = new DesignerState(definition, false, false, false); + state = new DesignerState(definition, false, false, false, new MemoryPreferenceStorage()); callback = jasmine.createSpy('callback'); }); diff --git a/designer/src/behaviors/click-behavior-resolver.ts b/designer/src/behaviors/click-behavior-resolver.ts index 1282c9c..18b3a76 100644 --- a/designer/src/behaviors/click-behavior-resolver.ts +++ b/designer/src/behaviors/click-behavior-resolver.ts @@ -4,7 +4,7 @@ import { Behavior } from './behavior'; import { MoveViewportBehavior } from './move-viewport-behavior'; import { SelectStepBehavior } from './select-step-behavior'; import { PressingBehavior } from './pressing-behaviors/pressing-behavior'; -import { RerenderStepPressingBehaviorHandler } from './pressing-behaviors/rerender-step-pressing-behavior-handler'; +import { ChangePreferencesBehaviorHandler } from './pressing-behaviors/change-preferences-behavior-handler'; import { OpenFolderPressingBehaviorHandler } from './pressing-behaviors/open-folder-pressing-behavior-handler'; import { TriggerCustomActionPressingBehaviorHandler } from './pressing-behaviors/trigger-custom-action-pressing-behavior-handler'; @@ -20,8 +20,8 @@ export class ClickBehaviorResolver { case ClickCommandType.selectStep: return SelectStepBehavior.create(commandOrNull.component, forceMove, this.context); - case ClickCommandType.rerenderStep: - return PressingBehavior.create(element, new RerenderStepPressingBehaviorHandler(commandOrNull, this.context)); + case ClickCommandType.changePreferences: + return PressingBehavior.create(element, new ChangePreferencesBehaviorHandler(commandOrNull, this.context)); case ClickCommandType.openFolder: return PressingBehavior.create(element, new OpenFolderPressingBehaviorHandler(commandOrNull, this.context)); diff --git a/designer/src/behaviors/pressing-behaviors/change-preferences-behavior-handler.ts b/designer/src/behaviors/pressing-behaviors/change-preferences-behavior-handler.ts new file mode 100644 index 0000000..837db5f --- /dev/null +++ b/designer/src/behaviors/pressing-behaviors/change-preferences-behavior-handler.ts @@ -0,0 +1,14 @@ +import { DesignerContext } from '../../designer-context'; +import { SetPreferencesClickCommand } from '../../workspace'; +import { PressingBehaviorHandler } from './pressing-behavior'; + +export class ChangePreferencesBehaviorHandler implements PressingBehaviorHandler { + public constructor( + private readonly command: SetPreferencesClickCommand, + private readonly designerContext: DesignerContext + ) {} + + public handle() { + this.designerContext.state.setPreferences(this.command.changes, this.command.step.id); + } +} diff --git a/designer/src/behaviors/pressing-behaviors/rerender-step-pressing-behavior-handler.ts b/designer/src/behaviors/pressing-behaviors/rerender-step-pressing-behavior-handler.ts deleted file mode 100644 index 2f082b2..0000000 --- a/designer/src/behaviors/pressing-behaviors/rerender-step-pressing-behavior-handler.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { DesignerContext } from '../../designer-context'; -import { RerenderStepClickCommand } from '../../workspace'; -import { PressingBehaviorHandler } from './pressing-behavior'; - -export class RerenderStepPressingBehaviorHandler implements PressingBehaviorHandler { - public constructor( - private readonly command: RerenderStepClickCommand, - private readonly designerContext: DesignerContext - ) {} - - public handle() { - if (this.command.beforeCallback) { - this.command.beforeCallback(); - } - this.designerContext.workspaceController.updateRootComponent(); - } -} diff --git a/designer/src/core/definition-validator.spec.ts b/designer/src/core/definition-validator.spec.ts index eec98c1..04d2aee 100644 --- a/designer/src/core/definition-validator.spec.ts +++ b/designer/src/core/definition-validator.spec.ts @@ -3,6 +3,7 @@ import { DesignerState } from '../designer-state'; import { createStepStub } from '../test-tools/stubs'; import { createDefinitionStub } from '../test-tools/stubs'; import { DefinitionValidator } from './definition-validator'; +import { MemoryPreferenceStorage } from './memory-preference-storage'; describe('DefinitionValidator', () => { const testStep = createStepStub(); @@ -11,7 +12,7 @@ describe('DefinitionValidator', () => { let state: DesignerState; beforeEach(() => { - state = new DesignerState(testDefinition, false, false, false); + state = new DesignerState(testDefinition, false, false, false, new MemoryPreferenceStorage()); }); it('returns true if providers are not set in configuration', () => { diff --git a/designer/src/core/simple-event.spec.ts b/designer/src/core/simple-event.spec.ts index 9a25880..921610b 100644 --- a/designer/src/core/simple-event.spec.ts +++ b/designer/src/core/simple-event.spec.ts @@ -22,11 +22,11 @@ describe('SimpleEvent', () => { expect(e.count()).toEqual(0); }); - it('first() works as expected', done => { + it('once() works as expected', done => { const e = new SimpleEvent(); let lastValue: number | undefined; - e.first().then(v => (lastValue = v)); + e.once().then(v => (lastValue = v)); e.forward(1); e.forward(2); diff --git a/designer/src/core/simple-event.ts b/designer/src/core/simple-event.ts index 9d7a5b9..e20080e 100644 --- a/designer/src/core/simple-event.ts +++ b/designer/src/core/simple-event.ts @@ -24,7 +24,7 @@ export class SimpleEvent { return this.listeners.length; } - public first(): Promise { + public once(): Promise { return new Promise(resolve => { const handler = (value: T) => { this.unsubscribe(handler); diff --git a/designer/src/designer-configuration.ts b/designer/src/designer-configuration.ts index 5129a6e..a66a748 100644 --- a/designer/src/designer-configuration.ts +++ b/designer/src/designer-configuration.ts @@ -271,3 +271,13 @@ export interface DefinitionChangedEvent { diff --git a/designer/src/designer-state.ts b/designer/src/designer-state.ts index 133bb99..cd79d74 100644 --- a/designer/src/designer-state.ts +++ b/designer/src/designer-state.ts @@ -1,7 +1,13 @@ import { SimpleEvent } from './core/simple-event'; import { Vector } from './core/vector'; import { Definition } from './definition'; -import { DefinitionChangedEvent, DefinitionChangeType } from './designer-configuration'; +import { + DefinitionChangedEvent, + DefinitionChangeType, + PreferenceChange, + PreferencesChangedEvent, + PreferenceStorage +} from './designer-configuration'; import { Viewport } from './designer-extension'; export type DefinitionChangedEventDetails = Omit; @@ -17,6 +23,7 @@ export class DesignerState { public readonly onDefinitionChanged = new SimpleEvent(); public readonly onIsToolboxCollapsedChanged = new SimpleEvent(); public readonly onIsEditorCollapsedChanged = new SimpleEvent(); + public readonly onPreferencesChanged = new SimpleEvent(); public viewport: Viewport = { position: new Vector(0, 0), @@ -31,7 +38,8 @@ export class DesignerState { public definition: Definition, public isReadonly: boolean, public isToolboxCollapsed: boolean, - public isEditorCollapsed: boolean + public isEditorCollapsed: boolean, + private readonly preferenceStorage: PreferenceStorage ) {} public setSelectedStepId(stepId: string | null) { @@ -115,4 +123,15 @@ export class DesignerState { this.onIsEditorCollapsedChanged.forward(isCollapsed); } } + + public setPreferences(changes: PreferenceChange[], stepId: string) { + for (const change of changes) { + this.preferenceStorage.setItem(change.key, change.value); + } + this.onPreferencesChanged.forward({ changes, stepId }); + } + + public getPreference(key: string): string | null { + return this.preferenceStorage.getItem(key); + } } diff --git a/designer/src/designer.spec.ts b/designer/src/designer.spec.ts index 6c01c5d..fb7a20b 100644 --- a/designer/src/designer.spec.ts +++ b/designer/src/designer.spec.ts @@ -10,7 +10,7 @@ import { Workspace } from './workspace/workspace'; describe('Designer', () => { it('create() creates designer', () => { const workspaceSpy = spyOn(Workspace, 'create').and.returnValues({ - onRendered: new SimpleEvent() + onRootComponentUpdated: new SimpleEvent() } as Workspace); const toolboxSpy = spyOn(Toolbox, 'create'); const controlBarSpy = spyOn(ControlBar, 'create'); diff --git a/designer/src/designer.ts b/designer/src/designer.ts index cf769b0..0532ce7 100644 --- a/designer/src/designer.ts +++ b/designer/src/designer.ts @@ -1,7 +1,7 @@ import { SimpleEvent } from './core/simple-event'; import { isElementAttached } from './core/is-element-attached'; import { Definition, DefinitionWalker, Sequence, Step, StepOrName } from './definition'; -import { DefinitionChangedEvent, DesignerConfiguration, UndoStack } from './designer-configuration'; +import { DefinitionChangedEvent, DesignerConfiguration, PreferencesChangedEvent, UndoStack } from './designer-configuration'; import { DesignerContext } from './designer-context'; import { DesignerView } from './designer-view'; import { DesignerState } from './designer-state'; @@ -51,7 +51,8 @@ export class Designer { designerContext.historyController, designerApi ); - view.workspace.onRendered.first().then(designer.onReady.forward); + view.workspace.onRootComponentUpdated.subscribe(designer.onRootComponentUpdated.forward); + view.workspace.onRootComponentUpdated.once().then(designer.onReady.forward); race(0, designerContext.state.onDefinitionChanged, designerContext.state.onSelectedStepIdChanged).subscribe( ([definition, selectedStepId]) => { @@ -68,6 +69,7 @@ export class Designer { designerContext.state.onIsToolboxCollapsedChanged.subscribe(designer.onIsToolboxCollapsedChanged.forward); designerContext.state.onIsEditorCollapsedChanged.subscribe(designer.onIsEditorCollapsedChanged.forward); designerContext.state.onStepUnselectionBlocked.subscribe(designer.onStepUnselectionBlocked.forward); + designerContext.state.onPreferencesChanged.subscribe(designer.onPreferencesChanged.forward); return designer; } @@ -114,6 +116,16 @@ export class Designer { */ public readonly onIsEditorCollapsedChanged = new SimpleEvent(); + /** + * @description Fires when the root component and all its children are rerendered. + */ + public readonly onRootComponentUpdated = new SimpleEvent(); + + /** + * @description Fires when any of the designer preferences has changed. + */ + public readonly onPreferencesChanged = new SimpleEvent(); + /** * @returns the current definition of the workflow. */ @@ -257,8 +269,8 @@ export class Designer { this.getHistoryController().replaceDefinition(definition); await Promise.all([ - this.view.workspace.onRendered.first(), // This should be fired first - this.onDefinitionChanged.first() + this.view.workspace.onRootComponentUpdated.once(), // This should be fired first + this.onDefinitionChanged.once() ]); } diff --git a/designer/src/modifier/folder-path-definition-modifier-dependency.spec.ts b/designer/src/modifier/folder-path-definition-modifier-dependency.spec.ts index ad1110c..1c08953 100644 --- a/designer/src/modifier/folder-path-definition-modifier-dependency.spec.ts +++ b/designer/src/modifier/folder-path-definition-modifier-dependency.spec.ts @@ -1,3 +1,4 @@ +import { MemoryPreferenceStorage } from '../core/memory-preference-storage'; import { Definition, DefinitionWalker, Sequence, SequentialStep } from '../definition'; import { DesignerState } from '../designer-state'; import { FolderPathDefinitionModifierDependency } from './folder-path-definition-modifier-dependency'; @@ -24,7 +25,7 @@ describe('FolderPathDefinitionModifierDependency', () => { properties: {}, sequence: [createFolderStep('0x1', [createFolderStep('0x2', [createFolderStep('0x3', [])])])] }; - state = new DesignerState(definition, false, true, true); + state = new DesignerState(definition, false, true, true, new MemoryPreferenceStorage()); state.setFolderPath(['0x1', '0x2', '0x3']); dependency = new FolderPathDefinitionModifierDependency(state, walker); }); diff --git a/designer/src/modifier/selected-step-id-definition-modifier-dependency.spec.ts b/designer/src/modifier/selected-step-id-definition-modifier-dependency.spec.ts index a7b32e0..a4eea61 100644 --- a/designer/src/modifier/selected-step-id-definition-modifier-dependency.spec.ts +++ b/designer/src/modifier/selected-step-id-definition-modifier-dependency.spec.ts @@ -1,3 +1,4 @@ +import { MemoryPreferenceStorage } from '../core/memory-preference-storage'; import { Definition, DefinitionWalker } from '../definition'; import { DesignerState } from '../designer-state'; import { SelectedStepIdDefinitionModifierDependency } from './selected-step-id-definition-modifier-dependency'; @@ -16,7 +17,7 @@ describe('SelectedStepIdDefinitionModifierDependency', () => { } ] }; - const state = new DesignerState(definition, false, true, true); + const state = new DesignerState(definition, false, true, true, new MemoryPreferenceStorage()); const dependency = new SelectedStepIdDefinitionModifierDependency(state, walker); it('should unselect step when it is deleted', () => { diff --git a/designer/src/smart-editor/editor.spec.ts b/designer/src/smart-editor/editor.spec.ts index cff8519..d01847f 100644 --- a/designer/src/smart-editor/editor.spec.ts +++ b/designer/src/smart-editor/editor.spec.ts @@ -5,6 +5,7 @@ import { createDefinitionStub, createDesignerConfigurationStub, createStepStub } import { StateModifier } from '../modifier/state-modifier'; import { Editor } from './editor'; import { Uid } from '../core'; +import { MemoryPreferenceStorage } from '../core/memory-preference-storage'; describe('Editor', () => { const step = createStepStub(); @@ -25,7 +26,7 @@ describe('Editor', () => { parent = document.createElement('div'); const configuration = createDesignerConfigurationStub(); - state = new DesignerState(definition, false, false, false); + state = new DesignerState(definition, false, false, false, new MemoryPreferenceStorage()); const walker = new DefinitionWalker(); const modifier = StateModifier.create(walker, Uid.next, state, configuration.steps); diff --git a/designer/src/workspace/component.ts b/designer/src/workspace/component.ts index 18949f8..fc0edb8 100644 --- a/designer/src/workspace/component.ts +++ b/designer/src/workspace/component.ts @@ -1,6 +1,6 @@ import { Vector } from '../core/vector'; import { Sequence, Step } from '../definition'; -import { CustomAction } from '../designer-configuration'; +import { CustomAction, PreferenceChange } from '../designer-configuration'; import { StepComponent } from './step-component'; export interface Component { @@ -54,7 +54,7 @@ export interface ClickDetails { scale: number; } -export type ClickCommand = SelectStepClickCommand | RerenderStepClickCommand | OpenFolderClickCommand | TriggerCustomActionClickCommand; +export type ClickCommand = SelectStepClickCommand | SetPreferencesClickCommand | OpenFolderClickCommand | TriggerCustomActionClickCommand; export interface BaseClickCommand { type: ClickCommandType; @@ -65,10 +65,10 @@ export interface SelectStepClickCommand extends BaseClickCommand { component: StepComponent; } -export interface RerenderStepClickCommand extends BaseClickCommand { - type: ClickCommandType.rerenderStep; +export interface SetPreferencesClickCommand extends BaseClickCommand { + type: ClickCommandType.changePreferences; step: Step; - beforeCallback?: () => void; + changes: PreferenceChange[]; } export interface OpenFolderClickCommand extends BaseClickCommand { @@ -85,7 +85,7 @@ export interface TriggerCustomActionClickCommand extends BaseClickCommand { export enum ClickCommandType { selectStep = 1, - rerenderStep = 2, + changePreferences = 2, openFolder = 3, triggerCustomAction = 4 } diff --git a/designer/src/workspace/step-component-view-context-factory.ts b/designer/src/workspace/step-component-view-context-factory.ts index c6b858e..93a7ec6 100644 --- a/designer/src/workspace/step-component-view-context-factory.ts +++ b/designer/src/workspace/step-component-view-context-factory.ts @@ -52,7 +52,12 @@ export class StepComponentViewContextFactory { createPlaceholderForGap: componentContext.services.placeholder.createForGap.bind(componentContext.services.placeholder), createPlaceholderForArea: componentContext.services.placeholder.createForArea.bind(componentContext.services.placeholder), getPreference: (key: string) => componentContext.preferenceStorage.getItem(preferenceKeyPrefix + key), - setPreference: (key: string, value: string) => componentContext.preferenceStorage.setItem(preferenceKeyPrefix + key, value) + createPreferenceChange: (key: string, value: string) => { + return { + key: preferenceKeyPrefix + key, + value + }; + } }; } } diff --git a/designer/src/workspace/workspace.ts b/designer/src/workspace/workspace.ts index 4d22e9d..5c2b006 100644 --- a/designer/src/workspace/workspace.ts +++ b/designer/src/workspace/workspace.ts @@ -63,6 +63,7 @@ export class Workspace implements WorkspaceController { designerContext.setWorkspaceController(workspace); designerContext.state.onViewportChanged.subscribe(workspace.onViewportChanged); + designerContext.state.onPreferencesChanged.subscribe(workspace.onPreferencesChanged); race( 0, @@ -82,7 +83,7 @@ export class Workspace implements WorkspaceController { return workspace; } - public readonly onRendered = new SimpleEvent(); + public readonly onRootComponentUpdated = new SimpleEvent(); public isValid = false; private initTimeout: ReturnType | null = null; @@ -111,7 +112,7 @@ export class Workspace implements WorkspaceController { }); } - public updateRootComponent() { + public updateRootComponent = () => { this.selectedStepComponent = null; const rootSequence = this.workspaceApi.getRootSequence(); @@ -126,8 +127,8 @@ export class Workspace implements WorkspaceController { this.trySelectStepComponent(this.state.selectedStepId); this.updateBadges(); - this.onRendered.forward(); - } + this.onRootComponentUpdated.forward(); + }; public updateBadges() { const result = BadgesResultFactory.create(this.services); @@ -216,6 +217,10 @@ export class Workspace implements WorkspaceController { this.view.setPositionAndScale(viewport.position, viewport.scale); }; + private readonly onPreferencesChanged = () => { + this.updateRootComponent(); + }; + private onStateChanged( definitionChanged: DefinitionChangedEvent | undefined, selectedStepIdChanged: string | null | undefined, diff --git a/examples/assets/lib.js b/examples/assets/lib.js index e4aae3e..beeafd1 100644 --- a/examples/assets/lib.js +++ b/examples/assets/lib.js @@ -13,7 +13,7 @@ function embedStylesheet(url) { document.write(``); } -const baseUrl = isTestEnv() ? '../designer' : '//cdn.jsdelivr.net/npm/sequential-workflow-designer@0.36.0'; +const baseUrl = isTestEnv() ? '../designer' : '//cdn.jsdelivr.net/npm/sequential-workflow-designer@0.37.0'; embedScript(`${baseUrl}/dist/index.umd.js`); embedStylesheet(`${baseUrl}/css/designer.css`); diff --git a/react/package.json b/react/package.json index 912039b..c35d8ac 100644 --- a/react/package.json +++ b/react/package.json @@ -1,7 +1,7 @@ { "name": "sequential-workflow-designer-react", "description": "React wrapper for Sequential Workflow Designer component.", - "version": "0.36.0", + "version": "0.37.0", "type": "module", "main": "./lib/esm/index.js", "types": "./lib/index.d.ts", @@ -47,7 +47,7 @@ "peerDependencies": { "react": ">=18.2.0", "react-dom": ">=18.2.0", - "sequential-workflow-designer": "^0.36.0" + "sequential-workflow-designer": "^0.37.0" }, "devDependencies": { "@rollup/plugin-node-resolve": "^16.0.1", @@ -63,7 +63,7 @@ "prettier": "^3.2.5", "react": "^18.2.0", "react-dom": "^18.2.0", - "sequential-workflow-designer": "^0.36.0", + "sequential-workflow-designer": "^0.37.0", "rollup": "^4.40.0", "rollup-plugin-dts": "^6.2.1", "rollup-plugin-typescript2": "^0.36.0", diff --git a/svelte/package.json b/svelte/package.json index 5bc39f1..d3e2c6a 100644 --- a/svelte/package.json +++ b/svelte/package.json @@ -1,7 +1,7 @@ { "name": "sequential-workflow-designer-svelte", "description": "Svelte wrapper for Sequential Workflow Designer component.", - "version": "0.36.0", + "version": "0.37.0", "license": "MIT", "scripts": { "prepare": "cp ../LICENSE LICENSE", @@ -28,10 +28,10 @@ ], "peerDependencies": { "svelte": "^4.0.0", - "sequential-workflow-designer": "^0.36.0" + "sequential-workflow-designer": "^0.37.0" }, "devDependencies": { - "sequential-workflow-designer": "^0.36.0", + "sequential-workflow-designer": "^0.37.0", "@sveltejs/adapter-static": "^2.0.3", "@sveltejs/kit": "^1.20.4", "@sveltejs/package": "^2.0.0",