@dooc-dev/dooc 0.0.0-stage → 0.0.2
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 +26 -2
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +311 -0
- package/dist/code.global.js +285 -0
- package/dist/compiler/bundle-urls.d.ts +3 -0
- package/dist/compiler/bundle-urls.js +294 -0
- package/dist/compiler/bundle.d.ts +2 -0
- package/dist/compiler/bundle.js +100 -0
- package/dist/compiler/check-prose.d.ts +11 -0
- package/dist/compiler/check-prose.js +138 -0
- package/dist/compiler/check-types.d.ts +44 -0
- package/dist/compiler/check-types.js +1 -0
- package/dist/compiler/check.d.ts +5 -0
- package/dist/compiler/check.js +450 -0
- package/dist/compiler/code-blocks.d.ts +17 -0
- package/dist/compiler/code-blocks.js +198 -0
- package/dist/compiler/code-languages.d.ts +10 -0
- package/dist/compiler/code-languages.js +109 -0
- package/dist/compiler/compile.d.ts +95 -0
- package/dist/compiler/compile.js +410 -0
- package/dist/compiler/config.d.ts +7 -0
- package/dist/compiler/config.js +52 -0
- package/dist/compiler/dialect.d.ts +24 -0
- package/dist/compiler/dialect.js +198 -0
- package/dist/compiler/drawio.d.ts +26 -0
- package/dist/compiler/drawio.js +176 -0
- package/dist/compiler/figures.d.ts +14 -0
- package/dist/compiler/figures.js +221 -0
- package/dist/compiler/file-cache.d.ts +14 -0
- package/dist/compiler/file-cache.js +61 -0
- package/dist/compiler/files.d.ts +29 -0
- package/dist/compiler/files.js +431 -0
- package/dist/compiler/fonts.d.ts +10 -0
- package/dist/compiler/fonts.js +54 -0
- package/dist/compiler/format.d.ts +1 -0
- package/dist/compiler/format.js +42 -0
- package/dist/compiler/from-mdast.d.ts +16 -0
- package/dist/compiler/from-mdast.js +142 -0
- package/dist/compiler/icons.d.ts +14 -0
- package/dist/compiler/icons.js +85 -0
- package/dist/compiler/language-codes.d.ts +7 -0
- package/dist/compiler/language-codes.js +17 -0
- package/dist/compiler/locales.d.ts +7 -0
- package/dist/compiler/locales.js +67 -0
- package/dist/compiler/manifest.d.ts +6 -0
- package/dist/compiler/manifest.js +30 -0
- package/dist/compiler/ops.d.ts +44 -0
- package/dist/compiler/ops.js +362 -0
- package/dist/compiler/public-file.d.ts +2 -0
- package/dist/compiler/public-file.js +93 -0
- package/dist/compiler/serialize.d.ts +3 -0
- package/dist/compiler/serialize.js +16 -0
- package/dist/compiler/terms.d.ts +9 -0
- package/dist/compiler/terms.js +44 -0
- package/dist/compiler/textfile-remote.d.ts +12 -0
- package/dist/compiler/textfile-remote.js +124 -0
- package/dist/compiler/textfile.d.ts +9 -0
- package/dist/compiler/textfile.js +113 -0
- package/dist/compiler/theme-variants.d.ts +4 -0
- package/dist/compiler/theme-variants.js +22 -0
- package/dist/compiler/zip.d.ts +6 -0
- package/dist/compiler/zip.js +48 -0
- package/dist/core/blocks.d.ts +99 -0
- package/dist/core/blocks.js +29 -0
- package/dist/core/code-file.d.ts +12 -0
- package/dist/core/code-file.js +68 -0
- package/dist/core/content-metadata.d.ts +48 -0
- package/dist/core/content-metadata.js +264 -0
- package/dist/core/content-types.d.ts +45 -0
- package/dist/core/content-types.js +1 -0
- package/dist/core/extension-package.d.ts +34 -0
- package/dist/core/extension-package.js +147 -0
- package/dist/core/figure-frame.d.ts +12 -0
- package/dist/core/figure-frame.js +108 -0
- package/dist/core/file-embed.d.ts +13 -0
- package/dist/core/file-embed.js +43 -0
- package/dist/core/files.d.ts +15 -0
- package/dist/core/files.js +59 -0
- package/dist/core/flow-base-css.generated.d.ts +1 -0
- package/dist/core/flow-base-css.generated.js +4 -0
- package/dist/core/flow-css.d.ts +9 -0
- package/dist/core/flow-css.js +54 -0
- package/dist/core/graph-common.d.ts +32 -0
- package/dist/core/graph-common.js +113 -0
- package/dist/core/graph.d.ts +117 -0
- package/dist/core/graph.js +480 -0
- package/dist/core/html.d.ts +29 -0
- package/dist/core/html.js +444 -0
- package/dist/core/icons.d.ts +2 -0
- package/dist/core/icons.js +2 -0
- package/dist/core/inline.d.ts +27 -0
- package/dist/core/inline.js +42 -0
- package/dist/core/language.d.ts +41 -0
- package/dist/core/language.js +44 -0
- package/dist/core/languages/ja.d.ts +2 -0
- package/dist/core/languages/ja.js +5 -0
- package/dist/core/markdown.d.ts +27 -0
- package/dist/core/markdown.js +154 -0
- package/dist/core/previewers.d.ts +37 -0
- package/dist/core/previewers.js +103 -0
- package/dist/core/routing.d.ts +20 -0
- package/dist/core/routing.js +64 -0
- package/dist/core/schema-comments.d.ts +14 -0
- package/dist/core/schema-comments.js +52 -0
- package/dist/core/schema-graph-flow.d.ts +9 -0
- package/dist/core/schema-graph-flow.js +379 -0
- package/dist/core/schema-graph-mount.d.ts +9 -0
- package/dist/core/schema-graph-mount.js +105 -0
- package/dist/core/schema-graph.d.ts +254 -0
- package/dist/core/schema-graph.js +981 -0
- package/dist/core/table-ui.d.ts +2 -0
- package/dist/core/table-ui.js +180 -0
- package/dist/core/taxonomy.d.ts +12 -0
- package/dist/core/taxonomy.js +49 -0
- package/dist/core/term-reference.d.ts +5 -0
- package/dist/core/term-reference.js +19 -0
- package/dist/core/terms-ui.d.ts +6 -0
- package/dist/core/terms-ui.js +22 -0
- package/dist/core/textfile.d.ts +10 -0
- package/dist/core/textfile.js +39 -0
- package/dist/core/theme-variants.d.ts +3 -0
- package/dist/core/theme-variants.js +37 -0
- package/dist/core/toc-ui.d.ts +2 -0
- package/dist/core/toc-ui.js +161 -0
- package/dist/core/video-ui.d.ts +2 -0
- package/dist/core/video-ui.js +253 -0
- package/dist/core/workspace.d.ts +15 -0
- package/dist/core/workspace.js +28 -0
- package/dist/edit.global.js +306 -0
- package/dist/flow.global.js +4959 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +31 -0
- package/dist/mcp.d.ts +24 -0
- package/dist/mcp.js +467 -0
- package/dist/plugins/actions.d.ts +45 -0
- package/dist/plugins/actions.js +125 -0
- package/dist/plugins/blocks.d.ts +93 -0
- package/dist/plugins/blocks.js +100 -0
- package/dist/plugins/index.d.ts +4 -0
- package/dist/plugins/index.js +1 -0
- package/dist/plugins/local-storage.d.ts +18 -0
- package/dist/plugins/local-storage.js +115 -0
- package/dist/plugins/oauth.d.ts +14 -0
- package/dist/plugins/oauth.js +170 -0
- package/dist/plugins/runtime.d.ts +26 -0
- package/dist/plugins/runtime.js +395 -0
- package/dist/plugins/types.d.ts +59 -0
- package/dist/plugins/types.js +1 -0
- package/dist/plugins/view.d.ts +7 -0
- package/dist/plugins/view.js +21 -0
- package/dist/ui.global.js +78 -0
- package/dist/viewer/assets.d.ts +2 -0
- package/dist/viewer/assets.js +3 -0
- package/dist/viewer/build.d.ts +12 -0
- package/dist/viewer/build.js +55 -0
- package/dist/viewer/bundle-network.d.ts +2 -0
- package/dist/viewer/bundle-network.js +88 -0
- package/dist/viewer/code-file.d.ts +20 -0
- package/dist/viewer/code-file.js +42 -0
- package/dist/viewer/editor-tools.d.ts +38 -0
- package/dist/viewer/editor-tools.js +211 -0
- package/dist/viewer/extension-pack.d.ts +2 -0
- package/dist/viewer/extension-pack.js +36 -0
- package/dist/viewer/extensions.d.ts +10 -0
- package/dist/viewer/extensions.js +302 -0
- package/dist/viewer/file-references.d.ts +14 -0
- package/dist/viewer/file-references.js +38 -0
- package/dist/viewer/font-picker.d.ts +4 -0
- package/dist/viewer/font-picker.js +145 -0
- package/dist/viewer/font-settings.d.ts +11 -0
- package/dist/viewer/font-settings.js +50 -0
- package/dist/viewer/fonts/LICENSE.txt +119 -0
- package/dist/viewer/fonts/udev-gothic-regular.woff2 +0 -0
- package/dist/viewer/fonts.d.ts +2 -0
- package/dist/viewer/fonts.js +13 -0
- package/dist/viewer/git-diff.d.ts +3 -0
- package/dist/viewer/git-diff.js +33 -0
- package/dist/viewer/git-types.d.ts +73 -0
- package/dist/viewer/git-types.js +1 -0
- package/dist/viewer/git.d.ts +5 -0
- package/dist/viewer/git.js +337 -0
- package/dist/viewer/hmr.d.ts +53 -0
- package/dist/viewer/hmr.js +337 -0
- package/dist/viewer/i18n.d.ts +6 -0
- package/dist/viewer/i18n.js +65 -0
- package/dist/viewer/ja-lint.d.ts +3 -0
- package/dist/viewer/ja-lint.js +44 -0
- package/dist/viewer/language-picker.d.ts +2 -0
- package/dist/viewer/language-picker.js +233 -0
- package/dist/viewer/languages.d.ts +11 -0
- package/dist/viewer/languages.js +20 -0
- package/dist/viewer/locales/eng.json +317 -0
- package/dist/viewer/locales/jpn.json +317 -0
- package/dist/viewer/locales/zho.json +317 -0
- package/dist/viewer/nav-focus.d.ts +2 -0
- package/dist/viewer/nav-focus.js +64 -0
- package/dist/viewer/plugin-blocks.d.ts +3 -0
- package/dist/viewer/plugin-blocks.js +115 -0
- package/dist/viewer/plugin-config.d.ts +35 -0
- package/dist/viewer/plugin-config.js +57 -0
- package/dist/viewer/plugin-view.d.ts +2 -0
- package/dist/viewer/plugin-view.js +6 -0
- package/dist/viewer/plugins.d.ts +12 -0
- package/dist/viewer/plugins.js +267 -0
- package/dist/viewer/resize.d.ts +4 -0
- package/dist/viewer/resize.js +238 -0
- package/dist/viewer/resource-library.d.ts +29 -0
- package/dist/viewer/resource-library.js +104 -0
- package/dist/viewer/search.d.ts +16 -0
- package/dist/viewer/search.js +358 -0
- package/dist/viewer/serve.d.ts +210 -0
- package/dist/viewer/serve.js +3312 -0
- package/dist/viewer/site-icon.d.ts +8 -0
- package/dist/viewer/site-icon.js +56 -0
- package/dist/viewer/textfile.d.ts +9 -0
- package/dist/viewer/textfile.js +50 -0
- package/dist/viewer/theme-picker.d.ts +2 -0
- package/dist/viewer/theme-picker.js +135 -0
- package/dist/viewer/workspace.d.ts +4 -0
- package/dist/viewer/workspace.js +47 -0
- package/package.json +128 -5
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface FileLayout {
|
|
2
|
+
defaultLayout: boolean;
|
|
3
|
+
documents: Record<string, string>;
|
|
4
|
+
order: string[];
|
|
5
|
+
icons?: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
export declare const MAX_FILE_UPLOAD_BYTES: number;
|
|
8
|
+
export declare const localFile: (value: unknown) => value is string;
|
|
9
|
+
export declare const isDocumentFileName: (value: unknown) => value is string;
|
|
10
|
+
export declare const suggestDocFileName: (title: string) => string;
|
|
11
|
+
export declare const fileExtension: (file: string) => string;
|
|
12
|
+
export declare const defaultFilePath: (file: string) => string;
|
|
13
|
+
export declare const docFile: (id: string, layout?: FileLayout) => string;
|
|
14
|
+
export declare const parseFileLayout: (value: unknown) => FileLayout;
|
|
15
|
+
export declare const docIconFile: (id: string, layout?: FileLayout) => string;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export const MAX_FILE_UPLOAD_BYTES = 64 * 1024 * 1024;
|
|
2
|
+
export const localFile = (value) => typeof value === "string" &&
|
|
3
|
+
value.length > 0 &&
|
|
4
|
+
!/[\\:?#]/.test(value) &&
|
|
5
|
+
[...value].every((char) => char.charCodeAt(0) >= 32) &&
|
|
6
|
+
value.split("/").every((part) => !!part && !part.startsWith("."));
|
|
7
|
+
export const isDocumentFileName = (value) => localFile(value) && !value.includes("/") && value.endsWith(".md");
|
|
8
|
+
export const suggestDocFileName = (title) => {
|
|
9
|
+
const name = [...title]
|
|
10
|
+
.filter((char) => char.charCodeAt(0) >= 32)
|
|
11
|
+
.join("")
|
|
12
|
+
.replace(/[\\/:?#]+/g, "-")
|
|
13
|
+
.trim()
|
|
14
|
+
.replace(/^\.+/, "");
|
|
15
|
+
return name ? (name.endsWith(".md") ? name : `${name}.md`) : "";
|
|
16
|
+
};
|
|
17
|
+
export const fileExtension = (file) => {
|
|
18
|
+
const name = file.split("/").pop() ?? file;
|
|
19
|
+
return name.includes(".") ? name.slice(name.lastIndexOf(".") + 1).toLowerCase() : "other";
|
|
20
|
+
};
|
|
21
|
+
export const defaultFilePath = (file) => `files/${fileExtension(file)}/${file.split("/").pop()}`;
|
|
22
|
+
export const docFile = (id, layout) => layout && Object.hasOwn(layout.documents, id)
|
|
23
|
+
? layout.documents[id]
|
|
24
|
+
: `content/${id}.md`;
|
|
25
|
+
export const parseFileLayout = (value) => {
|
|
26
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
27
|
+
throw new Error("files must be an object");
|
|
28
|
+
const v = value;
|
|
29
|
+
if (Object.keys(v).some((key) => !["defaultLayout", "documents", "order", "icons"].includes(key)) ||
|
|
30
|
+
(v.defaultLayout !== undefined && typeof v.defaultLayout !== "boolean"))
|
|
31
|
+
throw new Error("Invalid file layout");
|
|
32
|
+
const documents = v.documents ?? {};
|
|
33
|
+
const order = v.order ?? [];
|
|
34
|
+
const icons = v.icons;
|
|
35
|
+
if (icons !== undefined &&
|
|
36
|
+
(!icons ||
|
|
37
|
+
typeof icons !== "object" ||
|
|
38
|
+
Array.isArray(icons) ||
|
|
39
|
+
Object.entries(icons).some(([id, file]) => !/^[a-z0-9][a-z0-9-]*$/.test(id) || !localFile(file) || !file.endsWith(".svg"))))
|
|
40
|
+
throw new Error("Invalid icon paths");
|
|
41
|
+
if (!documents ||
|
|
42
|
+
typeof documents !== "object" ||
|
|
43
|
+
Array.isArray(documents) ||
|
|
44
|
+
Object.entries(documents).some(([id, file]) => !/^[a-z0-9][a-z0-9-]*$/.test(id) || !localFile(file) || !file.endsWith(".md")) ||
|
|
45
|
+
new Set(Object.values(documents)).size !== Object.keys(documents).length ||
|
|
46
|
+
!Array.isArray(order) ||
|
|
47
|
+
order.some((file) => !localFile(file)) ||
|
|
48
|
+
new Set(order).size !== order.length)
|
|
49
|
+
throw new Error("Invalid file paths or order");
|
|
50
|
+
return {
|
|
51
|
+
defaultLayout: v.defaultLayout !== false,
|
|
52
|
+
documents: documents,
|
|
53
|
+
order,
|
|
54
|
+
...(icons ? { icons: icons } : {}),
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
export const docIconFile = (id, layout) => layout?.icons && Object.hasOwn(layout.icons, id)
|
|
58
|
+
? layout.icons[id]
|
|
59
|
+
: `icons/${id}.svg`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const XYFLOW_BASE_CSS = "/* this will be exported as base.css and can be used for a basic styling */\n/* these are the necessary styles for React/Svelte Flow, they get used by base.css and style.css */\n.react-flow {\n direction: ltr;\n\n --xy-edge-stroke-default: #b1b1b7;\n --xy-edge-stroke-width-default: 1;\n --xy-edge-stroke-selected-default: #555;\n\n --xy-connectionline-stroke-default: #b1b1b7;\n --xy-connectionline-stroke-width-default: 1;\n\n --xy-attribution-background-color-default: rgba(255, 255, 255, 0.5);\n\n --xy-minimap-background-color-default: #fff;\n --xy-minimap-mask-background-color-default: rgba(240, 240, 240, 0.6);\n --xy-minimap-mask-stroke-color-default: transparent;\n --xy-minimap-mask-stroke-width-default: 1;\n --xy-minimap-node-background-color-default: #e2e2e2;\n --xy-minimap-node-stroke-color-default: transparent;\n --xy-minimap-node-stroke-width-default: 2;\n\n --xy-background-color-default: transparent;\n --xy-background-pattern-dots-color-default: #91919a;\n --xy-background-pattern-lines-color-default: #eee;\n --xy-background-pattern-cross-color-default: #e2e2e2;\n background-color: var(--xy-background-color, var(--xy-background-color-default));\n --xy-node-border-default: 1px solid #bbb;\n --xy-node-border-selected-default: 1px solid #555;\n\n --xy-handle-background-color-default: #333;\n\n --xy-selection-background-color-default: rgba(150, 150, 180, 0.1);\n --xy-selection-border-default: 1px dotted rgba(155, 155, 155, 0.8);\n --xy-resize-background-color-default: #3367d9;\n}\n.react-flow.dark {\n --xy-edge-stroke-default: #3e3e3e;\n --xy-edge-stroke-width-default: 1;\n --xy-edge-stroke-selected-default: #727272;\n\n --xy-connectionline-stroke-default: #b1b1b7;\n --xy-connectionline-stroke-width-default: 1;\n\n --xy-attribution-background-color-default: rgba(150, 150, 150, 0.25);\n\n --xy-minimap-background-color-default: #141414;\n --xy-minimap-mask-background-color-default: rgba(60, 60, 60, 0.6);\n --xy-minimap-mask-stroke-color-default: transparent;\n --xy-minimap-mask-stroke-width-default: 1;\n --xy-minimap-node-background-color-default: #2b2b2b;\n --xy-minimap-node-stroke-color-default: transparent;\n --xy-minimap-node-stroke-width-default: 2;\n\n --xy-background-color-default: #141414;\n --xy-background-pattern-dots-color-default: #555;\n --xy-background-pattern-lines-color-default: #333;\n --xy-background-pattern-cross-color-default: #333;\n --xy-node-color-default: #f8f8f8;\n}\n.react-flow__background {\n background-color: var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));\n pointer-events: none;\n z-index: -1;\n}\n.react-flow__container {\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n}\n.react-flow__pane {\n z-index: 1;\n touch-action: none;\n}\n.react-flow__pane.draggable {\n cursor: grab;\n }\n.react-flow__pane.dragging {\n cursor: grabbing;\n }\n.react-flow__pane.selection {\n cursor: pointer;\n }\n.react-flow__viewport {\n transform-origin: 0 0;\n z-index: 2;\n pointer-events: none;\n}\n.react-flow__renderer {\n z-index: 4;\n}\n.react-flow__selection {\n z-index: 6;\n}\n.react-flow__nodesselection-rect:focus,\n.react-flow__nodesselection-rect:focus-visible {\n outline: none;\n}\n.react-flow__edge-path {\n stroke: var(--xy-edge-stroke, var(--xy-edge-stroke-default));\n stroke-width: var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));\n fill: none;\n}\n.react-flow__connection-path {\n stroke: var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));\n stroke-width: var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));\n fill: none;\n}\n.react-flow .react-flow__edges {\n position: absolute;\n}\n.react-flow .react-flow__edges svg {\n overflow: visible;\n position: absolute;\n pointer-events: none;\n }\n.react-flow__edge {\n pointer-events: visibleStroke;\n}\n.react-flow__edge.selectable {\n cursor: pointer;\n }\n.react-flow__edge.animated path {\n stroke-dasharray: 5;\n animation: dashdraw 0.5s linear infinite;\n }\n.react-flow__edge.animated path.react-flow__edge-interaction {\n stroke-dasharray: none;\n animation: none;\n }\n.react-flow__edge.inactive {\n pointer-events: none;\n }\n.react-flow__edge.selected,\n .react-flow__edge:focus,\n .react-flow__edge:focus-visible {\n outline: none;\n }\n.react-flow__edge.selected .react-flow__edge-path,\n .react-flow__edge.selectable:focus .react-flow__edge-path,\n .react-flow__edge.selectable:focus-visible .react-flow__edge-path {\n stroke: var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default));\n }\n.react-flow__edge-textwrapper {\n pointer-events: all;\n }\n.react-flow__edge .react-flow__edge-text {\n pointer-events: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n }\n/* Arrowhead marker styles - use CSS custom properties as default */\n.react-flow__arrowhead polyline {\n stroke: var(--xy-edge-stroke, var(--xy-edge-stroke-default));\n}\n.react-flow__arrowhead polyline.arrowclosed {\n fill: var(--xy-edge-stroke, var(--xy-edge-stroke-default));\n}\n.react-flow__connection {\n pointer-events: none;\n}\n.react-flow__connection .animated {\n stroke-dasharray: 5;\n animation: dashdraw 0.5s linear infinite;\n }\nsvg.react-flow__connectionline {\n z-index: 1001;\n overflow: visible;\n position: absolute;\n}\n.react-flow__nodes {\n pointer-events: none;\n transform-origin: 0 0;\n}\n.react-flow__node {\n position: absolute;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n pointer-events: all;\n transform-origin: 0 0;\n box-sizing: border-box;\n cursor: default;\n}\n.react-flow__node.selectable {\n cursor: pointer;\n }\n.react-flow__node.draggable {\n cursor: grab;\n pointer-events: all;\n }\n.react-flow__node.draggable.dragging {\n cursor: grabbing;\n }\n.react-flow__nodesselection {\n z-index: 3;\n transform-origin: left top;\n pointer-events: none;\n}\n.react-flow__nodesselection-rect {\n position: absolute;\n pointer-events: all;\n cursor: grab;\n }\n.react-flow__handle {\n position: absolute;\n pointer-events: none;\n min-width: 5px;\n min-height: 5px;\n background-color: var(--xy-handle-background-color, var(--xy-handle-background-color-default));\n}\n.react-flow__handle.connectingfrom {\n pointer-events: all;\n }\n.react-flow__handle.connectionindicator {\n pointer-events: all;\n cursor: crosshair;\n }\n.react-flow__handle-bottom {\n top: auto;\n left: 50%;\n bottom: 0;\n transform: translate(-50%, 50%);\n }\n.react-flow__handle-top {\n top: 0;\n left: 50%;\n transform: translate(-50%, -50%);\n }\n.react-flow__handle-left {\n top: 50%;\n left: 0;\n transform: translate(-50%, -50%);\n }\n.react-flow__handle-right {\n top: 50%;\n right: 0;\n transform: translate(50%, -50%);\n }\n.react-flow__edgeupdater {\n cursor: move;\n pointer-events: all;\n}\n.react-flow__pane.selection .react-flow__panel {\n pointer-events: none;\n}\n.react-flow__panel {\n position: absolute;\n z-index: 5;\n margin: 15px;\n}\n.react-flow__panel.top {\n top: 0;\n }\n.react-flow__panel.bottom {\n bottom: 0;\n }\n.react-flow__panel.top.center, .react-flow__panel.bottom.center {\n left: 50%;\n transform: translateX(-15px) translateX(-50%);\n }\n.react-flow__panel.left {\n left: 0;\n }\n.react-flow__panel.right {\n right: 0;\n }\n.react-flow__panel.left.center, .react-flow__panel.right.center {\n top: 50%;\n transform: translateY(-15px) translateY(-50%);\n }\n.react-flow__attribution {\n font-size: 10px;\n background: var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));\n padding: 2px 3px;\n margin: 0;\n}\n.react-flow__attribution a {\n text-decoration: none;\n color: #999;\n }\n@keyframes dashdraw {\n from {\n stroke-dashoffset: 10;\n }\n}\n.react-flow__edgelabel-renderer {\n position: absolute;\n width: 100%;\n height: 100%;\n pointer-events: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n left: 0;\n top: 0;\n}\n.react-flow__viewport-portal {\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n}\n.react-flow__minimap {\n background: var(\n --xy-minimap-background-color-props,\n var(--xy-minimap-background-color, var(--xy-minimap-background-color-default))\n );\n}\n.react-flow__minimap-svg {\n display: block;\n }\n.react-flow__minimap-mask {\n fill: var(\n --xy-minimap-mask-background-color-props,\n var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default))\n );\n stroke: var(\n --xy-minimap-mask-stroke-color-props,\n var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default))\n );\n stroke-width: var(\n --xy-minimap-mask-stroke-width-props,\n var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default))\n );\n }\n.react-flow__minimap-node {\n fill: var(\n --xy-minimap-node-background-color-props,\n var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default))\n );\n stroke: var(\n --xy-minimap-node-stroke-color-props,\n var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default))\n );\n stroke-width: var(\n --xy-minimap-node-stroke-width-props,\n var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default))\n );\n }\n.react-flow__background-pattern.dots {\n fill: var(\n --xy-background-pattern-color-props,\n var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default))\n );\n }\n.react-flow__background-pattern.lines {\n stroke: var(\n --xy-background-pattern-color-props,\n var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default))\n );\n }\n.react-flow__background-pattern.cross {\n stroke: var(\n --xy-background-pattern-color-props,\n var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default))\n );\n }\n.react-flow__controls {\n display: flex;\n flex-direction: column;\n}\n.react-flow__controls.horizontal {\n flex-direction: row;\n }\n.react-flow__controls-button {\n display: flex;\n justify-content: center;\n align-items: center;\n height: 26px;\n width: 26px;\n padding: 4px;\n }\n.react-flow__controls-button svg {\n width: 100%;\n max-width: 12px;\n max-height: 12px;\n fill: currentColor;\n }\n.react-flow__node-input,\n.react-flow__node-default,\n.react-flow__node-output,\n.react-flow__node-group {\n border: var(--xy-node-border, var(--xy-node-border-default));\n color: var(--xy-node-color, var(--xy-node-color-default));\n}\n.react-flow__node-input.selected,\n .react-flow__node-input:focus,\n .react-flow__node-input:focus-visible,\n .react-flow__node-default.selected,\n .react-flow__node-default:focus,\n .react-flow__node-default:focus-visible,\n .react-flow__node-output.selected,\n .react-flow__node-output:focus,\n .react-flow__node-output:focus-visible,\n .react-flow__node-group.selected,\n .react-flow__node-group:focus,\n .react-flow__node-group:focus-visible {\n outline: none;\n border: var(--xy-node-border-selected, var(--xy-node-border-selected-default));\n }\n.react-flow__nodesselection-rect,\n.react-flow__selection {\n background: var(--xy-selection-background-color, var(--xy-selection-background-color-default));\n border: var(--xy-selection-border, var(--xy-selection-border-default));\n}\n.react-flow__resize-control {\n position: absolute;\n}\n.react-flow__resize-control.left,\n.react-flow__resize-control.right {\n cursor: ew-resize;\n}\n.react-flow__resize-control.top,\n.react-flow__resize-control.bottom {\n cursor: ns-resize;\n}\n.react-flow__resize-control.top.left,\n.react-flow__resize-control.bottom.right {\n cursor: nwse-resize;\n}\n.react-flow__resize-control.bottom.left,\n.react-flow__resize-control.top.right {\n cursor: nesw-resize;\n}\n/* handle styles */\n.react-flow__resize-control.handle {\n width: 5px;\n height: 5px;\n border: 1px solid #fff;\n border-radius: 1px;\n background-color: var(--xy-resize-background-color, var(--xy-resize-background-color-default));\n translate: -50% -50%;\n}\n.react-flow__resize-control.handle.left {\n left: 0;\n top: 50%;\n}\n.react-flow__resize-control.handle.right {\n left: 100%;\n top: 50%;\n}\n.react-flow__resize-control.handle.top {\n left: 50%;\n top: 0;\n}\n.react-flow__resize-control.handle.bottom {\n left: 50%;\n top: 100%;\n}\n.react-flow__resize-control.handle.top.left {\n left: 0;\n}\n.react-flow__resize-control.handle.bottom.left {\n left: 0;\n}\n.react-flow__resize-control.handle.top.right {\n left: 100%;\n}\n.react-flow__resize-control.handle.bottom.right {\n left: 100%;\n}\n/* line styles */\n.react-flow__resize-control.line {\n border-color: var(--xy-resize-background-color, var(--xy-resize-background-color-default));\n border-width: 0;\n border-style: solid;\n}\n.react-flow__resize-control.line.left,\n.react-flow__resize-control.line.right {\n width: 1px;\n transform: translate(-50%, 0);\n top: 0;\n height: 100%;\n}\n.react-flow__resize-control.line.left {\n left: 0;\n border-left-width: 1px;\n}\n.react-flow__resize-control.line.right {\n left: 100%;\n border-right-width: 1px;\n}\n.react-flow__resize-control.line.top,\n.react-flow__resize-control.line.bottom {\n height: 1px;\n transform: translate(0, -50%);\n left: 0;\n width: 100%;\n}\n.react-flow__resize-control.line.top {\n top: 0;\n border-top-width: 1px;\n}\n.react-flow__resize-control.line.bottom {\n border-bottom-width: 1px;\n top: 100%;\n}\n";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Generated — do not edit by hand (`pnpm run build:css` = build-flow-css.ts
|
|
2
|
+
// copies it from @xyflow/react/dist/base.css). A structure-only stylesheet; colors come from
|
|
3
|
+
// `--doc-*` injected by the consumer (React Flow's default theme = style.css is not included).
|
|
4
|
+
export const XYFLOW_BASE_CSS = "/* this will be exported as base.css and can be used for a basic styling */\n/* these are the necessary styles for React/Svelte Flow, they get used by base.css and style.css */\n.react-flow {\n direction: ltr;\n\n --xy-edge-stroke-default: #b1b1b7;\n --xy-edge-stroke-width-default: 1;\n --xy-edge-stroke-selected-default: #555;\n\n --xy-connectionline-stroke-default: #b1b1b7;\n --xy-connectionline-stroke-width-default: 1;\n\n --xy-attribution-background-color-default: rgba(255, 255, 255, 0.5);\n\n --xy-minimap-background-color-default: #fff;\n --xy-minimap-mask-background-color-default: rgba(240, 240, 240, 0.6);\n --xy-minimap-mask-stroke-color-default: transparent;\n --xy-minimap-mask-stroke-width-default: 1;\n --xy-minimap-node-background-color-default: #e2e2e2;\n --xy-minimap-node-stroke-color-default: transparent;\n --xy-minimap-node-stroke-width-default: 2;\n\n --xy-background-color-default: transparent;\n --xy-background-pattern-dots-color-default: #91919a;\n --xy-background-pattern-lines-color-default: #eee;\n --xy-background-pattern-cross-color-default: #e2e2e2;\n background-color: var(--xy-background-color, var(--xy-background-color-default));\n --xy-node-border-default: 1px solid #bbb;\n --xy-node-border-selected-default: 1px solid #555;\n\n --xy-handle-background-color-default: #333;\n\n --xy-selection-background-color-default: rgba(150, 150, 180, 0.1);\n --xy-selection-border-default: 1px dotted rgba(155, 155, 155, 0.8);\n --xy-resize-background-color-default: #3367d9;\n}\n.react-flow.dark {\n --xy-edge-stroke-default: #3e3e3e;\n --xy-edge-stroke-width-default: 1;\n --xy-edge-stroke-selected-default: #727272;\n\n --xy-connectionline-stroke-default: #b1b1b7;\n --xy-connectionline-stroke-width-default: 1;\n\n --xy-attribution-background-color-default: rgba(150, 150, 150, 0.25);\n\n --xy-minimap-background-color-default: #141414;\n --xy-minimap-mask-background-color-default: rgba(60, 60, 60, 0.6);\n --xy-minimap-mask-stroke-color-default: transparent;\n --xy-minimap-mask-stroke-width-default: 1;\n --xy-minimap-node-background-color-default: #2b2b2b;\n --xy-minimap-node-stroke-color-default: transparent;\n --xy-minimap-node-stroke-width-default: 2;\n\n --xy-background-color-default: #141414;\n --xy-background-pattern-dots-color-default: #555;\n --xy-background-pattern-lines-color-default: #333;\n --xy-background-pattern-cross-color-default: #333;\n --xy-node-color-default: #f8f8f8;\n}\n.react-flow__background {\n background-color: var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));\n pointer-events: none;\n z-index: -1;\n}\n.react-flow__container {\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n}\n.react-flow__pane {\n z-index: 1;\n touch-action: none;\n}\n.react-flow__pane.draggable {\n cursor: grab;\n }\n.react-flow__pane.dragging {\n cursor: grabbing;\n }\n.react-flow__pane.selection {\n cursor: pointer;\n }\n.react-flow__viewport {\n transform-origin: 0 0;\n z-index: 2;\n pointer-events: none;\n}\n.react-flow__renderer {\n z-index: 4;\n}\n.react-flow__selection {\n z-index: 6;\n}\n.react-flow__nodesselection-rect:focus,\n.react-flow__nodesselection-rect:focus-visible {\n outline: none;\n}\n.react-flow__edge-path {\n stroke: var(--xy-edge-stroke, var(--xy-edge-stroke-default));\n stroke-width: var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));\n fill: none;\n}\n.react-flow__connection-path {\n stroke: var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));\n stroke-width: var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));\n fill: none;\n}\n.react-flow .react-flow__edges {\n position: absolute;\n}\n.react-flow .react-flow__edges svg {\n overflow: visible;\n position: absolute;\n pointer-events: none;\n }\n.react-flow__edge {\n pointer-events: visibleStroke;\n}\n.react-flow__edge.selectable {\n cursor: pointer;\n }\n.react-flow__edge.animated path {\n stroke-dasharray: 5;\n animation: dashdraw 0.5s linear infinite;\n }\n.react-flow__edge.animated path.react-flow__edge-interaction {\n stroke-dasharray: none;\n animation: none;\n }\n.react-flow__edge.inactive {\n pointer-events: none;\n }\n.react-flow__edge.selected,\n .react-flow__edge:focus,\n .react-flow__edge:focus-visible {\n outline: none;\n }\n.react-flow__edge.selected .react-flow__edge-path,\n .react-flow__edge.selectable:focus .react-flow__edge-path,\n .react-flow__edge.selectable:focus-visible .react-flow__edge-path {\n stroke: var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default));\n }\n.react-flow__edge-textwrapper {\n pointer-events: all;\n }\n.react-flow__edge .react-flow__edge-text {\n pointer-events: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n }\n/* Arrowhead marker styles - use CSS custom properties as default */\n.react-flow__arrowhead polyline {\n stroke: var(--xy-edge-stroke, var(--xy-edge-stroke-default));\n}\n.react-flow__arrowhead polyline.arrowclosed {\n fill: var(--xy-edge-stroke, var(--xy-edge-stroke-default));\n}\n.react-flow__connection {\n pointer-events: none;\n}\n.react-flow__connection .animated {\n stroke-dasharray: 5;\n animation: dashdraw 0.5s linear infinite;\n }\nsvg.react-flow__connectionline {\n z-index: 1001;\n overflow: visible;\n position: absolute;\n}\n.react-flow__nodes {\n pointer-events: none;\n transform-origin: 0 0;\n}\n.react-flow__node {\n position: absolute;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n pointer-events: all;\n transform-origin: 0 0;\n box-sizing: border-box;\n cursor: default;\n}\n.react-flow__node.selectable {\n cursor: pointer;\n }\n.react-flow__node.draggable {\n cursor: grab;\n pointer-events: all;\n }\n.react-flow__node.draggable.dragging {\n cursor: grabbing;\n }\n.react-flow__nodesselection {\n z-index: 3;\n transform-origin: left top;\n pointer-events: none;\n}\n.react-flow__nodesselection-rect {\n position: absolute;\n pointer-events: all;\n cursor: grab;\n }\n.react-flow__handle {\n position: absolute;\n pointer-events: none;\n min-width: 5px;\n min-height: 5px;\n background-color: var(--xy-handle-background-color, var(--xy-handle-background-color-default));\n}\n.react-flow__handle.connectingfrom {\n pointer-events: all;\n }\n.react-flow__handle.connectionindicator {\n pointer-events: all;\n cursor: crosshair;\n }\n.react-flow__handle-bottom {\n top: auto;\n left: 50%;\n bottom: 0;\n transform: translate(-50%, 50%);\n }\n.react-flow__handle-top {\n top: 0;\n left: 50%;\n transform: translate(-50%, -50%);\n }\n.react-flow__handle-left {\n top: 50%;\n left: 0;\n transform: translate(-50%, -50%);\n }\n.react-flow__handle-right {\n top: 50%;\n right: 0;\n transform: translate(50%, -50%);\n }\n.react-flow__edgeupdater {\n cursor: move;\n pointer-events: all;\n}\n.react-flow__pane.selection .react-flow__panel {\n pointer-events: none;\n}\n.react-flow__panel {\n position: absolute;\n z-index: 5;\n margin: 15px;\n}\n.react-flow__panel.top {\n top: 0;\n }\n.react-flow__panel.bottom {\n bottom: 0;\n }\n.react-flow__panel.top.center, .react-flow__panel.bottom.center {\n left: 50%;\n transform: translateX(-15px) translateX(-50%);\n }\n.react-flow__panel.left {\n left: 0;\n }\n.react-flow__panel.right {\n right: 0;\n }\n.react-flow__panel.left.center, .react-flow__panel.right.center {\n top: 50%;\n transform: translateY(-15px) translateY(-50%);\n }\n.react-flow__attribution {\n font-size: 10px;\n background: var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));\n padding: 2px 3px;\n margin: 0;\n}\n.react-flow__attribution a {\n text-decoration: none;\n color: #999;\n }\n@keyframes dashdraw {\n from {\n stroke-dashoffset: 10;\n }\n}\n.react-flow__edgelabel-renderer {\n position: absolute;\n width: 100%;\n height: 100%;\n pointer-events: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n left: 0;\n top: 0;\n}\n.react-flow__viewport-portal {\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n}\n.react-flow__minimap {\n background: var(\n --xy-minimap-background-color-props,\n var(--xy-minimap-background-color, var(--xy-minimap-background-color-default))\n );\n}\n.react-flow__minimap-svg {\n display: block;\n }\n.react-flow__minimap-mask {\n fill: var(\n --xy-minimap-mask-background-color-props,\n var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default))\n );\n stroke: var(\n --xy-minimap-mask-stroke-color-props,\n var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default))\n );\n stroke-width: var(\n --xy-minimap-mask-stroke-width-props,\n var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default))\n );\n }\n.react-flow__minimap-node {\n fill: var(\n --xy-minimap-node-background-color-props,\n var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default))\n );\n stroke: var(\n --xy-minimap-node-stroke-color-props,\n var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default))\n );\n stroke-width: var(\n --xy-minimap-node-stroke-width-props,\n var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default))\n );\n }\n.react-flow__background-pattern.dots {\n fill: var(\n --xy-background-pattern-color-props,\n var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default))\n );\n }\n.react-flow__background-pattern.lines {\n stroke: var(\n --xy-background-pattern-color-props,\n var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default))\n );\n }\n.react-flow__background-pattern.cross {\n stroke: var(\n --xy-background-pattern-color-props,\n var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default))\n );\n }\n.react-flow__controls {\n display: flex;\n flex-direction: column;\n}\n.react-flow__controls.horizontal {\n flex-direction: row;\n }\n.react-flow__controls-button {\n display: flex;\n justify-content: center;\n align-items: center;\n height: 26px;\n width: 26px;\n padding: 4px;\n }\n.react-flow__controls-button svg {\n width: 100%;\n max-width: 12px;\n max-height: 12px;\n fill: currentColor;\n }\n.react-flow__node-input,\n.react-flow__node-default,\n.react-flow__node-output,\n.react-flow__node-group {\n border: var(--xy-node-border, var(--xy-node-border-default));\n color: var(--xy-node-color, var(--xy-node-color-default));\n}\n.react-flow__node-input.selected,\n .react-flow__node-input:focus,\n .react-flow__node-input:focus-visible,\n .react-flow__node-default.selected,\n .react-flow__node-default:focus,\n .react-flow__node-default:focus-visible,\n .react-flow__node-output.selected,\n .react-flow__node-output:focus,\n .react-flow__node-output:focus-visible,\n .react-flow__node-group.selected,\n .react-flow__node-group:focus,\n .react-flow__node-group:focus-visible {\n outline: none;\n border: var(--xy-node-border-selected, var(--xy-node-border-selected-default));\n }\n.react-flow__nodesselection-rect,\n.react-flow__selection {\n background: var(--xy-selection-background-color, var(--xy-selection-background-color-default));\n border: var(--xy-selection-border, var(--xy-selection-border-default));\n}\n.react-flow__resize-control {\n position: absolute;\n}\n.react-flow__resize-control.left,\n.react-flow__resize-control.right {\n cursor: ew-resize;\n}\n.react-flow__resize-control.top,\n.react-flow__resize-control.bottom {\n cursor: ns-resize;\n}\n.react-flow__resize-control.top.left,\n.react-flow__resize-control.bottom.right {\n cursor: nwse-resize;\n}\n.react-flow__resize-control.bottom.left,\n.react-flow__resize-control.top.right {\n cursor: nesw-resize;\n}\n/* handle styles */\n.react-flow__resize-control.handle {\n width: 5px;\n height: 5px;\n border: 1px solid #fff;\n border-radius: 1px;\n background-color: var(--xy-resize-background-color, var(--xy-resize-background-color-default));\n translate: -50% -50%;\n}\n.react-flow__resize-control.handle.left {\n left: 0;\n top: 50%;\n}\n.react-flow__resize-control.handle.right {\n left: 100%;\n top: 50%;\n}\n.react-flow__resize-control.handle.top {\n left: 50%;\n top: 0;\n}\n.react-flow__resize-control.handle.bottom {\n left: 50%;\n top: 100%;\n}\n.react-flow__resize-control.handle.top.left {\n left: 0;\n}\n.react-flow__resize-control.handle.bottom.left {\n left: 0;\n}\n.react-flow__resize-control.handle.top.right {\n left: 100%;\n}\n.react-flow__resize-control.handle.bottom.right {\n left: 100%;\n}\n/* line styles */\n.react-flow__resize-control.line {\n border-color: var(--xy-resize-background-color, var(--xy-resize-background-color-default));\n border-width: 0;\n border-style: solid;\n}\n.react-flow__resize-control.line.left,\n.react-flow__resize-control.line.right {\n width: 1px;\n transform: translate(-50%, 0);\n top: 0;\n height: 100%;\n}\n.react-flow__resize-control.line.left {\n left: 0;\n border-left-width: 1px;\n}\n.react-flow__resize-control.line.right {\n left: 100%;\n border-right-width: 1px;\n}\n.react-flow__resize-control.line.top,\n.react-flow__resize-control.line.bottom {\n height: 1px;\n transform: translate(0, -50%);\n left: 0;\n width: 100%;\n}\n.react-flow__resize-control.line.top {\n top: 0;\n border-top-width: 1px;\n}\n.react-flow__resize-control.line.bottom {\n border-bottom-width: 1px;\n top: 100%;\n}\n";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const FLOW_STYLE_ID = "doc-sg-flow-css";
|
|
2
|
+
/** Full text of the injected stylesheet (base.css + extra rules that map onto `--doc-*`). */
|
|
3
|
+
export declare const SCHEMA_GRAPH_FLOW_CSS = "/* this will be exported as base.css and can be used for a basic styling */\n/* these are the necessary styles for React/Svelte Flow, they get used by base.css and style.css */\n.react-flow {\n direction: ltr;\n\n --xy-edge-stroke-default: #b1b1b7;\n --xy-edge-stroke-width-default: 1;\n --xy-edge-stroke-selected-default: #555;\n\n --xy-connectionline-stroke-default: #b1b1b7;\n --xy-connectionline-stroke-width-default: 1;\n\n --xy-attribution-background-color-default: rgba(255, 255, 255, 0.5);\n\n --xy-minimap-background-color-default: #fff;\n --xy-minimap-mask-background-color-default: rgba(240, 240, 240, 0.6);\n --xy-minimap-mask-stroke-color-default: transparent;\n --xy-minimap-mask-stroke-width-default: 1;\n --xy-minimap-node-background-color-default: #e2e2e2;\n --xy-minimap-node-stroke-color-default: transparent;\n --xy-minimap-node-stroke-width-default: 2;\n\n --xy-background-color-default: transparent;\n --xy-background-pattern-dots-color-default: #91919a;\n --xy-background-pattern-lines-color-default: #eee;\n --xy-background-pattern-cross-color-default: #e2e2e2;\n background-color: var(--xy-background-color, var(--xy-background-color-default));\n --xy-node-border-default: 1px solid #bbb;\n --xy-node-border-selected-default: 1px solid #555;\n\n --xy-handle-background-color-default: #333;\n\n --xy-selection-background-color-default: rgba(150, 150, 180, 0.1);\n --xy-selection-border-default: 1px dotted rgba(155, 155, 155, 0.8);\n --xy-resize-background-color-default: #3367d9;\n}\n.react-flow.dark {\n --xy-edge-stroke-default: #3e3e3e;\n --xy-edge-stroke-width-default: 1;\n --xy-edge-stroke-selected-default: #727272;\n\n --xy-connectionline-stroke-default: #b1b1b7;\n --xy-connectionline-stroke-width-default: 1;\n\n --xy-attribution-background-color-default: rgba(150, 150, 150, 0.25);\n\n --xy-minimap-background-color-default: #141414;\n --xy-minimap-mask-background-color-default: rgba(60, 60, 60, 0.6);\n --xy-minimap-mask-stroke-color-default: transparent;\n --xy-minimap-mask-stroke-width-default: 1;\n --xy-minimap-node-background-color-default: #2b2b2b;\n --xy-minimap-node-stroke-color-default: transparent;\n --xy-minimap-node-stroke-width-default: 2;\n\n --xy-background-color-default: #141414;\n --xy-background-pattern-dots-color-default: #555;\n --xy-background-pattern-lines-color-default: #333;\n --xy-background-pattern-cross-color-default: #333;\n --xy-node-color-default: #f8f8f8;\n}\n.react-flow__background {\n background-color: var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));\n pointer-events: none;\n z-index: -1;\n}\n.react-flow__container {\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n}\n.react-flow__pane {\n z-index: 1;\n touch-action: none;\n}\n.react-flow__pane.draggable {\n cursor: grab;\n }\n.react-flow__pane.dragging {\n cursor: grabbing;\n }\n.react-flow__pane.selection {\n cursor: pointer;\n }\n.react-flow__viewport {\n transform-origin: 0 0;\n z-index: 2;\n pointer-events: none;\n}\n.react-flow__renderer {\n z-index: 4;\n}\n.react-flow__selection {\n z-index: 6;\n}\n.react-flow__nodesselection-rect:focus,\n.react-flow__nodesselection-rect:focus-visible {\n outline: none;\n}\n.react-flow__edge-path {\n stroke: var(--xy-edge-stroke, var(--xy-edge-stroke-default));\n stroke-width: var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));\n fill: none;\n}\n.react-flow__connection-path {\n stroke: var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));\n stroke-width: var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));\n fill: none;\n}\n.react-flow .react-flow__edges {\n position: absolute;\n}\n.react-flow .react-flow__edges svg {\n overflow: visible;\n position: absolute;\n pointer-events: none;\n }\n.react-flow__edge {\n pointer-events: visibleStroke;\n}\n.react-flow__edge.selectable {\n cursor: pointer;\n }\n.react-flow__edge.animated path {\n stroke-dasharray: 5;\n animation: dashdraw 0.5s linear infinite;\n }\n.react-flow__edge.animated path.react-flow__edge-interaction {\n stroke-dasharray: none;\n animation: none;\n }\n.react-flow__edge.inactive {\n pointer-events: none;\n }\n.react-flow__edge.selected,\n .react-flow__edge:focus,\n .react-flow__edge:focus-visible {\n outline: none;\n }\n.react-flow__edge.selected .react-flow__edge-path,\n .react-flow__edge.selectable:focus .react-flow__edge-path,\n .react-flow__edge.selectable:focus-visible .react-flow__edge-path {\n stroke: var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default));\n }\n.react-flow__edge-textwrapper {\n pointer-events: all;\n }\n.react-flow__edge .react-flow__edge-text {\n pointer-events: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n }\n/* Arrowhead marker styles - use CSS custom properties as default */\n.react-flow__arrowhead polyline {\n stroke: var(--xy-edge-stroke, var(--xy-edge-stroke-default));\n}\n.react-flow__arrowhead polyline.arrowclosed {\n fill: var(--xy-edge-stroke, var(--xy-edge-stroke-default));\n}\n.react-flow__connection {\n pointer-events: none;\n}\n.react-flow__connection .animated {\n stroke-dasharray: 5;\n animation: dashdraw 0.5s linear infinite;\n }\nsvg.react-flow__connectionline {\n z-index: 1001;\n overflow: visible;\n position: absolute;\n}\n.react-flow__nodes {\n pointer-events: none;\n transform-origin: 0 0;\n}\n.react-flow__node {\n position: absolute;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n pointer-events: all;\n transform-origin: 0 0;\n box-sizing: border-box;\n cursor: default;\n}\n.react-flow__node.selectable {\n cursor: pointer;\n }\n.react-flow__node.draggable {\n cursor: grab;\n pointer-events: all;\n }\n.react-flow__node.draggable.dragging {\n cursor: grabbing;\n }\n.react-flow__nodesselection {\n z-index: 3;\n transform-origin: left top;\n pointer-events: none;\n}\n.react-flow__nodesselection-rect {\n position: absolute;\n pointer-events: all;\n cursor: grab;\n }\n.react-flow__handle {\n position: absolute;\n pointer-events: none;\n min-width: 5px;\n min-height: 5px;\n background-color: var(--xy-handle-background-color, var(--xy-handle-background-color-default));\n}\n.react-flow__handle.connectingfrom {\n pointer-events: all;\n }\n.react-flow__handle.connectionindicator {\n pointer-events: all;\n cursor: crosshair;\n }\n.react-flow__handle-bottom {\n top: auto;\n left: 50%;\n bottom: 0;\n transform: translate(-50%, 50%);\n }\n.react-flow__handle-top {\n top: 0;\n left: 50%;\n transform: translate(-50%, -50%);\n }\n.react-flow__handle-left {\n top: 50%;\n left: 0;\n transform: translate(-50%, -50%);\n }\n.react-flow__handle-right {\n top: 50%;\n right: 0;\n transform: translate(50%, -50%);\n }\n.react-flow__edgeupdater {\n cursor: move;\n pointer-events: all;\n}\n.react-flow__pane.selection .react-flow__panel {\n pointer-events: none;\n}\n.react-flow__panel {\n position: absolute;\n z-index: 5;\n margin: 15px;\n}\n.react-flow__panel.top {\n top: 0;\n }\n.react-flow__panel.bottom {\n bottom: 0;\n }\n.react-flow__panel.top.center, .react-flow__panel.bottom.center {\n left: 50%;\n transform: translateX(-15px) translateX(-50%);\n }\n.react-flow__panel.left {\n left: 0;\n }\n.react-flow__panel.right {\n right: 0;\n }\n.react-flow__panel.left.center, .react-flow__panel.right.center {\n top: 50%;\n transform: translateY(-15px) translateY(-50%);\n }\n.react-flow__attribution {\n font-size: 10px;\n background: var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));\n padding: 2px 3px;\n margin: 0;\n}\n.react-flow__attribution a {\n text-decoration: none;\n color: #999;\n }\n@keyframes dashdraw {\n from {\n stroke-dashoffset: 10;\n }\n}\n.react-flow__edgelabel-renderer {\n position: absolute;\n width: 100%;\n height: 100%;\n pointer-events: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n left: 0;\n top: 0;\n}\n.react-flow__viewport-portal {\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n}\n.react-flow__minimap {\n background: var(\n --xy-minimap-background-color-props,\n var(--xy-minimap-background-color, var(--xy-minimap-background-color-default))\n );\n}\n.react-flow__minimap-svg {\n display: block;\n }\n.react-flow__minimap-mask {\n fill: var(\n --xy-minimap-mask-background-color-props,\n var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default))\n );\n stroke: var(\n --xy-minimap-mask-stroke-color-props,\n var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default))\n );\n stroke-width: var(\n --xy-minimap-mask-stroke-width-props,\n var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default))\n );\n }\n.react-flow__minimap-node {\n fill: var(\n --xy-minimap-node-background-color-props,\n var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default))\n );\n stroke: var(\n --xy-minimap-node-stroke-color-props,\n var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default))\n );\n stroke-width: var(\n --xy-minimap-node-stroke-width-props,\n var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default))\n );\n }\n.react-flow__background-pattern.dots {\n fill: var(\n --xy-background-pattern-color-props,\n var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default))\n );\n }\n.react-flow__background-pattern.lines {\n stroke: var(\n --xy-background-pattern-color-props,\n var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default))\n );\n }\n.react-flow__background-pattern.cross {\n stroke: var(\n --xy-background-pattern-color-props,\n var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default))\n );\n }\n.react-flow__controls {\n display: flex;\n flex-direction: column;\n}\n.react-flow__controls.horizontal {\n flex-direction: row;\n }\n.react-flow__controls-button {\n display: flex;\n justify-content: center;\n align-items: center;\n height: 26px;\n width: 26px;\n padding: 4px;\n }\n.react-flow__controls-button svg {\n width: 100%;\n max-width: 12px;\n max-height: 12px;\n fill: currentColor;\n }\n.react-flow__node-input,\n.react-flow__node-default,\n.react-flow__node-output,\n.react-flow__node-group {\n border: var(--xy-node-border, var(--xy-node-border-default));\n color: var(--xy-node-color, var(--xy-node-color-default));\n}\n.react-flow__node-input.selected,\n .react-flow__node-input:focus,\n .react-flow__node-input:focus-visible,\n .react-flow__node-default.selected,\n .react-flow__node-default:focus,\n .react-flow__node-default:focus-visible,\n .react-flow__node-output.selected,\n .react-flow__node-output:focus,\n .react-flow__node-output:focus-visible,\n .react-flow__node-group.selected,\n .react-flow__node-group:focus,\n .react-flow__node-group:focus-visible {\n outline: none;\n border: var(--xy-node-border-selected, var(--xy-node-border-selected-default));\n }\n.react-flow__nodesselection-rect,\n.react-flow__selection {\n background: var(--xy-selection-background-color, var(--xy-selection-background-color-default));\n border: var(--xy-selection-border, var(--xy-selection-border-default));\n}\n.react-flow__resize-control {\n position: absolute;\n}\n.react-flow__resize-control.left,\n.react-flow__resize-control.right {\n cursor: ew-resize;\n}\n.react-flow__resize-control.top,\n.react-flow__resize-control.bottom {\n cursor: ns-resize;\n}\n.react-flow__resize-control.top.left,\n.react-flow__resize-control.bottom.right {\n cursor: nwse-resize;\n}\n.react-flow__resize-control.bottom.left,\n.react-flow__resize-control.top.right {\n cursor: nesw-resize;\n}\n/* handle styles */\n.react-flow__resize-control.handle {\n width: 5px;\n height: 5px;\n border: 1px solid #fff;\n border-radius: 1px;\n background-color: var(--xy-resize-background-color, var(--xy-resize-background-color-default));\n translate: -50% -50%;\n}\n.react-flow__resize-control.handle.left {\n left: 0;\n top: 50%;\n}\n.react-flow__resize-control.handle.right {\n left: 100%;\n top: 50%;\n}\n.react-flow__resize-control.handle.top {\n left: 50%;\n top: 0;\n}\n.react-flow__resize-control.handle.bottom {\n left: 50%;\n top: 100%;\n}\n.react-flow__resize-control.handle.top.left {\n left: 0;\n}\n.react-flow__resize-control.handle.bottom.left {\n left: 0;\n}\n.react-flow__resize-control.handle.top.right {\n left: 100%;\n}\n.react-flow__resize-control.handle.bottom.right {\n left: 100%;\n}\n/* line styles */\n.react-flow__resize-control.line {\n border-color: var(--xy-resize-background-color, var(--xy-resize-background-color-default));\n border-width: 0;\n border-style: solid;\n}\n.react-flow__resize-control.line.left,\n.react-flow__resize-control.line.right {\n width: 1px;\n transform: translate(-50%, 0);\n top: 0;\n height: 100%;\n}\n.react-flow__resize-control.line.left {\n left: 0;\n border-left-width: 1px;\n}\n.react-flow__resize-control.line.right {\n left: 100%;\n border-right-width: 1px;\n}\n.react-flow__resize-control.line.top,\n.react-flow__resize-control.line.bottom {\n height: 1px;\n transform: translate(0, -50%);\n left: 0;\n width: 100%;\n}\n.react-flow__resize-control.line.top {\n top: 0;\n border-top-width: 1px;\n}\n.react-flow__resize-control.line.bottom {\n border-bottom-width: 1px;\n top: 100%;\n}\n\n.doc-sg-flow .react-flow__controls {\n border-radius: 6px;\n overflow: hidden;\n box-shadow: 0 1px 3px color-mix(in srgb, var(--doc-fg, #000000) 14%, transparent);\n}\n.doc-sg-flow .react-flow__controls-button {\n border: none;\n border-bottom: 1px solid var(--doc-border, #dde3eb);\n background: var(--doc-panel, #ffffff);\n color: var(--doc-fg-3, #5b6271);\n cursor: pointer;\n}\n.doc-sg-flow .react-flow__controls-button:last-child {\n border-bottom: none;\n}\n.doc-sg-flow .react-flow__controls-button:hover {\n background: color-mix(in srgb, var(--doc-fg, #000000) 7%, var(--doc-panel, #ffffff));\n color: var(--doc-fg, #000000);\n}\n.doc-sg-flow .react-flow__controls-button:disabled {\n opacity: 0.45;\n}\n";
|
|
4
|
+
/**
|
|
5
|
+
* Injected once, when a graph is first mounted (no-op if already present).
|
|
6
|
+
* Placed at the start of head = laid down as a base layer weaker than the consumer's
|
|
7
|
+
* stylesheets, so it doesn't override the caller's CSS (theme / its own React Flow usage).
|
|
8
|
+
*/
|
|
9
|
+
export declare const injectSchemaGraphCss: (doc: Document) => void;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Layer that lets the mount layer inject the schema graph (React Flow) stylesheet itself.
|
|
2
|
+
// Without its plain CSS, React Flow loses both the absolute positioning of nodes and the
|
|
3
|
+
// placement of Controls / MiniMap (the figure collapses to just the dotted background), so
|
|
4
|
+
// consumers importing the `./flow` subpath aren't asked to ship the CSS (React embedding meets
|
|
5
|
+
// the same conditions as the global bundle).
|
|
6
|
+
//
|
|
7
|
+
// Only **base.css (structure only)** is included; React Flow's default theme (style.css) is not
|
|
8
|
+
// used: this repo's convention is that colors come from the `--doc-*` variables the consumer
|
|
9
|
+
// injects (same as `var(--doc-*)` in figures). Including the default theme would mix light-only
|
|
10
|
+
// chrome into dark-theme docs and clash with the caller's palette.
|
|
11
|
+
// Only what inline styles can't reach (the Controls buttons = plain `<button>`) is patched,
|
|
12
|
+
// scoped under `.doc-sg-flow` so that a React Flow the consumer uses separately isn't affected.
|
|
13
|
+
import { XYFLOW_BASE_CSS } from "./flow-base-css.generated.js";
|
|
14
|
+
export const FLOW_STYLE_ID = "doc-sg-flow-css";
|
|
15
|
+
const THEME_CSS = `
|
|
16
|
+
.doc-sg-flow .react-flow__controls {
|
|
17
|
+
border-radius: 6px;
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
box-shadow: 0 1px 3px color-mix(in srgb, var(--doc-fg, #000000) 14%, transparent);
|
|
20
|
+
}
|
|
21
|
+
.doc-sg-flow .react-flow__controls-button {
|
|
22
|
+
border: none;
|
|
23
|
+
border-bottom: 1px solid var(--doc-border, #dde3eb);
|
|
24
|
+
background: var(--doc-panel, #ffffff);
|
|
25
|
+
color: var(--doc-fg-3, #5b6271);
|
|
26
|
+
cursor: pointer;
|
|
27
|
+
}
|
|
28
|
+
.doc-sg-flow .react-flow__controls-button:last-child {
|
|
29
|
+
border-bottom: none;
|
|
30
|
+
}
|
|
31
|
+
.doc-sg-flow .react-flow__controls-button:hover {
|
|
32
|
+
background: color-mix(in srgb, var(--doc-fg, #000000) 7%, var(--doc-panel, #ffffff));
|
|
33
|
+
color: var(--doc-fg, #000000);
|
|
34
|
+
}
|
|
35
|
+
.doc-sg-flow .react-flow__controls-button:disabled {
|
|
36
|
+
opacity: 0.45;
|
|
37
|
+
}
|
|
38
|
+
`;
|
|
39
|
+
/** Full text of the injected stylesheet (base.css + extra rules that map onto `--doc-*`). */
|
|
40
|
+
export const SCHEMA_GRAPH_FLOW_CSS = `${XYFLOW_BASE_CSS}${THEME_CSS}`;
|
|
41
|
+
/**
|
|
42
|
+
* Injected once, when a graph is first mounted (no-op if already present).
|
|
43
|
+
* Placed at the start of head = laid down as a base layer weaker than the consumer's
|
|
44
|
+
* stylesheets, so it doesn't override the caller's CSS (theme / its own React Flow usage).
|
|
45
|
+
*/
|
|
46
|
+
export const injectSchemaGraphCss = (doc) => {
|
|
47
|
+
if (doc.getElementById(FLOW_STYLE_ID) != null) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const style = doc.createElement("style");
|
|
51
|
+
style.id = FLOW_STYLE_ID;
|
|
52
|
+
style.textContent = SCHEMA_GRAPH_FLOW_CSS;
|
|
53
|
+
doc.head.prepend(style);
|
|
54
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Coordinates are rounded to one decimal place (keeps the SVG stable and short). */
|
|
2
|
+
export declare const round1: (v: number) => number;
|
|
3
|
+
/** Estimated rendered width (px) of a string. scale = actual font size / 12. */
|
|
4
|
+
export declare const textW: (s: string, scale?: number) => number;
|
|
5
|
+
/**
|
|
6
|
+
* Dependency depth = the level of the column band. `deps[i]` = the set of elements i depends on
|
|
7
|
+
* (the caller decides which direction counts as "dependency" — schema uses "referenced target",
|
|
8
|
+
* graph uses "incoming source").
|
|
9
|
+
* Elements with no dependencies get 0; otherwise 1 + max(level of dependencies).
|
|
10
|
+
* A memoized (settled) DFS plus an in-progress set (onStack) detects cycles; back-edges to an
|
|
11
|
+
* ancestor still being explored don't contribute (they stay -1 and are ignored), so recursion is
|
|
12
|
+
* cut off deterministically. Levels are settled in order from index 0, so the same input always
|
|
13
|
+
* yields the same levels.
|
|
14
|
+
*/
|
|
15
|
+
export declare const depthLevels: (deps: readonly ReadonlySet<number>[]) => number[];
|
|
16
|
+
/**
|
|
17
|
+
* Splits a tall column into several columns (so it doesn't grow too tall). Takes box heights
|
|
18
|
+
* (in original order); returns the positions per column (indices into the input array) — the
|
|
19
|
+
* split is greedy = deterministic.
|
|
20
|
+
*/
|
|
21
|
+
export declare const splitByHeight: (heights: readonly number[], gapY: number, maxColH: number) => number[][];
|
|
22
|
+
/**
|
|
23
|
+
* Orthogonal path (horizontal from the source → vertical along the corridor (cx) → horizontal to
|
|
24
|
+
* the target). Corners are rounded with quadratic curves. Degenerates to a single straight line
|
|
25
|
+
* when sy ≈ ty.
|
|
26
|
+
*/
|
|
27
|
+
export declare const orthPath: (sx: number, sy: number, cx: number, ty: number, tx: number, corner: number) => string;
|
|
28
|
+
/**
|
|
29
|
+
* String → deterministic short id (djb2). Callers pass the model serialized as JSON; the result
|
|
30
|
+
* namespaces SVG classes / marker ids (= multiple graphs on the same page don't collide).
|
|
31
|
+
*/
|
|
32
|
+
export declare const hashId: (src: string) => string;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// Layout helpers shared by the two DSLs that draw static SVG graphs (`schemath` = ER diagram /
|
|
2
|
+
// `graphth` = relationship graph); browser-safe, no dependencies. Text-width estimation, band
|
|
3
|
+
// (level) assignment, column splitting, orthogonal paths and namespace uids are the rules behind
|
|
4
|
+
// "same input, same picture", so they live here as the SoT instead of being written twice.
|
|
5
|
+
/** Coordinates are rounded to one decimal place (keeps the SVG stable and short). */
|
|
6
|
+
export const round1 = (v) => Math.round(v * 10) / 10;
|
|
7
|
+
// Full-width characters (CJK / full-width symbols) count as double width. Approximates 12px mono
|
|
8
|
+
// (font metrics can't be measured, so this is an estimate = deterministic).
|
|
9
|
+
const charW = (code) => (code > 0x2e7f ? 12 : 6.7);
|
|
10
|
+
/** Estimated rendered width (px) of a string. scale = actual font size / 12. */
|
|
11
|
+
export const textW = (s, scale = 1) => [...s].reduce((sum, ch) => sum + charW(ch.codePointAt(0) ?? 0) * scale, 0);
|
|
12
|
+
/**
|
|
13
|
+
* Dependency depth = the level of the column band. `deps[i]` = the set of elements i depends on
|
|
14
|
+
* (the caller decides which direction counts as "dependency" — schema uses "referenced target",
|
|
15
|
+
* graph uses "incoming source").
|
|
16
|
+
* Elements with no dependencies get 0; otherwise 1 + max(level of dependencies).
|
|
17
|
+
* A memoized (settled) DFS plus an in-progress set (onStack) detects cycles; back-edges to an
|
|
18
|
+
* ancestor still being explored don't contribute (they stay -1 and are ignored), so recursion is
|
|
19
|
+
* cut off deterministically. Levels are settled in order from index 0, so the same input always
|
|
20
|
+
* yields the same levels.
|
|
21
|
+
*/
|
|
22
|
+
export const depthLevels = (deps) => {
|
|
23
|
+
const level = new Array(deps.length).fill(0);
|
|
24
|
+
const settled = new Array(deps.length).fill(false);
|
|
25
|
+
const onStack = new Array(deps.length).fill(false);
|
|
26
|
+
const levelOf = (i) => {
|
|
27
|
+
if (settled[i]) {
|
|
28
|
+
return level[i] ?? 0;
|
|
29
|
+
}
|
|
30
|
+
if (onStack[i]) {
|
|
31
|
+
// back-edge (cycle) — this dependency doesn't contribute to the level.
|
|
32
|
+
return -1;
|
|
33
|
+
}
|
|
34
|
+
onStack[i] = true;
|
|
35
|
+
let max = -1;
|
|
36
|
+
for (const d of deps[i] ?? []) {
|
|
37
|
+
max = Math.max(max, levelOf(d));
|
|
38
|
+
}
|
|
39
|
+
onStack[i] = false;
|
|
40
|
+
const result = max < 0 ? 0 : max + 1;
|
|
41
|
+
level[i] = result;
|
|
42
|
+
settled[i] = true;
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
deps.forEach((_, i) => {
|
|
46
|
+
levelOf(i);
|
|
47
|
+
});
|
|
48
|
+
return level;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Splits a tall column into several columns (so it doesn't grow too tall). Takes box heights
|
|
52
|
+
* (in original order); returns the positions per column (indices into the input array) — the
|
|
53
|
+
* split is greedy = deterministic.
|
|
54
|
+
*/
|
|
55
|
+
export const splitByHeight = (heights, gapY, maxColH) => {
|
|
56
|
+
const all = heights.map((_, i) => i);
|
|
57
|
+
const total = heights.reduce((a, b) => a + b, 0) + gapY * Math.max(0, heights.length - 1);
|
|
58
|
+
const count = Math.max(1, Math.ceil(total / maxColH));
|
|
59
|
+
if (count === 1) {
|
|
60
|
+
return [all];
|
|
61
|
+
}
|
|
62
|
+
const target = total / count;
|
|
63
|
+
const cols = [];
|
|
64
|
+
let col = [];
|
|
65
|
+
let colH = 0;
|
|
66
|
+
for (const i of all) {
|
|
67
|
+
const h = heights[i] ?? 0;
|
|
68
|
+
if (col.length > 0 && colH + h > target && cols.length < count - 1) {
|
|
69
|
+
cols.push(col);
|
|
70
|
+
col = [];
|
|
71
|
+
colH = 0;
|
|
72
|
+
}
|
|
73
|
+
col.push(i);
|
|
74
|
+
colH += h + gapY;
|
|
75
|
+
}
|
|
76
|
+
cols.push(col);
|
|
77
|
+
return cols;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Orthogonal path (horizontal from the source → vertical along the corridor (cx) → horizontal to
|
|
81
|
+
* the target). Corners are rounded with quadratic curves. Degenerates to a single straight line
|
|
82
|
+
* when sy ≈ ty.
|
|
83
|
+
*/
|
|
84
|
+
export const orthPath = (sx, sy, cx, ty, tx, corner) => {
|
|
85
|
+
const p = (x, y) => `${round1(x)},${round1(y)}`;
|
|
86
|
+
if (Math.abs(sy - ty) < 0.6) {
|
|
87
|
+
return `M${p(sx, sy)} L${p(tx, ty)}`;
|
|
88
|
+
}
|
|
89
|
+
const outDir = cx >= sx ? 1 : -1;
|
|
90
|
+
const inDir = tx >= cx ? 1 : -1;
|
|
91
|
+
const vDir = ty > sy ? 1 : -1;
|
|
92
|
+
const r1 = Math.min(corner, Math.abs(cx - sx), Math.abs(ty - sy) / 2);
|
|
93
|
+
const r2 = Math.min(corner, Math.abs(tx - cx), Math.abs(ty - sy) / 2);
|
|
94
|
+
return [
|
|
95
|
+
`M${p(sx, sy)}`,
|
|
96
|
+
`L${p(cx - outDir * r1, sy)}`,
|
|
97
|
+
`Q${p(cx, sy)} ${p(cx, sy + vDir * r1)}`,
|
|
98
|
+
`L${p(cx, ty - vDir * r2)}`,
|
|
99
|
+
`Q${p(cx, ty)} ${p(cx + inDir * r2, ty)}`,
|
|
100
|
+
`L${p(tx, ty)}`,
|
|
101
|
+
].join(" ");
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* String → deterministic short id (djb2). Callers pass the model serialized as JSON; the result
|
|
105
|
+
* namespaces SVG classes / marker ids (= multiple graphs on the same page don't collide).
|
|
106
|
+
*/
|
|
107
|
+
export const hashId = (src) => {
|
|
108
|
+
let hash = 5381;
|
|
109
|
+
for (let i = 0; i < src.length; i += 1) {
|
|
110
|
+
hash = (hash * 33 + src.charCodeAt(i)) | 0;
|
|
111
|
+
}
|
|
112
|
+
return (hash >>> 0).toString(36);
|
|
113
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/** Edge kind = line style. solid / dashed are directed (with arrow); undirected has no arrow. */
|
|
2
|
+
export declare const GRAPH_EDGE_KINDS: readonly ["solid", "dashed", "undirected"];
|
|
3
|
+
export type GraphEdgeKind = (typeof GRAPH_EDGE_KINDS)[number];
|
|
4
|
+
/** A single node. If label is omitted, the id is used as the label. No region = not in a frame. */
|
|
5
|
+
export interface GraphNode {
|
|
6
|
+
id: string;
|
|
7
|
+
label: string;
|
|
8
|
+
region?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface GraphEdge {
|
|
11
|
+
from: string;
|
|
12
|
+
to: string;
|
|
13
|
+
kind: GraphEdgeKind;
|
|
14
|
+
label?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Group = one frame. With label = a region (the nodes tagged with that name; drawn as a dashed
|
|
18
|
+
* frame + heading); without label = a standalone group of one node that has no region (no frame
|
|
19
|
+
* drawn). regions partitions all nodes, ordered by first occurrence in the source (= vertical
|
|
20
|
+
* stacking order within a band).
|
|
21
|
+
*/
|
|
22
|
+
export interface GraphRegion {
|
|
23
|
+
label?: string;
|
|
24
|
+
nodes: string[];
|
|
25
|
+
}
|
|
26
|
+
export interface GraphModel {
|
|
27
|
+
nodes: GraphNode[];
|
|
28
|
+
edges: GraphEdge[];
|
|
29
|
+
regions: GraphRegion[];
|
|
30
|
+
}
|
|
31
|
+
/** Error with a DSL line number (0-indexed, relative to the start of the DSL). */
|
|
32
|
+
export interface GraphParseError {
|
|
33
|
+
line: number;
|
|
34
|
+
message: string;
|
|
35
|
+
}
|
|
36
|
+
export interface GraphParseResult {
|
|
37
|
+
model: GraphModel;
|
|
38
|
+
errors: GraphParseError[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Node / edge DSL → graph model + errors. The model is returned as a partial result even when
|
|
42
|
+
* there are errors (so the preview can show "validation errors + as much as can be drawn" at once).
|
|
43
|
+
*/
|
|
44
|
+
export declare const parseGraphSource: (source: string) => GraphParseResult;
|
|
45
|
+
/** model → deterministic short id (namespace for SVG classes / marker ids). */
|
|
46
|
+
export declare const graphUid: (model: GraphModel) => string;
|
|
47
|
+
export interface GraphLayoutNode {
|
|
48
|
+
id: string;
|
|
49
|
+
/** Index into model.nodes (key for linked hover highlighting). */
|
|
50
|
+
index: number;
|
|
51
|
+
label: string;
|
|
52
|
+
x: number;
|
|
53
|
+
y: number;
|
|
54
|
+
w: number;
|
|
55
|
+
h: number;
|
|
56
|
+
/** Label baseline y / center x (the renderer places it with text-anchor=middle). */
|
|
57
|
+
baseline: number;
|
|
58
|
+
textX: number;
|
|
59
|
+
/** Corner radius of the box. */
|
|
60
|
+
radius: number;
|
|
61
|
+
}
|
|
62
|
+
export interface GraphLayoutRegion {
|
|
63
|
+
label: string;
|
|
64
|
+
x: number;
|
|
65
|
+
y: number;
|
|
66
|
+
w: number;
|
|
67
|
+
h: number;
|
|
68
|
+
/** Member node ids (declaration order). */
|
|
69
|
+
members: string[];
|
|
70
|
+
}
|
|
71
|
+
export interface GraphLayoutEdge {
|
|
72
|
+
/** Node index (an index into model.nodes, not into GraphLayout.nodes). */
|
|
73
|
+
from: number;
|
|
74
|
+
to: number;
|
|
75
|
+
kind: GraphEdgeKind;
|
|
76
|
+
/** SVG path d (3 orthogonal segments, rounded corners). */
|
|
77
|
+
d: string;
|
|
78
|
+
label?: string;
|
|
79
|
+
labelX?: number;
|
|
80
|
+
labelY?: number;
|
|
81
|
+
/** Label alignment — centered above a straight line; right of the vertical leg if bent. */
|
|
82
|
+
labelAnchor?: "middle" | "start";
|
|
83
|
+
}
|
|
84
|
+
export interface GraphLayout {
|
|
85
|
+
width: number;
|
|
86
|
+
height: number;
|
|
87
|
+
regions: GraphLayoutRegion[];
|
|
88
|
+
nodes: GraphLayoutNode[];
|
|
89
|
+
edges: GraphLayoutEdge[];
|
|
90
|
+
/** Baseline y of the legend (only when there are dashed / undirected edges). */
|
|
91
|
+
legendY?: number;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Legend text (shown only when there are dashed / undirected edges). html.ts places the
|
|
95
|
+
* markup, but layout also needs the text length to keep the canvas at least this wide (= so the
|
|
96
|
+
* text isn't cut off on a narrow graph), so the text is declared here, in one place.
|
|
97
|
+
*/
|
|
98
|
+
export declare const GRAPH_LEGEND = "Solid = dependency / dashed = optional or async / no arrow = undirected / hover to highlight related edges";
|
|
99
|
+
/** Left edge of the legend / group labels (used by the renderer). */
|
|
100
|
+
export declare const GRAPH_LAYOUT_MARGIN: 16;
|
|
101
|
+
/** Minimum gap between groups stacked in the same band (tests use it to check non-overlap). */
|
|
102
|
+
export declare const GRAPH_GAP_REGION_Y: 40;
|
|
103
|
+
/** Height / padding of a group frame's label area (tests use it to derive the "label top"). */
|
|
104
|
+
export declare const GRAPH_FRAME_LABEL_H: 22;
|
|
105
|
+
export declare const GRAPH_FRAME_PAD: 13;
|
|
106
|
+
/**
|
|
107
|
+
* Graph model → deterministic layout. Dagre's compound graph computes node / region positions and
|
|
108
|
+
* sizes. Edges are then routed between the placed boxes by routeGraphEdges, which keeps the
|
|
109
|
+
* per-kind SVG representation and the hover indices. The Dagre graph is built in model
|
|
110
|
+
* declaration order, so the same input always yields the same coordinates.
|
|
111
|
+
*/
|
|
112
|
+
export declare const layoutGraph: (model: GraphModel) => GraphLayout;
|
|
113
|
+
/**
|
|
114
|
+
* Boxes + edges → routes. A pure function so that layout (at build time) and a future interactive
|
|
115
|
+
* UI that moves boxes share the same rules (= a single SoT for how edges are drawn).
|
|
116
|
+
*/
|
|
117
|
+
export declare const routeGraphEdges: (boxes: readonly GraphLayoutNode[], edges: readonly GraphEdge[]) => GraphLayoutEdge[];
|