@dineug/erd-editor 3.6.0 → 3.7.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 +21 -24
- package/dist/components/erd/automatic-table-placement/AutomaticTablePlacement.d.ts +5 -0
- package/dist/components/erd/automatic-table-placement/runElkPlacement.d.ts +12 -0
- package/dist/components/erd/erd-context-menu/menus/tablePlacementMenus.d.ts +24 -0
- package/dist/components/primitives/code-block/CodeBlock.d.ts +2 -2
- package/dist/components/primitives/icon/icons.d.ts +4 -0
- package/dist/constants/tablePlacement.d.ts +15 -0
- package/dist/erd-editor.umd.js +260 -260
- package/dist/index.d.ts +0 -1
- package/dist/index.dev.d.ts +0 -1
- package/dist/index.js +3556 -3337
- package/dist/services/elk-layout/elkGraph.d.ts +44 -0
- package/dist/services/elk-layout/elkLayout.shared-worker.d.ts +2 -0
- package/dist/services/elk-layout/elkLayoutOptions.d.ts +25 -0
- package/dist/services/elk-layout/elkLayoutService.d.ts +21 -0
- package/dist/services/elk-layout/elkWorkerRealm.d.ts +2 -0
- package/dist/services/elk-layout/index.d.ts +13 -0
- package/dist/services/shiki/index.d.ts +10 -0
- package/dist/services/shiki/shiki.shared-worker.d.ts +2 -0
- package/dist/services/shiki/shikiService.d.ts +18 -0
- package/dist/utils/domEvent.d.ts +6 -0
- package/dist/utils/emitter.d.ts +14 -7
- package/dist/utils/globalEventObservable.d.ts +6 -1
- package/dist/utils/promise.d.ts +6 -0
- package/dist/workers/elkLayout.shared-worker.js +1 -0
- package/dist/workers/exportPng.shared-worker.js +26 -26
- package/dist/workers/shiki.shared-worker.js +1 -0
- package/dist/workers/spawn.d.ts +5 -3
- package/dist/workers/spawn.inline.d.ts +2 -0
- package/package.json +7 -4
- package/dist/services/shikiService.d.ts +0 -9
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { RootState } from '../../engine/state';
|
|
2
|
+
import { ElkPlacement } from './elkLayoutOptions';
|
|
3
|
+
export type ElkLayoutNode = {
|
|
4
|
+
id: string;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
};
|
|
8
|
+
export type ElkLayoutEdge = {
|
|
9
|
+
source: string;
|
|
10
|
+
target: string;
|
|
11
|
+
/**
|
|
12
|
+
* Which row of each table the relationship meets, counted from the top, or
|
|
13
|
+
* -1 where the column it names is gone. A placement that hands ELK ports
|
|
14
|
+
* orders them by this, so a layout reads the connectors the editor draws.
|
|
15
|
+
*/
|
|
16
|
+
sourceRow: number;
|
|
17
|
+
targetRow: number;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* A layout as it crosses a realm boundary. Only the boxes and what joins them
|
|
21
|
+
* travel, so the answering realm measures no text and reads no document.
|
|
22
|
+
*/
|
|
23
|
+
export type ElkLayoutRequest = {
|
|
24
|
+
placement: ElkPlacement;
|
|
25
|
+
nodes: ElkLayoutNode[];
|
|
26
|
+
edges: ElkLayoutEdge[];
|
|
27
|
+
};
|
|
28
|
+
/** Where one table's top left corner ended up, in scene units. */
|
|
29
|
+
export type ElkLayoutPoint = {
|
|
30
|
+
id: string;
|
|
31
|
+
x: number;
|
|
32
|
+
y: number;
|
|
33
|
+
};
|
|
34
|
+
export declare function createElkLayoutRequest(state: RootState, placement: ElkPlacement): ElkLayoutRequest;
|
|
35
|
+
/**
|
|
36
|
+
* Where each table lands, over the middle of what the document already draws.
|
|
37
|
+
* ELK lays every graph out from its own origin, so a document placed twice
|
|
38
|
+
* would otherwise walk away from where it was read.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* onChange(toTablePoints(store.state, request, await createElkLayout(request)));
|
|
42
|
+
*/
|
|
43
|
+
export declare function toTablePoints(state: RootState, { nodes }: ElkLayoutRequest, points: ElkLayoutPoint[]): ElkLayoutPoint[];
|
|
44
|
+
//# sourceMappingURL=elkGraph.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { LayoutOptions } from 'elkjs/lib/elk-api';
|
|
2
|
+
import { TablePlacement } from '../../constants/tablePlacement';
|
|
3
|
+
/** The placements ELK answers, which is every one but the force simulation. */
|
|
4
|
+
export type ElkPlacement = Exclude<TablePlacement, typeof TablePlacement.force>;
|
|
5
|
+
export declare function isElkPlacement(placement: TablePlacement): placement is ElkPlacement;
|
|
6
|
+
/**
|
|
7
|
+
* Whether ELK is handed a port per relationship endpoint rather than a bare
|
|
8
|
+
* box. The layered placements ask only where a table goes; flow also says
|
|
9
|
+
* where each connector meets it, which is what pulls the crossings out.
|
|
10
|
+
*/
|
|
11
|
+
export declare function usesPorts(placement: ElkPlacement): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* What ELK is told, for the placement the author picked.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const graph = { id: 'root', layoutOptions: elkLayoutOptions(placement) };
|
|
17
|
+
*/
|
|
18
|
+
export declare function elkLayoutOptions(placement: ElkPlacement): LayoutOptions;
|
|
19
|
+
/**
|
|
20
|
+
* Every algorithm the placements name. ELK registers the metadata of these and
|
|
21
|
+
* no others, so it is read off the options rather than listed: a placement
|
|
22
|
+
* naming an algorithm left out here would be answered with an error.
|
|
23
|
+
*/
|
|
24
|
+
export declare const ELK_ALGORITHMS: string[];
|
|
25
|
+
//# sourceMappingURL=elkLayoutOptions.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ElkNode, ElkPort } from 'elkjs/lib/elk-api';
|
|
2
|
+
import { ElkLayoutEdge, ElkLayoutPoint, ElkLayoutRequest } from './elkGraph';
|
|
3
|
+
/** One port per relationship endpoint, grouped by the table it sits on. */
|
|
4
|
+
export declare function portsByNode(edges: ElkLayoutEdge[]): Map<string, ElkPort[]>;
|
|
5
|
+
/** The graph ELK is handed, which is flat: an ERD nests no table in another. */
|
|
6
|
+
export declare function toElkGraph({ placement, nodes, edges, }: ElkLayoutRequest): ElkNode;
|
|
7
|
+
/**
|
|
8
|
+
* Places tables by an ELK algorithm, off the thread that asked for it. What
|
|
9
|
+
* comes back is a corner per table and nothing else, because the editor routes
|
|
10
|
+
* its own relationship lines and drops the sections ELK computed for them.
|
|
11
|
+
*/
|
|
12
|
+
export declare class ElkLayoutService {
|
|
13
|
+
/**
|
|
14
|
+
* Loading ELK at all is what proves this realm can run it. A shared worker
|
|
15
|
+
* that throws while evaluating reports it to the console and to nobody else:
|
|
16
|
+
* its port stays open and every call after it hangs.
|
|
17
|
+
*/
|
|
18
|
+
ready(): Promise<boolean>;
|
|
19
|
+
layout(request: ElkLayoutRequest): Promise<ElkLayoutPoint[]>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=elkLayoutService.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ElkLayoutPoint, ElkLayoutRequest } from './elkGraph';
|
|
2
|
+
export { createElkLayoutRequest, type ElkLayoutPoint, type ElkLayoutRequest, toTablePoints, } from './elkGraph';
|
|
3
|
+
export { type ElkPlacement, isElkPlacement } from './elkLayoutOptions';
|
|
4
|
+
/**
|
|
5
|
+
* Where every table goes under the placement the author picked. ELK runs on a
|
|
6
|
+
* worker and only there, because laying a large schema out holds a thread for
|
|
7
|
+
* long enough to stop the editor drawing.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const points = await createElkLayout(createElkLayoutRequest(state, placement));
|
|
11
|
+
*/
|
|
12
|
+
export declare function createElkLayout(request: ElkLayoutRequest): Promise<ElkLayoutPoint[]>;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ShikiService } from './shikiService';
|
|
2
|
+
import * as Comlink from 'comlink';
|
|
3
|
+
export type { ShikiService } from './shikiService';
|
|
4
|
+
/**
|
|
5
|
+
* The highlighter the code panels read, built on the first panel that asks for
|
|
6
|
+
* one and kept for the session. Shiki and its grammars live behind the worker
|
|
7
|
+
* boundary, so a host that builds none is answered with null and plain text.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getShikiService(): Comlink.Remote<ShikiService> | null;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Lang } from '../../constants/language';
|
|
2
|
+
/**
|
|
3
|
+
* Shiki behind the one method the code panels call, instantiated in the shared
|
|
4
|
+
* worker and nowhere else. The grammars are exactly what constants/language.ts
|
|
5
|
+
* maps a Language onto, imported one by one so the worker carries no others.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const html = await new ShikiService().codeToHtml('select 1', { lang: 'sql' });
|
|
9
|
+
*/
|
|
10
|
+
export declare class ShikiService {
|
|
11
|
+
private highlighter;
|
|
12
|
+
constructor();
|
|
13
|
+
codeToHtml(code: string, { lang, theme }: {
|
|
14
|
+
lang: Lang;
|
|
15
|
+
theme?: 'dark' | 'light';
|
|
16
|
+
}): Promise<string>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=shikiService.d.ts.map
|
package/dist/utils/domEvent.d.ts
CHANGED
|
@@ -4,4 +4,10 @@ export declare function onStop(event: Event): void;
|
|
|
4
4
|
export declare function onStopImmediate(event: Event): void;
|
|
5
5
|
export declare function isMouseEvent(event: Event): event is MouseEvent;
|
|
6
6
|
export declare function isTouchEvent(event: Event): event is TouchEvent;
|
|
7
|
+
/**
|
|
8
|
+
* Takes selection off an element for the length of a gesture and hands back the
|
|
9
|
+
* undo. A press allowed to start one lets the browser promote the drag to a
|
|
10
|
+
* native one, which swallows the mouseup the gesture was waiting for.
|
|
11
|
+
*/
|
|
12
|
+
export declare function suppressSelection(el: HTMLElement): () => void;
|
|
7
13
|
//# sourceMappingURL=domEvent.d.ts.map
|
package/dist/utils/emitter.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Action, AnyAction, DOMTemplateLiterals } from '@dineug/r-html';
|
|
2
|
+
import { TablePlacement } from '../constants/tablePlacement';
|
|
2
3
|
import { ValuesType } from '../internal-types';
|
|
3
4
|
import { ThemeOptions } from '../themes/radix-ui-theme';
|
|
4
5
|
declare const InternalActionType: {
|
|
5
6
|
readonly openColorPicker: "openColorPicker";
|
|
6
7
|
readonly closeColorPicker: "closeColorPicker";
|
|
7
8
|
readonly openToast: "openToast";
|
|
8
|
-
readonly loadShikiService: "loadShikiService";
|
|
9
9
|
readonly openTableProperties: "openTableProperties";
|
|
10
10
|
readonly dragendColumnAll: "dragendColumnAll";
|
|
11
11
|
readonly copy: "copy";
|
|
@@ -17,6 +17,7 @@ declare const InternalActionType: {
|
|
|
17
17
|
readonly mouseTrackerStart: "mouseTrackerStart";
|
|
18
18
|
readonly mouseTrackerEnd: "mouseTrackerEnd";
|
|
19
19
|
readonly openDiffViewer: "openDiffViewer";
|
|
20
|
+
readonly openAutomaticTablePlacement: "openAutomaticTablePlacement";
|
|
20
21
|
readonly duplicateDragStart: "duplicateDragStart";
|
|
21
22
|
readonly dragSelectStart: "dragSelectStart";
|
|
22
23
|
};
|
|
@@ -32,7 +33,6 @@ type InternalActionMap = {
|
|
|
32
33
|
message: DOMTemplateLiterals;
|
|
33
34
|
close?: Promise<void>;
|
|
34
35
|
};
|
|
35
|
-
[InternalActionType.loadShikiService]: void;
|
|
36
36
|
[InternalActionType.openTableProperties]: {
|
|
37
37
|
tableId: string;
|
|
38
38
|
};
|
|
@@ -52,6 +52,9 @@ type InternalActionMap = {
|
|
|
52
52
|
[InternalActionType.openDiffViewer]: {
|
|
53
53
|
value: string;
|
|
54
54
|
};
|
|
55
|
+
[InternalActionType.openAutomaticTablePlacement]: {
|
|
56
|
+
placement: TablePlacement;
|
|
57
|
+
};
|
|
55
58
|
[InternalActionType.duplicateDragStart]: {
|
|
56
59
|
tableIds: string[];
|
|
57
60
|
memoIds: string[];
|
|
@@ -99,11 +102,6 @@ export declare const openToastAction: {
|
|
|
99
102
|
toString(): string;
|
|
100
103
|
type: string;
|
|
101
104
|
};
|
|
102
|
-
export declare const loadShikiServiceAction: {
|
|
103
|
-
(payload: void): AnyAction<void>;
|
|
104
|
-
toString(): string;
|
|
105
|
-
type: string;
|
|
106
|
-
};
|
|
107
105
|
export declare const openTablePropertiesAction: {
|
|
108
106
|
(payload: {
|
|
109
107
|
tableId: string;
|
|
@@ -175,6 +173,15 @@ export declare const openDiffViewerAction: {
|
|
|
175
173
|
toString(): string;
|
|
176
174
|
type: string;
|
|
177
175
|
};
|
|
176
|
+
export declare const openAutomaticTablePlacementAction: {
|
|
177
|
+
(payload: {
|
|
178
|
+
placement: TablePlacement;
|
|
179
|
+
}): AnyAction<{
|
|
180
|
+
placement: TablePlacement;
|
|
181
|
+
}>;
|
|
182
|
+
toString(): string;
|
|
183
|
+
type: string;
|
|
184
|
+
};
|
|
178
185
|
export declare const duplicateDragStartAction: {
|
|
179
186
|
(payload: void | {
|
|
180
187
|
tableIds: string[];
|
|
@@ -11,7 +11,12 @@ export declare const animationFrames$: Observable<{
|
|
|
11
11
|
elapsed: number;
|
|
12
12
|
}>;
|
|
13
13
|
export declare const moveStart$: Observable<MouseEvent | TouchEvent>;
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* A gesture also ends wherever the browser takes the pointer away: a native
|
|
16
|
+
* drag swallows the rest of the stream, a cancelled pointer never lifts, and a
|
|
17
|
+
* blurred window never sees the mouseup, each leaving drag$ subscribed.
|
|
18
|
+
*/
|
|
19
|
+
export declare const moveEnd$: Observable<MouseEvent | TouchEvent | DragEvent | PointerEvent | FocusEvent>;
|
|
15
20
|
export type DragMove = {
|
|
16
21
|
movementX: number;
|
|
17
22
|
movementY: number;
|
package/dist/utils/promise.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
export declare const delay: (ms: number) => Promise<void>;
|
|
2
2
|
export declare function closePromise(): [Promise<void>, () => void];
|
|
3
|
+
/**
|
|
4
|
+
* Rejects a promise that has not settled in time. A shared worker that throws
|
|
5
|
+
* while evaluating leaves its port open and its first call pending for ever,
|
|
6
|
+
* which is a wait only a clock ends.
|
|
7
|
+
*/
|
|
8
|
+
export declare function withTimeout<T>(promise: Promise<T>, ms: number, message: string): Promise<T>;
|
|
3
9
|
//# sourceMappingURL=promise.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as e from"comlink";typeof document>`u`&&Reflect.set(globalThis,`document`,{});const t={force:`force`,layeredHorizontal:`layeredHorizontal`,layeredVertical:`layeredVertical`,flow:`flow`};t.force;function n(e){return e!==t.force}function r(e){return e===t.flow}const i={"elk.spacing.nodeNode":`80`,"elk.separateConnectedComponents":`true`,"elk.spacing.componentComponent":`160`},a=e=>({...i,"elk.algorithm":`layered`,"elk.direction":e,"elk.layered.spacing.nodeNodeBetweenLayers":`160`,"elk.layered.cycleBreaking.strategy":`DEPTH_FIRST`});function o(e){switch(e){case t.layeredHorizontal:return a(`RIGHT`);case t.layeredVertical:return a(`DOWN`);case t.flow:return{...a(`RIGHT`),"elk.layered.nodePlacement.strategy":`SIMPLE`,"elk.layered.spacing.edgeNodeBetweenLayers":`80`}}}const s=[...new Set(Object.values(t).filter(n).map(e=>o(e)[`elk.algorithm`]))],c=`EAST`,l=e=>`edge-${e}-source`,u=e=>`edge-${e}-target`;function d(e,t){return e.side===t.side?e.side===c?e.row-t.row:t.row-e.row:e.side===c?-1:1}function f(e){let t=new Map,n=(e,n)=>{let r=t.get(e);r?r.push(n):t.set(e,[n])};return e.forEach((e,t)=>{n(e.source,{id:l(t),row:e.sourceRow,side:c}),n(e.target,{id:u(t),row:e.targetRow,side:`WEST`})}),new Map([...t].map(([e,t])=>[e,t.sort(d).map(({id:e,side:t})=>({id:e,width:8,height:8,layoutOptions:{"elk.port.side":t}}))]))}function p({placement:e,nodes:t,edges:n}){let i=r(e)?f(n):null;return{id:`root`,layoutOptions:o(e),children:t.map(({id:e,width:t,height:n})=>({id:e,width:t,height:n,...i?{layoutOptions:{"elk.portConstraints":`FIXED_ORDER`},ports:i.get(e)??[]}:{}})),edges:n.map(({source:e,target:t},n)=>({id:`edge-${n}`,sources:[i?l(n):e],targets:[i?u(n):t]}))}}let m=null;function h(){return m??=import(`elkjs/lib/elk.bundled.js`).then(({default:e})=>new e({algorithms:s})),m}const g=new class{async ready(){return await h(),!0}async layout(e){return((await(await h()).layout(p(e))).children??[]).map(({id:e,x:t,y:n})=>({id:e,x:t??0,y:n??0}))}};self.onconnect=t=>{let n=t.ports[0];e.expose(g,n)};
|