@bemedev/mind-flow 0.3.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -12
- package/lib/helpers/clamp.d.ts +2 -0
- package/lib/helpers/clamp.d.ts.map +1 -0
- package/lib/helpers/createContext.d.ts +1 -1
- package/lib/helpers/createContext.d.ts.map +1 -1
- package/lib/helpers/index.d.ts +3 -0
- package/lib/helpers/index.d.ts.map +1 -0
- package/lib/index.cjs.js +1 -1
- package/lib/index.d.ts +9 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.es.js +2543 -448
- package/lib/output.css +1 -1
- package/lib/server.cjs.js +1129 -397
- package/lib/server.es.js +1095 -407
- package/lib/services/main.machine.d.ts +2453 -576
- package/lib/services/main.machine.d.ts.map +1 -1
- package/lib/services/main.machine.data.d.ts +14 -1
- package/lib/services/main.machine.data.d.ts.map +1 -1
- package/lib/services/main.machine.helpers.d.ts +1 -1
- package/lib/services/main.machine.helpers.d.ts.map +1 -1
- package/lib/services/main.machine.test.d.ts +2 -0
- package/lib/services/main.machine.test.d.ts.map +1 -0
- package/lib/services/main.machine.typings.d.ts +26 -8
- package/lib/services/main.machine.typings.d.ts.map +1 -1
- package/lib/ui/Flow.d.ts +8 -4
- package/lib/ui/Flow.d.ts.map +1 -1
- package/lib/ui/components/Bounds.d.ts.map +1 -1
- package/lib/ui/components/EdgeComponent.d.ts.map +1 -1
- package/lib/ui/components/EdgesBoard.d.ts.map +1 -1
- package/lib/ui/components/EditPanel.d.ts +19 -0
- package/lib/ui/components/EditPanel.d.ts.map +1 -0
- package/lib/ui/components/EditPanel.hooks.d.ts +29 -0
- package/lib/ui/components/EditPanel.hooks.d.ts.map +1 -0
- package/lib/ui/components/EditPanel.types.d.ts +47 -0
- package/lib/ui/components/EditPanel.types.d.ts.map +1 -0
- package/lib/ui/components/FlowChart.context.d.ts +2452 -575
- package/lib/ui/components/FlowChart.context.d.ts.map +1 -1
- package/lib/ui/components/FlowChart.d.ts +8 -47
- package/lib/ui/components/FlowChart.d.ts.map +1 -1
- package/lib/ui/components/FlowChart.types.d.ts +87 -0
- package/lib/ui/components/FlowChart.types.d.ts.map +1 -0
- package/lib/ui/components/NodeComponent.d.ts +10 -12
- package/lib/ui/components/NodeComponent.d.ts.map +1 -1
- package/lib/ui/components/NodesBoard.d.ts +17 -2
- package/lib/ui/components/NodesBoard.d.ts.map +1 -1
- package/lib/ui/components/Panels.d.ts +12 -0
- package/lib/ui/components/Panels.d.ts.map +1 -0
- package/lib/ui/globals/components/atoms/TypingText.d.ts +29 -0
- package/lib/ui/globals/components/atoms/TypingText.d.ts.map +1 -0
- package/lib/ui/globals/components/molecules/FadingDots.d.ts +21 -0
- package/lib/ui/globals/components/molecules/FadingDots.d.ts.map +1 -0
- package/lib/ui/globals/components/organisms/LoadingFallback.d.ts +46 -0
- package/lib/ui/globals/components/organisms/LoadingFallback.d.ts.map +1 -0
- package/lib/ui/globals/constants/index.d.ts +3 -0
- package/lib/ui/globals/constants/index.d.ts.map +1 -0
- package/lib/ui/globals/constants/links.d.ts +4 -0
- package/lib/ui/globals/constants/links.d.ts.map +1 -0
- package/lib/ui/globals/constants/strings.d.ts +5 -0
- package/lib/ui/globals/constants/strings.d.ts.map +1 -0
- package/lib/ui/globals/directives/clickOutside.d.ts +9 -0
- package/lib/ui/globals/directives/clickOutside.d.ts.map +1 -0
- package/lib/ui/globals/directives/index.d.ts +16 -0
- package/lib/ui/globals/directives/index.d.ts.map +1 -0
- package/lib/ui/globals/directives/mouseOut.d.ts +33 -0
- package/lib/ui/globals/directives/mouseOut.d.ts.map +1 -0
- package/lib/ui/globals/directives/mouseOut.test.d.ts +2 -0
- package/lib/ui/globals/directives/mouseOut.test.d.ts.map +1 -0
- package/lib/ui/globals/directives/resize.d.ts +11 -0
- package/lib/ui/globals/directives/resize.d.ts.map +1 -0
- package/lib/ui/globals/helpers/espace.d.ts +17 -0
- package/lib/ui/globals/helpers/espace.d.ts.map +1 -0
- package/lib/ui/globals/signals/createTyping.d.ts +27 -0
- package/lib/ui/globals/signals/createTyping.d.ts.map +1 -0
- package/lib/ui/globals/types.d.ts +54 -0
- package/lib/ui/globals/types.d.ts.map +1 -0
- package/lib/ui/utils.d.ts +11 -0
- package/lib/ui/utils.d.ts.map +1 -0
- package/package.json +2 -3
- package/src/helpers/clamp.ts +3 -0
- package/src/helpers/createContext.ts +20 -4
- package/src/helpers/index.ts +2 -0
- package/src/index.ts +9 -1
- package/src/services/main.machine.data.ts +13 -2
- package/src/services/main.machine.helpers.ts +12 -4
- package/src/services/main.machine.test.ts +205 -0
- package/src/services/main.machine.ts +253 -75
- package/src/services/main.machine.typings.ts +31 -6
- package/src/ui/Flow.tsx +47 -8
- package/src/ui/components/Bounds.tsx +0 -2
- package/src/ui/components/EdgeComponent.tsx +60 -46
- package/src/ui/components/EdgesBoard.tsx +1 -2
- package/src/ui/components/EditPanel.hooks.ts +69 -0
- package/src/ui/components/EditPanel.tsx +89 -0
- package/src/ui/components/EditPanel.types.ts +49 -0
- package/src/ui/components/FlowChart.context.ts +22 -141
- package/src/ui/components/FlowChart.tsx +27 -64
- package/src/ui/components/FlowChart.types.ts +92 -0
- package/src/ui/components/NodeComponent.tsx +88 -65
- package/src/ui/components/NodesBoard.tsx +61 -56
- package/src/ui/components/Panels.tsx +40 -0
- package/src/ui/globals/components/atoms/TypingText.tsx +63 -0
- package/src/ui/globals/components/molecules/FadingDots.tsx +45 -0
- package/src/ui/globals/components/organisms/LoadingFallback.tsx +116 -0
- package/src/ui/globals/constants/index.ts +2 -0
- package/src/ui/globals/constants/links.ts +15 -0
- package/src/ui/globals/constants/strings.ts +5 -0
- package/src/ui/globals/directives/clickOutside.ts +18 -0
- package/src/ui/globals/directives/index.ts +16 -0
- package/src/ui/globals/directives/mouseOut.test.ts +115 -0
- package/src/ui/globals/directives/mouseOut.ts +98 -0
- package/src/ui/globals/directives/resize.ts +33 -0
- package/src/ui/globals/helpers/espace.ts +26 -0
- package/src/ui/globals/signals/createTyping.ts +82 -0
- package/src/ui/globals/types.ts +83 -0
- package/src/ui/utils.ts +14 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Component, ComponentProps, JSX, ValidComponent } from 'solid-js';
|
|
2
|
+
/**
|
|
3
|
+
* Extracts a subset of component props from a valid component.
|
|
4
|
+
*
|
|
5
|
+
* @template | {@linkcode ValidComponent} `T` - Target component type.
|
|
6
|
+
* @template | `keyof ComponentProps<T>` `K` - Prop keys to pick.
|
|
7
|
+
*/
|
|
8
|
+
export type PropsOf<T extends ValidComponent, K extends keyof ComponentProps<T> = never> = Pick<ComponentProps<T>, K>;
|
|
9
|
+
/**
|
|
10
|
+
* Omits a subset of component props from a valid component.
|
|
11
|
+
*
|
|
12
|
+
* @template | {@linkcode ValidComponent} `T` - Target component type.
|
|
13
|
+
* @template | `keyof ComponentProps<T>` `K` - Prop keys to omit.
|
|
14
|
+
*/
|
|
15
|
+
export type OmitPropsOf<T extends ValidComponent, K extends keyof ComponentProps<T> = never> = Omit<ComponentProps<T>, K>;
|
|
16
|
+
/**
|
|
17
|
+
* Creates a component type where specified props are optional.
|
|
18
|
+
*
|
|
19
|
+
* @template | {@linkcode ValidComponent} `T` - Target component type.
|
|
20
|
+
* @template | `keyof ComponentProps<T>` `K` - Prop keys to make optional.
|
|
21
|
+
*/
|
|
22
|
+
export type ReduceComponent<T extends ValidComponent, K extends keyof ComponentProps<T> = never> = Component<OmitPropsOf<T, K> & Partial<PropsOf<T, K>>>;
|
|
23
|
+
/**
|
|
24
|
+
* Short alias for type {@linkcode ReduceComponent}.
|
|
25
|
+
*
|
|
26
|
+
* @template | {@linkcode ValidComponent} `T` - Target component type.
|
|
27
|
+
* @template | `keyof ComponentProps<T>` `K` - Prop keys to make optional.
|
|
28
|
+
*/
|
|
29
|
+
export type RC<T extends ValidComponent, K extends keyof ComponentProps<T> = never> = ReduceComponent<T, K>;
|
|
30
|
+
/**
|
|
31
|
+
* Creates a component type requiring only a picked subset of props.
|
|
32
|
+
*
|
|
33
|
+
* @template | {@linkcode ValidComponent} `T` - Target component type.
|
|
34
|
+
* @template | `keyof ComponentProps<T>` `K` - Picked prop keys.
|
|
35
|
+
*/
|
|
36
|
+
export type PickComponent<T extends ValidComponent, K extends keyof ComponentProps<T> = never> = Component<PropsOf<T, K>>;
|
|
37
|
+
/**
|
|
38
|
+
* Short alias for type {@linkcode PickComponent}.
|
|
39
|
+
*
|
|
40
|
+
* @template | {@linkcode ValidComponent} `T` - Target component type.
|
|
41
|
+
* @template | `keyof ComponentProps<T>` `K` - Picked prop keys.
|
|
42
|
+
*/
|
|
43
|
+
export type PiC<T extends ValidComponent, K extends keyof ComponentProps<T> = never> = PickComponent<T, K>;
|
|
44
|
+
/** Type representing an HTML `<link>` tag properties. */
|
|
45
|
+
export type RootLink = JSX.HTMLElementTags['link'];
|
|
46
|
+
/**
|
|
47
|
+
* Type representing an HTML element ref or ref callback.
|
|
48
|
+
*
|
|
49
|
+
* @template | {@linkcode HTMLElement} `T` - Target HTML element type.
|
|
50
|
+
*/
|
|
51
|
+
export type Ref<T extends HTMLElement> = T | ((el: T | undefined) => void) | undefined;
|
|
52
|
+
/** Class map dictionary for conditional styling in Solid.js components. */
|
|
53
|
+
export type ClassList = Record<string, boolean | undefined>;
|
|
54
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/ui/globals/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,MAAM,OAAO,CACjB,CAAC,SAAS,cAAc,EACxB,CAAC,SAAS,MAAM,cAAc,CAAC,CAAC,CAAC,GAAG,KAAK,IACvC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,MAAM,WAAW,CACrB,CAAC,SAAS,cAAc,EACxB,CAAC,SAAS,MAAM,cAAc,CAAC,CAAC,CAAC,GAAG,KAAK,IACvC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,MAAM,eAAe,CACzB,CAAC,SAAS,cAAc,EACxB,CAAC,SAAS,MAAM,cAAc,CAAC,CAAC,CAAC,GAAG,KAAK,IACvC,SAAS,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1D;;;;;GAKG;AACH,MAAM,MAAM,EAAE,CACZ,CAAC,SAAS,cAAc,EACxB,CAAC,SAAS,MAAM,cAAc,CAAC,CAAC,CAAC,GAAG,KAAK,IACvC,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE1B;;;;;GAKG;AACH,MAAM,MAAM,aAAa,CACvB,CAAC,SAAS,cAAc,EACxB,CAAC,SAAS,MAAM,cAAc,CAAC,CAAC,CAAC,GAAG,KAAK,IACvC,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAE7B;;;;;GAKG;AACH,MAAM,MAAM,GAAG,CACb,CAAC,SAAS,cAAc,EACxB,CAAC,SAAS,MAAM,cAAc,CAAC,CAAC,CAAC,GAAG,KAAK,IACvC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAExB,yDAAyD;AACzD,MAAM,MAAM,QAAQ,GAAG,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;AAEnD;;;;GAIG;AACH,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,WAAW,IACjC,CAAC,GACD,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,SAAS,KAAK,IAAI,CAAC,GAC7B,SAAS,CAAC;AAEd,2EAA2E;AAC3E,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ClassValue } from 'clsx';
|
|
2
|
+
/**
|
|
3
|
+
* Merges conditional CSS class names using `clsx` and resolves Tailwind CSS class
|
|
4
|
+
* conflicts with `twMerge`.
|
|
5
|
+
*
|
|
6
|
+
* @param inputs - Variable list of class values, objects, or arrays.
|
|
7
|
+
*
|
|
8
|
+
* @returns The resolved single class name string.
|
|
9
|
+
*/
|
|
10
|
+
export declare function cn(...inputs: ClassValue[]): string;
|
|
11
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/ui/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAG7C;;;;;;;GAOG;AACH,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bemedev/mind-flow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Flow Chart UI library for Solid.js applications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"diagram",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"@size-limit/file": "^13.0.3",
|
|
72
72
|
"@tailwindcss/cli": "^4.3.3",
|
|
73
73
|
"@tailwindcss/vite": "^4.3.3",
|
|
74
|
-
"@types/node": "^26.
|
|
74
|
+
"@types/node": "^26.3.0",
|
|
75
75
|
"@vitest/coverage-v8": "^4.1.11",
|
|
76
76
|
"glob": "^13.0.6",
|
|
77
77
|
"globals": "^17.11.0",
|
|
@@ -82,7 +82,6 @@
|
|
|
82
82
|
"pretty-quick": "^4.2.2",
|
|
83
83
|
"rimraf": "^6.1.3",
|
|
84
84
|
"rolldown": "^1.2.5",
|
|
85
|
-
"rollup": "^4.62.5",
|
|
86
85
|
"rollup-preset-solid": "^3.0.0",
|
|
87
86
|
"size-limit": "^13.0.3",
|
|
88
87
|
"solid-js": "^1.9.15",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
createComponent,
|
|
2
3
|
createContext as createSolidContext,
|
|
3
4
|
useContext,
|
|
4
5
|
type ParentComponent,
|
|
@@ -28,12 +29,27 @@ export const createContext = <const T>(
|
|
|
28
29
|
context: () => NonNullable<T>,
|
|
29
30
|
options?: Options,
|
|
30
31
|
) => {
|
|
31
|
-
const _context = createSolidContext(
|
|
32
|
+
const _context = createSolidContext<NonNullable<T> | undefined>(
|
|
33
|
+
undefined,
|
|
34
|
+
options,
|
|
35
|
+
);
|
|
32
36
|
|
|
33
|
-
const Provider: ParentComponent =
|
|
34
|
-
_context.Provider
|
|
37
|
+
const Provider: ParentComponent = props => {
|
|
38
|
+
return createComponent(_context.Provider, {
|
|
39
|
+
value: context(),
|
|
40
|
+
get children() {
|
|
41
|
+
return props.children;
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
};
|
|
35
45
|
|
|
36
|
-
const _useContext = () =>
|
|
46
|
+
const _useContext = () => {
|
|
47
|
+
const __context = useContext(_context);
|
|
48
|
+
if (!__context) {
|
|
49
|
+
throw new Error('useContext must be used within a Provider');
|
|
50
|
+
}
|
|
51
|
+
return __context as NonNullable<T>;
|
|
52
|
+
};
|
|
37
53
|
|
|
38
54
|
return [Provider, _useContext, _context] as const;
|
|
39
55
|
};
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from './services/main.machine.data';
|
|
2
|
+
export * from './services/main.machine.typings';
|
|
2
3
|
export * from './ui/components/classes';
|
|
4
|
+
export * from './ui/components/FlowChart';
|
|
5
|
+
export type * from './ui/components/FlowChart.types';
|
|
6
|
+
export * from './ui/components/FlowChart.context';
|
|
3
7
|
export * from './ui/Flow';
|
|
8
|
+
export * from './ui/components/EditPanel';
|
|
9
|
+
export * from './ui/components/Panels';
|
|
10
|
+
export * from './ui/globals/directives';
|
|
11
|
+
export * from './helpers';
|
|
@@ -1,9 +1,21 @@
|
|
|
1
|
-
import type { NodeProps } from '
|
|
1
|
+
import type { NodeProps } from './main.machine.typings';
|
|
2
2
|
|
|
3
3
|
/** Horizontal gap in pixels between a parent node and newly created child node. */
|
|
4
4
|
export const PARENT_CHILD_GAP_WIDTH = 100;
|
|
5
5
|
|
|
6
6
|
// #region Node & Handle Layout Constants & Formulas
|
|
7
|
+
/** Default width and height dimensions for newly created flowchart nodes. */
|
|
8
|
+
export const DEFAULT_SIZE = { width: 192, height: 50 } as const;
|
|
9
|
+
|
|
10
|
+
/** Default node width in pixels. */
|
|
11
|
+
export const DEFAULT_NODE_WIDTH = DEFAULT_SIZE.width;
|
|
12
|
+
|
|
13
|
+
/** Default node height in pixels. */
|
|
14
|
+
export const DEFAULT_NODE_HEIGHT = DEFAULT_SIZE.height;
|
|
15
|
+
|
|
16
|
+
/** Default node data payload applied when creating new nodes. */
|
|
17
|
+
export const DEFAULT_DATA = { content: '<Nouveau nœud>' };
|
|
18
|
+
|
|
7
19
|
/** Border width in pixels for a node container. */
|
|
8
20
|
export const NODE_BORDER_WIDTH = 1.5;
|
|
9
21
|
|
|
@@ -82,7 +94,6 @@ export const DEFAULT_NODES: (NodeProps & { id: string })[] = [
|
|
|
82
94
|
{
|
|
83
95
|
id: 'node-0',
|
|
84
96
|
data: { content: 'Some text', label: 'Root node' },
|
|
85
|
-
input: false,
|
|
86
97
|
position: { x: 350, y: 100 },
|
|
87
98
|
},
|
|
88
99
|
];
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_INPUT_OFFSET,
|
|
3
|
+
DEFAULT_SIZE,
|
|
4
|
+
getDefaultOutputOffset,
|
|
5
|
+
} from './main.machine.data';
|
|
2
6
|
import type { Dimension, Point } from './main.machine.typings';
|
|
3
7
|
|
|
4
8
|
/**
|
|
@@ -34,19 +38,23 @@ export const buildNodeID = (generated?: string | null) => {
|
|
|
34
38
|
*
|
|
35
39
|
* @returns Node layout dimension object of type {@linkcode Dimension}.
|
|
36
40
|
*
|
|
37
|
-
* @see {@linkcode getDefaultOutputOffset}, {@linkcode DEFAULT_INPUT_OFFSET}
|
|
41
|
+
* @see {@linkcode getDefaultOutputOffset}, {@linkcode DEFAULT_INPUT_OFFSET}, {@linkcode DEFAULT_SIZE}
|
|
38
42
|
*/
|
|
39
43
|
export const calculateDimensions = (
|
|
40
44
|
position: Point,
|
|
41
45
|
parentDimension: Pick<
|
|
42
46
|
Dimension,
|
|
43
47
|
'width' | 'height' | 'outputOffset' | 'inputOffset'
|
|
44
|
-
> = {
|
|
48
|
+
> = {
|
|
49
|
+
width: DEFAULT_SIZE.width,
|
|
50
|
+
height: DEFAULT_SIZE.height,
|
|
51
|
+
inputOffset: DEFAULT_INPUT_OFFSET,
|
|
52
|
+
},
|
|
45
53
|
): Dimension => {
|
|
46
54
|
const width = parentDimension.width;
|
|
47
55
|
const height = parentDimension.height;
|
|
48
56
|
const outputOffset = parentDimension.outputOffset ?? getDefaultOutputOffset(width);
|
|
49
|
-
const inputOffset = parentDimension.inputOffset
|
|
57
|
+
const inputOffset = parentDimension.inputOffset ?? DEFAULT_INPUT_OFFSET;
|
|
50
58
|
|
|
51
59
|
const output = { x: position.x + outputOffset.x, y: position.y + outputOffset.y };
|
|
52
60
|
const input = { x: position.x + inputOffset.x, y: position.y + inputOffset.y };
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { interpret } from '@bemedev/app';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { machine } from './main.machine';
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_DATA,
|
|
7
|
+
DEFAULT_INPUT_OFFSET,
|
|
8
|
+
DEFAULT_NODES,
|
|
9
|
+
DEFAULT_SIZE,
|
|
10
|
+
getDefaultOutputOffset,
|
|
11
|
+
} from './main.machine.data';
|
|
12
|
+
|
|
13
|
+
const createTestService = () => {
|
|
14
|
+
const service = interpret(machine, {
|
|
15
|
+
context: { zoom: 1, edgesPositions: {}, bounds: { x: 0, y: 0 } },
|
|
16
|
+
pContext: {
|
|
17
|
+
generatedId: null,
|
|
18
|
+
dimensions: {},
|
|
19
|
+
getBoardPosition: (clientX, clientY) => ({ x: clientX, y: clientY }),
|
|
20
|
+
clampPosition: (_board, x, y) => ({ x, y }),
|
|
21
|
+
calculateDimensions: (
|
|
22
|
+
position,
|
|
23
|
+
parentDimension = {
|
|
24
|
+
width: DEFAULT_SIZE.width,
|
|
25
|
+
height: DEFAULT_SIZE.height,
|
|
26
|
+
inputOffset: DEFAULT_INPUT_OFFSET,
|
|
27
|
+
},
|
|
28
|
+
) => {
|
|
29
|
+
const width = parentDimension.width;
|
|
30
|
+
const height = parentDimension.height;
|
|
31
|
+
const outputOffset =
|
|
32
|
+
parentDimension.outputOffset ?? getDefaultOutputOffset(width);
|
|
33
|
+
const inputOffset = parentDimension.inputOffset ?? DEFAULT_INPUT_OFFSET;
|
|
34
|
+
return {
|
|
35
|
+
width,
|
|
36
|
+
height,
|
|
37
|
+
output: { x: position.x + outputOffset.x, y: position.y + outputOffset.y },
|
|
38
|
+
input: { x: position.x + inputOffset.x, y: position.y + inputOffset.y },
|
|
39
|
+
outputOffset,
|
|
40
|
+
inputOffset,
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
service.start();
|
|
47
|
+
return service;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
describe('#01 => Flow State Machine', () => {
|
|
51
|
+
describe('#01 => Initialization & Configuration', () => {
|
|
52
|
+
it('#01 => should initialize in idle state and transition to working on CONFIGURE', () => {
|
|
53
|
+
const service = createTestService();
|
|
54
|
+
expect(service.state.value).toBe('idle');
|
|
55
|
+
|
|
56
|
+
service.send({
|
|
57
|
+
type: 'CONFIGURE',
|
|
58
|
+
payload: {
|
|
59
|
+
nodes: DEFAULT_NODES,
|
|
60
|
+
edges: [],
|
|
61
|
+
defaultData: {
|
|
62
|
+
title: 'Default Title',
|
|
63
|
+
priority: 1,
|
|
64
|
+
content: 'Default Content',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(service.state.value).toBe('working');
|
|
70
|
+
expect(service.state.context.data?.nodes).toHaveLength(1);
|
|
71
|
+
expect(service.state.context.data?.nodes[0].data).toEqual(
|
|
72
|
+
DEFAULT_NODES[0].data,
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('#02 => SET_NODE_DATA event', () => {
|
|
78
|
+
it('#01 => should update node data for an existing node', () => {
|
|
79
|
+
const service = createTestService();
|
|
80
|
+
service.send({
|
|
81
|
+
type: 'CONFIGURE',
|
|
82
|
+
payload: { nodes: DEFAULT_NODES, edges: [] },
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
service.send({
|
|
86
|
+
type: 'SET_NODE_DATA',
|
|
87
|
+
payload: {
|
|
88
|
+
id: 'node-0',
|
|
89
|
+
data: {
|
|
90
|
+
title: 'Updated Title',
|
|
91
|
+
priority: 4,
|
|
92
|
+
content: 'Updated Content Description',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const updatedNode = service.state.context.data?.nodes.find(
|
|
98
|
+
n => n.id === 'node-0',
|
|
99
|
+
);
|
|
100
|
+
expect(updatedNode?.data).toEqual({
|
|
101
|
+
content: 'Updated Content Description',
|
|
102
|
+
label: 'Root node',
|
|
103
|
+
title: 'Updated Title',
|
|
104
|
+
priority: 4,
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('#03 => Adding nodes with defaultData & DEFAULT_SIZE', () => {
|
|
110
|
+
it('#01 => should create parent node with defaultData and DEFAULT_SIZE', () => {
|
|
111
|
+
const service = createTestService();
|
|
112
|
+
const customDefaultData = {
|
|
113
|
+
title: 'New Task',
|
|
114
|
+
priority: 2,
|
|
115
|
+
content: 'Task content',
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
service.send({
|
|
119
|
+
type: 'SET_BOARD',
|
|
120
|
+
payload: {
|
|
121
|
+
self: { left: 0, top: 0, width: 1000, height: 800 },
|
|
122
|
+
parent: { scrollLeft: 0, scrollTop: 0, width: 1000, height: 800 },
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
service.send({
|
|
127
|
+
type: 'CONFIGURE',
|
|
128
|
+
payload: { nodes: [], edges: [], defaultData: customDefaultData },
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
service.send('ADD_PARENT');
|
|
132
|
+
|
|
133
|
+
expect(service.state.context.data?.nodes).toHaveLength(1);
|
|
134
|
+
const created = service.state.context.data?.nodes[0];
|
|
135
|
+
expect(created?.data).toEqual(customDefaultData);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('#02 => should fallback to DEFAULT_DATA when defaultData is not provided', () => {
|
|
139
|
+
const service = createTestService();
|
|
140
|
+
|
|
141
|
+
service.send({
|
|
142
|
+
type: 'SET_BOARD',
|
|
143
|
+
payload: {
|
|
144
|
+
self: { left: 0, top: 0, width: 1000, height: 800 },
|
|
145
|
+
parent: { scrollLeft: 0, scrollTop: 0, width: 1000, height: 800 },
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
service.send({ type: 'CONFIGURE', payload: { nodes: [], edges: [] } });
|
|
150
|
+
|
|
151
|
+
service.send('ADD_PARENT');
|
|
152
|
+
|
|
153
|
+
expect(service.state.context.data?.nodes).toHaveLength(1);
|
|
154
|
+
const created = service.state.context.data?.nodes[0];
|
|
155
|
+
expect(created?.data).toEqual(DEFAULT_DATA);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe('#04 => EDIT & STOP_EDIT events', () => {
|
|
160
|
+
it('#01 => should set editing and selected on EDIT event', () => {
|
|
161
|
+
const service = createTestService();
|
|
162
|
+
service.send({
|
|
163
|
+
type: 'CONFIGURE',
|
|
164
|
+
payload: { nodes: DEFAULT_NODES, edges: [] },
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
expect(service.state.context.editing).toBeUndefined();
|
|
168
|
+
|
|
169
|
+
service.send({ type: 'EDIT', payload: 'node-0' });
|
|
170
|
+
|
|
171
|
+
expect(service.state.context.editing).toBe('node-0');
|
|
172
|
+
expect(service.state.context.selected).toBe('node-0');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('#02 => should clear editing on STOP_EDIT event', () => {
|
|
176
|
+
const service = createTestService();
|
|
177
|
+
service.send({
|
|
178
|
+
type: 'CONFIGURE',
|
|
179
|
+
payload: { nodes: DEFAULT_NODES, edges: [] },
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
service.send({ type: 'EDIT', payload: 'node-0' });
|
|
183
|
+
expect(service.state.context.editing).toBe('node-0');
|
|
184
|
+
|
|
185
|
+
service.send('STOP_EDIT');
|
|
186
|
+
expect(service.state.context.editing).toBeUndefined();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('#03 => should clear editing and selected on DESELECT event', () => {
|
|
190
|
+
const service = createTestService();
|
|
191
|
+
service.send({
|
|
192
|
+
type: 'CONFIGURE',
|
|
193
|
+
payload: { nodes: DEFAULT_NODES, edges: [] },
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
service.send({ type: 'EDIT', payload: 'node-0' });
|
|
197
|
+
expect(service.state.context.editing).toBe('node-0');
|
|
198
|
+
expect(service.state.context.selected).toBe('node-0');
|
|
199
|
+
|
|
200
|
+
service.send('DESELECT');
|
|
201
|
+
expect(service.state.context.editing).toBeUndefined();
|
|
202
|
+
expect(service.state.context.selected).toBeUndefined();
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
});
|