flexdesk 0.16.1 → 0.17.1
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/CHANGELOG.md +112 -0
- package/LICENSE +0 -0
- package/README.md +2435 -42
- package/THIRD_PARTY_LICENSES.md +0 -0
- package/canvas.js +18 -0
- package/charts.js +21 -0
- package/core.js +14 -0
- package/css/base.css +1834 -75
- package/css/flexdesk.css +3165 -159
- package/css/overrides.css +16 -0
- package/css/reset.css +0 -0
- package/css/tokens.css +0 -0
- package/dist/canvas.js +6 -239
- package/dist/canvas.js.map +3 -3
- package/dist/charts.js +707 -18
- package/dist/charts.js.map +4 -4
- package/dist/chunk-3PHCPZHT.js +0 -0
- package/dist/chunk-3PHCPZHT.js.map +0 -0
- package/dist/chunk-4A7SJC3T.js +503 -0
- package/dist/chunk-4A7SJC3T.js.map +7 -0
- package/dist/{chunk-6JSOVNID.js → chunk-CVMCZZX2.js} +635 -10
- package/dist/chunk-CVMCZZX2.js.map +7 -0
- package/dist/chunk-D3COLZZ2.js +1311 -0
- package/dist/chunk-D3COLZZ2.js.map +7 -0
- package/dist/chunk-FOOS3T5L.js +0 -0
- package/dist/chunk-FOOS3T5L.js.map +0 -0
- package/dist/{chunk-SN4LSOAR.js → chunk-GOQLR5WR.js} +452 -2
- package/dist/chunk-GOQLR5WR.js.map +7 -0
- package/dist/{chunk-FL5KFNQH.js → chunk-HNU6MM2B.js} +52 -17
- package/dist/chunk-HNU6MM2B.js.map +7 -0
- package/dist/chunk-HYJYYEPK.js +375 -0
- package/dist/chunk-HYJYYEPK.js.map +7 -0
- package/dist/chunk-JKZLNKG6.js +2041 -0
- package/dist/chunk-JKZLNKG6.js.map +7 -0
- package/dist/chunk-JYWURG5T.js +0 -0
- package/dist/chunk-JYWURG5T.js.map +0 -0
- package/dist/{chunk-FBGP5KN5.js → chunk-LWV23YVE.js} +5073 -532
- package/dist/chunk-LWV23YVE.js.map +7 -0
- package/dist/chunk-N7HC3ADV.js +30 -0
- package/dist/chunk-N7HC3ADV.js.map +7 -0
- package/dist/{chunk-RQM5Z2MU.js → chunk-RMTRWWEO.js} +633 -311
- package/dist/chunk-RMTRWWEO.js.map +7 -0
- package/dist/{chunk-NLTOY57M.js → chunk-UURZ37SD.js} +28 -48
- package/dist/chunk-UURZ37SD.js.map +7 -0
- package/dist/{chunk-B5Q53LAJ.js → chunk-UWO43BZU.js} +2 -2
- package/dist/chunk-UWO43BZU.js.map +7 -0
- package/dist/chunk-WVFGV5FT.js +0 -0
- package/dist/chunk-WVFGV5FT.js.map +0 -0
- package/dist/core.js +170 -118
- package/dist/core.js.map +2 -2
- package/dist/editor.js +156 -70
- package/dist/editor.js.map +2 -2
- package/dist/flexdesk.css +3165 -159
- package/dist/flow.js +2789 -306
- package/dist/flow.js.map +4 -4
- package/dist/host.js +109 -3
- package/dist/host.js.map +3 -3
- package/dist/reset.css +0 -0
- package/dist/tile_registry-6WZPTUZV.js +0 -0
- package/dist/tile_registry-6WZPTUZV.js.map +0 -0
- package/dist/tiles.js +657 -234
- package/dist/tiles.js.map +4 -4
- package/dist/tokens.css +0 -0
- package/dist/widgets.js +3290 -2124
- package/dist/widgets.js.map +4 -4
- package/dist/wm.js +1227 -347
- package/dist/wm.js.map +4 -4
- package/editor.js +20 -0
- package/flow.js +21 -0
- package/host.js +14 -0
- package/package.json +12 -1
- package/src/canvas/canvas_adapter.js +5 -0
- package/src/canvas/edge_router.js +0 -0
- package/src/canvas/graph/connector_router.js +0 -0
- package/src/canvas/graph/history_service.js +0 -0
- package/src/canvas/graph/node_platform.js +0 -0
- package/src/canvas/index.js +1 -0
- package/src/canvas/layered_layout.js +244 -0
- package/src/charts/chart_types.js +0 -0
- package/src/charts/data_series_plot_window.js +0 -0
- package/src/charts/downsample.js +2 -2
- package/src/charts/plot_config.js +53 -29
- package/src/charts/plot_config_editor.js +627 -0
- package/src/charts/plot_grid.js +449 -0
- package/src/charts/plot_popout_window.js +103 -317
- package/src/charts/plotly_wrapper.js +22 -2
- package/src/charts/series_transforms.js +206 -0
- package/src/core/event_bus.js +0 -0
- package/src/core/logging.js +1 -1
- package/src/core/settings.js +105 -19
- package/src/core/state_guard.js +93 -51
- package/src/core/state_guard_config.js +85 -74
- package/src/core/state_machine.js +0 -0
- package/src/editor/editor_pane.js +3 -3
- package/src/editor/monaco_editor_factory.js +124 -60
- package/src/editor/monaco_loader.js +103 -28
- package/src/editor/notebook_search.js +0 -0
- package/src/editor/notebook_tab_bar.js +38 -52
- package/src/editor/notebook_undo_manager.js +0 -0
- package/src/editor/split_pane_container.js +6 -3
- package/src/flow/canvas_editor/connections.js +90 -0
- package/src/flow/canvas_editor/editor.js +2351 -153
- package/src/flow/canvas_editor/index.js +2 -1
- package/src/flow/canvas_editor/layout.js +119 -12
- package/src/flow/canvas_editor/strings.js +80 -0
- package/src/flow/kit/always_before.js +0 -0
- package/src/flow/kit/catalogue.js +97 -3
- package/src/flow/kit/chip_input.js +0 -0
- package/src/flow/kit/dom.js +0 -0
- package/src/flow/kit/findings.js +0 -0
- package/src/flow/kit/history.js +0 -0
- package/src/flow/kit/index.js +3 -3
- package/src/flow/kit/keys.js +7 -1
- package/src/flow/kit/logic_graph.js +97 -15
- package/src/flow/kit/references.js +0 -0
- package/src/flow/kit/settings_panel.js +0 -0
- package/src/flow/kit/settings_schema.js +2 -1
- package/src/flow/kit/step_picker.js +0 -0
- package/src/flow/kit/strings.js +3 -1
- package/src/flow/kit/value_picker.js +0 -0
- package/src/flow/kit/widgets.js +86 -109
- package/src/flow/lanes/editor.js +136 -14
- package/src/flow/lanes/index.js +3 -1
- package/src/flow/lanes/layout.js +0 -0
- package/src/flow/lanes/pipeline.js +44 -2
- package/src/flow/lanes/preview.js +0 -0
- package/src/flow/lanes/strings.js +1 -0
- package/src/flow/outline/editor.js +0 -0
- package/src/flow/outline/index.js +0 -0
- package/src/flow/outline/mapping.js +0 -0
- package/src/flow/outline/menu.js +0 -0
- package/src/flow/outline/operations.js +0 -0
- package/src/flow/outline/recognise.js +0 -0
- package/src/flow/outline/strings.js +0 -0
- package/src/help/help_modal.js +168 -42
- package/src/help/help_registry.js +12 -1
- package/src/host/external_links.js +0 -0
- package/src/host/file_picker.js +117 -0
- package/src/host/host.js +10 -2
- package/src/host/photino_host.js +9 -0
- package/src/host/photino_host.md +21 -3
- package/src/host/pywebview_host.js +10 -0
- package/src/tiles/chart_tiles.js +53 -245
- package/src/tiles/config_schema.js +8 -0
- package/src/tiles/figure_tile.js +322 -0
- package/src/tiles/layout_persistence.js +3 -3
- package/src/tiles/list_tiles.js +7 -7
- package/src/tiles/scope_picker.js +0 -0
- package/src/tiles/tile_base.js +1 -1
- package/src/tiles/tile_config_form.js +442 -0
- package/src/tiles/tile_grid.js +2 -0
- package/src/tiles/tile_registry.js +0 -0
- package/src/tiling/bottom_panel_tabs.js +67 -99
- package/src/tiling/command_palette.js +64 -19
- package/src/tiling/content_registry.js +4 -1
- package/src/tiling/desktops.js +11 -1
- package/src/tiling/entity_sources.js +0 -0
- package/src/tiling/keymap.js +403 -128
- package/src/tiling/kind_taxonomy.js +78 -0
- package/src/tiling/landing_table.js +0 -0
- package/src/tiling/loading_overlay.js +0 -0
- package/src/tiling/nav_panel.js +59 -10
- package/src/tiling/page_factory.js +5 -5
- package/src/tiling/panel_availability.js +49 -0
- package/src/tiling/panel_keys.js +0 -0
- package/src/tiling/shell.js +114 -12
- package/src/tiling/tab_strip.js +0 -0
- package/src/tiling/tile_breadcrumb.js +0 -0
- package/src/tiling/tile_renderer.js +105 -9
- package/src/tiling/tile_tab_menu.js +0 -0
- package/src/tiling/tile_tree.js +0 -0
- package/src/tiling/wm.js +562 -30
- package/src/tiling/zoom.js +0 -0
- package/src/ui/base/component_base.js +0 -0
- package/src/ui/base/controller_base.js +0 -0
- package/src/ui/base/page_base.js +0 -0
- package/src/ui/components/about_dialog.js +0 -0
- package/src/ui/components/action_dropdown.js +30 -2
- package/src/ui/components/alert_log.js +0 -0
- package/src/ui/components/alerts_pane.js +0 -0
- package/src/ui/components/attribute_list_editor.js +0 -0
- package/src/ui/components/autocomplete_field.js +0 -0
- package/src/ui/components/cell_editor_host.js +293 -0
- package/src/ui/components/cell_editors.js +480 -0
- package/src/ui/components/cell_grid.js +761 -0
- package/src/ui/components/cell_paste.js +243 -0
- package/src/ui/components/cell_selection.js +220 -0
- package/src/ui/components/choice_controls.js +351 -0
- package/src/ui/components/color_field.js +211 -0
- package/src/ui/components/color_list_field.js +210 -0
- package/src/ui/components/column_fit.js +0 -0
- package/src/ui/components/column_groups.js +314 -0
- package/src/ui/components/column_order.js +142 -0
- package/src/ui/components/computing_status_window.js +98 -25
- package/src/ui/components/confirm_dialog.js +81 -38
- package/src/ui/components/context_menu.js +2 -2
- package/src/ui/components/conversation_view.js +440 -0
- package/src/ui/components/crosstab.js +289 -0
- package/src/ui/components/data_table.js +696 -71
- package/src/ui/components/detail_header.js +22 -11
- package/src/ui/components/document_outline.js +397 -0
- package/src/ui/components/drag_reorder.js +0 -0
- package/src/ui/components/fact_table.js +0 -0
- package/src/ui/components/fill_handle.js +322 -0
- package/src/ui/components/gallery_picker.js +19 -8
- package/src/ui/components/header_actions.js +55 -0
- package/src/ui/components/inline_renamer.js +0 -0
- package/src/ui/components/job_progress.js +51 -0
- package/src/ui/components/managed_window.js +27 -4
- package/src/ui/components/menu_bar.js +745 -0
- package/src/ui/components/modal.js +449 -75
- package/src/ui/components/notification_history.js +3 -3
- package/src/ui/components/progress.js +483 -0
- package/src/ui/components/record_list.js +0 -0
- package/src/ui/components/row_activation.js +0 -0
- package/src/ui/components/section_stack.js +298 -0
- package/src/ui/components/series.js +173 -0
- package/src/ui/components/settings_view.js +634 -0
- package/src/ui/components/slide_out_panel.js +43 -6
- package/src/ui/components/slider_field.js +275 -18
- package/src/ui/components/sortable_list.js +0 -0
- package/src/ui/components/staged_edits.js +361 -0
- package/src/ui/components/staged_history.js +172 -0
- package/src/ui/components/table_filter_chips.js +0 -0
- package/src/ui/components/table_state_store.js +0 -0
- package/src/ui/components/table_structure.js +182 -0
- package/src/ui/components/table_values.js +0 -0
- package/src/ui/components/tabs.js +497 -0
- package/src/ui/components/tag_input.js +215 -0
- package/src/ui/components/toast.js +25 -8
- package/src/ui/components/toggle_field.js +175 -0
- package/src/ui/components/tree_view.js +55 -34
- package/src/ui/components/tsv.js +74 -0
- package/src/ui/components/window_taskbar.js +0 -0
- package/src/ui/components/wizard.js +563 -0
- package/src/ui/controllers/window_chrome_controller.js +2 -2
- package/src/ui/notification_center.js +375 -119
- package/src/ui/utils/auto_scrollbars.js +0 -0
- package/src/ui/utils/markdown.js +709 -0
- package/src/ui/utils/native_context_menu.js +0 -0
- package/src/ui/utils/overlay_scrollbar.js +16 -12
- package/src/ui/utils/raf_resize_observer.js +0 -0
- package/src/ui/utils/scroll_lock.js +0 -0
- package/src/ui/utils/strip_scroll.js +55 -0
- package/src/ui/utils/tooltip_service.js +0 -8
- package/tiles.js +27 -0
- package/widgets.js +69 -0
- package/wm.js +28 -0
- package/dist/chunk-6JSOVNID.js.map +0 -7
- package/dist/chunk-B5Q53LAJ.js.map +0 -7
- package/dist/chunk-FBGP5KN5.js.map +0 -7
- package/dist/chunk-FL5KFNQH.js.map +0 -7
- package/dist/chunk-NLTOY57M.js.map +0 -7
- package/dist/chunk-NNFTETK3.js +0 -633
- package/dist/chunk-NNFTETK3.js.map +0 -7
- package/dist/chunk-O5OHMWBB.js +0 -284
- package/dist/chunk-O5OHMWBB.js.map +0 -7
- package/dist/chunk-RQM5Z2MU.js.map +0 -7
- package/dist/chunk-SN4LSOAR.js.map +0 -7
- package/dist/chunk-W6FBJLPW.js +0 -367
- package/dist/chunk-W6FBJLPW.js.map +0 -7
- package/src/ui/controllers/panel_state_machine.js +0 -634
|
@@ -4,6 +4,10 @@ var MAX_SCALE = 4;
|
|
|
4
4
|
var COARSE_GRID_EVERY = 5;
|
|
5
5
|
var SUB_PIXEL = 0.5;
|
|
6
6
|
var CanvasAdapter = class {
|
|
7
|
+
/** The zoom limits every `setViewport`, `zoomAt` and `fit` clamps to, for an
|
|
8
|
+
* embedder whose own zoom controls must stop where the kernel stops. */
|
|
9
|
+
static MIN_SCALE = MIN_SCALE;
|
|
10
|
+
static MAX_SCALE = MAX_SCALE;
|
|
7
11
|
/**
|
|
8
12
|
* @param {object} o
|
|
9
13
|
* @param {HTMLElement} o.container the box the canvas fills (it needs a height)
|
|
@@ -518,6 +522,448 @@ function arrange(nodes, edges, { columnGap = 340, rowGap = 40 } = {}) {
|
|
|
518
522
|
return positions;
|
|
519
523
|
}
|
|
520
524
|
|
|
525
|
+
// src/canvas/layered_layout.js
|
|
526
|
+
var DEFAULT_SIZE = Object.freeze({ width: 160, height: 80 });
|
|
527
|
+
var defaultSizeOf = (node) => ({
|
|
528
|
+
width: Number(node?.width) || DEFAULT_SIZE.width,
|
|
529
|
+
height: Number(node?.height) || DEFAULT_SIZE.height
|
|
530
|
+
});
|
|
531
|
+
function crossingsBetween(pairs) {
|
|
532
|
+
let n = 0;
|
|
533
|
+
for (let i = 0; i < pairs.length; i++) {
|
|
534
|
+
const [a1, b1] = pairs[i];
|
|
535
|
+
for (let j = i + 1; j < pairs.length; j++) {
|
|
536
|
+
const [a2, b2] = pairs[j];
|
|
537
|
+
if ((a1 - a2) * (b1 - b2) < 0) n++;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return n;
|
|
541
|
+
}
|
|
542
|
+
function layeredLayout(nodes, edges, {
|
|
543
|
+
rank = null,
|
|
544
|
+
sizeOf = null,
|
|
545
|
+
columnGap = 64,
|
|
546
|
+
rowGap = 32,
|
|
547
|
+
componentGap = 80,
|
|
548
|
+
passes = 8
|
|
549
|
+
} = {}) {
|
|
550
|
+
const list = [];
|
|
551
|
+
const index = /* @__PURE__ */ new Map();
|
|
552
|
+
for (const node of Array.isArray(nodes) ? nodes : []) {
|
|
553
|
+
if (!node || node.id === void 0 || node.id === null || index.has(String(node.id))) continue;
|
|
554
|
+
index.set(String(node.id), list.length);
|
|
555
|
+
list.push(node);
|
|
556
|
+
}
|
|
557
|
+
const count = list.length;
|
|
558
|
+
const positions = /* @__PURE__ */ new Map();
|
|
559
|
+
if (!count) return positions;
|
|
560
|
+
const hint = list.map((n) => {
|
|
561
|
+
const r = typeof rank === "function" ? rank(n) : null;
|
|
562
|
+
return r === "source" || r === "sink" ? r : null;
|
|
563
|
+
});
|
|
564
|
+
const measure = typeof sizeOf === "function" ? sizeOf : defaultSizeOf;
|
|
565
|
+
const size = list.map((n) => {
|
|
566
|
+
const s = measure(n) || {};
|
|
567
|
+
return { width: Math.max(0, Number(s.width) || 0), height: Math.max(0, Number(s.height) || 0) };
|
|
568
|
+
});
|
|
569
|
+
const out = Array.from({ length: count }, () => []);
|
|
570
|
+
const near = Array.from({ length: count }, () => []);
|
|
571
|
+
const seen = /* @__PURE__ */ new Set();
|
|
572
|
+
const lines = [];
|
|
573
|
+
for (const e of Array.isArray(edges) ? edges : []) {
|
|
574
|
+
const u = index.get(String(e?.from));
|
|
575
|
+
const v = index.get(String(e?.to));
|
|
576
|
+
if (u === void 0 || v === void 0 || u === v) continue;
|
|
577
|
+
const key = `${u}>${v}`;
|
|
578
|
+
if (seen.has(key)) continue;
|
|
579
|
+
seen.add(key);
|
|
580
|
+
out[u].push(v);
|
|
581
|
+
lines.push([u, v]);
|
|
582
|
+
if (!seen.has(`${u}~${v}`)) {
|
|
583
|
+
seen.add(`${u}~${v}`);
|
|
584
|
+
seen.add(`${v}~${u}`);
|
|
585
|
+
near[u].push(v);
|
|
586
|
+
near[v].push(u);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
const componentOf = new Int32Array(count).fill(-1);
|
|
590
|
+
const components = [];
|
|
591
|
+
for (let s = 0; s < count; s++) {
|
|
592
|
+
if (componentOf[s] >= 0) continue;
|
|
593
|
+
const members = [];
|
|
594
|
+
const stack = [s];
|
|
595
|
+
componentOf[s] = components.length;
|
|
596
|
+
while (stack.length) {
|
|
597
|
+
const u = stack.pop();
|
|
598
|
+
members.push(u);
|
|
599
|
+
for (const v of near[u]) if (componentOf[v] < 0) {
|
|
600
|
+
componentOf[v] = components.length;
|
|
601
|
+
stack.push(v);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
members.sort((a, b) => a - b);
|
|
605
|
+
components.push(members);
|
|
606
|
+
}
|
|
607
|
+
const ordered = components.map((m, i) => ({ m, i })).sort((a, b) => b.m.length - a.m.length || a.i - b.i);
|
|
608
|
+
const linesOf = components.map(() => []);
|
|
609
|
+
for (const line of lines) linesOf[componentOf[line[0]]].push(line);
|
|
610
|
+
const reversed = /* @__PURE__ */ new Set();
|
|
611
|
+
const state = new Uint8Array(count);
|
|
612
|
+
for (let s = 0; s < count; s++) {
|
|
613
|
+
if (state[s]) continue;
|
|
614
|
+
const stack = [[s, 0]];
|
|
615
|
+
state[s] = 1;
|
|
616
|
+
while (stack.length) {
|
|
617
|
+
const top2 = stack[stack.length - 1];
|
|
618
|
+
const [u, k] = top2;
|
|
619
|
+
if (k < out[u].length) {
|
|
620
|
+
top2[1] = k + 1;
|
|
621
|
+
const v = out[u][k];
|
|
622
|
+
if (state[v] === 1) reversed.add(`${u}>${v}`);
|
|
623
|
+
else if (state[v] === 0) {
|
|
624
|
+
state[v] = 1;
|
|
625
|
+
stack.push([v, 0]);
|
|
626
|
+
}
|
|
627
|
+
} else {
|
|
628
|
+
state[u] = 2;
|
|
629
|
+
stack.pop();
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
const preds = Array.from({ length: count }, () => []);
|
|
634
|
+
const succs = Array.from({ length: count }, () => []);
|
|
635
|
+
for (const [u0, v0] of lines) {
|
|
636
|
+
const [u, v] = reversed.has(`${u0}>${v0}`) ? [v0, u0] : [u0, v0];
|
|
637
|
+
if (hint[v] === "source" || hint[u] === "sink") continue;
|
|
638
|
+
preds[v].push(u);
|
|
639
|
+
succs[u].push(v);
|
|
640
|
+
}
|
|
641
|
+
const layer = new Int32Array(count);
|
|
642
|
+
const waiting = preds.map((p) => p.length);
|
|
643
|
+
const queue = [];
|
|
644
|
+
for (let u = 0; u < count; u++) if (!waiting[u]) queue.push(u);
|
|
645
|
+
for (let q = 0; q < queue.length; q++) {
|
|
646
|
+
const u = queue[q];
|
|
647
|
+
for (const v of succs[u]) {
|
|
648
|
+
if (layer[u] + 1 > layer[v]) layer[v] = layer[u] + 1;
|
|
649
|
+
if (--waiting[v] === 0) queue.push(v);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
let top = 0;
|
|
653
|
+
for (const { m, i: c } of ordered) {
|
|
654
|
+
let last = -1;
|
|
655
|
+
for (const u of m) if (hint[u] !== "sink") last = Math.max(last, hint[u] === "source" ? 0 : layer[u]);
|
|
656
|
+
for (const u of m) {
|
|
657
|
+
if (hint[u] === "source") layer[u] = 0;
|
|
658
|
+
else if (hint[u] === "sink") layer[u] = last + 1;
|
|
659
|
+
}
|
|
660
|
+
const used = [...new Set(m.map((u) => layer[u]))].sort((a, b) => a - b);
|
|
661
|
+
const renumber = new Map(used.map((l, i) => [l, i]));
|
|
662
|
+
const columns = used.map(() => []);
|
|
663
|
+
for (const u of m) {
|
|
664
|
+
layer[u] = renumber.get(layer[u]);
|
|
665
|
+
columns[layer[u]].push(u);
|
|
666
|
+
}
|
|
667
|
+
const place = /* @__PURE__ */ new Map();
|
|
668
|
+
const remember = () => {
|
|
669
|
+
for (const c2 of columns) c2.forEach((u, i) => place.set(u, i));
|
|
670
|
+
};
|
|
671
|
+
remember();
|
|
672
|
+
const between = columns.map(() => []);
|
|
673
|
+
for (const [u, v] of linesOf[c]) {
|
|
674
|
+
const a = Math.min(layer[u], layer[v]);
|
|
675
|
+
if (Math.abs(layer[u] - layer[v]) === 1) between[a].push(layer[u] < layer[v] ? [u, v] : [v, u]);
|
|
676
|
+
}
|
|
677
|
+
const crossings = () => {
|
|
678
|
+
let n = 0;
|
|
679
|
+
for (let l = 0; l + 1 < columns.length; l++) {
|
|
680
|
+
n += crossingsBetween(between[l].map(([u, v]) => [place.get(u), place.get(v)]));
|
|
681
|
+
}
|
|
682
|
+
return n;
|
|
683
|
+
};
|
|
684
|
+
const sweep = (l, from) => {
|
|
685
|
+
const column = columns[l];
|
|
686
|
+
const centre = /* @__PURE__ */ new Map();
|
|
687
|
+
for (const u of column) {
|
|
688
|
+
let sum = 0;
|
|
689
|
+
let k = 0;
|
|
690
|
+
for (const v of near[u]) {
|
|
691
|
+
if (from(layer[v])) {
|
|
692
|
+
sum += place.get(v);
|
|
693
|
+
k++;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
centre.set(u, k ? sum / k : place.get(u));
|
|
697
|
+
}
|
|
698
|
+
column.sort((a, b) => centre.get(a) - centre.get(b) || place.get(a) - place.get(b));
|
|
699
|
+
column.forEach((u, i) => place.set(u, i));
|
|
700
|
+
};
|
|
701
|
+
let best = crossings();
|
|
702
|
+
let bestColumns = columns.map((c2) => [...c2]);
|
|
703
|
+
for (let p = 0; p < passes && best > 0; p++) {
|
|
704
|
+
for (let l = 1; l < columns.length; l++) sweep(l, (x2) => x2 < l);
|
|
705
|
+
for (let l = columns.length - 2; l >= 0; l--) sweep(l, (x2) => x2 > l);
|
|
706
|
+
const now = crossings();
|
|
707
|
+
if (now < best) {
|
|
708
|
+
best = now;
|
|
709
|
+
bestColumns = columns.map((c2) => [...c2]);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
const widths = bestColumns.map((c2) => Math.max(0, ...c2.map((u) => size[u].width)));
|
|
713
|
+
const heights = bestColumns.map((c2) => c2.reduce((h, u) => h + size[u].height, 0) + rowGap * Math.max(0, c2.length - 1));
|
|
714
|
+
const tallest = Math.max(0, ...heights);
|
|
715
|
+
let x = 0;
|
|
716
|
+
bestColumns.forEach((c2, l) => {
|
|
717
|
+
let y = top + (tallest - heights[l]) / 2;
|
|
718
|
+
for (const u of c2) {
|
|
719
|
+
positions.set(String(list[u].id), { x, y });
|
|
720
|
+
y += size[u].height + rowGap;
|
|
721
|
+
}
|
|
722
|
+
x += widths[l] + columnGap;
|
|
723
|
+
});
|
|
724
|
+
top += tallest + componentGap;
|
|
725
|
+
}
|
|
726
|
+
return positions;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// src/canvas/graph/node_platform.js
|
|
730
|
+
var NodePlatform = class {
|
|
731
|
+
/**
|
|
732
|
+
* @param {object} [options]
|
|
733
|
+
* @param {(node: object) => object[]} [options.collapsedPorts] the ports a COLLAPSED node
|
|
734
|
+
* still offers; by default none
|
|
735
|
+
*/
|
|
736
|
+
constructor({ collapsedPorts = null } = {}) {
|
|
737
|
+
this.nodes = /* @__PURE__ */ new Map();
|
|
738
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
739
|
+
this.collapsedPorts = typeof collapsedPorts === "function" ? collapsedPorts : null;
|
|
740
|
+
}
|
|
741
|
+
on(event, handler) {
|
|
742
|
+
if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
743
|
+
this.listeners.get(event).add(handler);
|
|
744
|
+
return () => this.listeners.get(event).delete(handler);
|
|
745
|
+
}
|
|
746
|
+
emit(event, payload) {
|
|
747
|
+
for (const handler of this.listeners.get(event) || []) handler(payload);
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* Replace the whole graph. Hydration, not an edit — see `HistoryService`.
|
|
751
|
+
*
|
|
752
|
+
* Each node is `{id, position?, size?, collapsed?, ports?, …}`: the position
|
|
753
|
+
* is copied (a missing one is (0, 0)), `size` is `{w, h}` or null, `ports`
|
|
754
|
+
* an array (none when absent), and every other key is kept as it is.
|
|
755
|
+
*/
|
|
756
|
+
hydrate(nodes) {
|
|
757
|
+
this.nodes.clear();
|
|
758
|
+
for (const raw of Array.isArray(nodes) ? nodes : []) {
|
|
759
|
+
if (!raw || raw.id === void 0 || raw.id === null) continue;
|
|
760
|
+
const id = raw.id;
|
|
761
|
+
this.nodes.set(id, {
|
|
762
|
+
...raw,
|
|
763
|
+
id,
|
|
764
|
+
// `size` and `collapsed` are in the snapshot, not derived: at
|
|
765
|
+
// hundreds of nodes a node showing forty ports is unreadable, and
|
|
766
|
+
// a collapsed node's ports fold away.
|
|
767
|
+
position: raw.position ? { x: raw.position.x, y: raw.position.y } : { x: 0, y: 0 },
|
|
768
|
+
size: raw.size ? { w: raw.size.w, h: raw.size.h } : null,
|
|
769
|
+
collapsed: Boolean(raw.collapsed),
|
|
770
|
+
ports: Array.isArray(raw.ports) ? raw.ports : []
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
this.emit("hydrated", { count: this.nodes.size });
|
|
774
|
+
}
|
|
775
|
+
get(id) {
|
|
776
|
+
return this.nodes.get(id);
|
|
777
|
+
}
|
|
778
|
+
all() {
|
|
779
|
+
return [...this.nodes.values()];
|
|
780
|
+
}
|
|
781
|
+
port(nodeId, portId) {
|
|
782
|
+
return this.nodes.get(nodeId)?.ports.find((p) => p.id === portId) || null;
|
|
783
|
+
}
|
|
784
|
+
setPosition(id, position, { silent = false } = {}) {
|
|
785
|
+
const node = this.nodes.get(id);
|
|
786
|
+
if (!node) return null;
|
|
787
|
+
const before = { ...node.position };
|
|
788
|
+
node.position = { ...position };
|
|
789
|
+
if (!silent) this.emit("moved", { id, before, after: { ...position } });
|
|
790
|
+
return before;
|
|
791
|
+
}
|
|
792
|
+
setCollapsed(id, collapsed, { silent = false } = {}) {
|
|
793
|
+
const node = this.nodes.get(id);
|
|
794
|
+
if (!node) return null;
|
|
795
|
+
const before = node.collapsed;
|
|
796
|
+
node.collapsed = Boolean(collapsed);
|
|
797
|
+
if (!silent) this.emit("collapsed", { id, before, after: node.collapsed });
|
|
798
|
+
return before;
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Ports that are visible right now.
|
|
802
|
+
*
|
|
803
|
+
* A collapsed node offers only what `collapsedPorts` says it keeps (by
|
|
804
|
+
* default nothing). Answering from one place is what stops a renderer and
|
|
805
|
+
* the legality guard disagreeing about what can be dropped on.
|
|
806
|
+
*/
|
|
807
|
+
visiblePorts(id) {
|
|
808
|
+
const node = this.nodes.get(id);
|
|
809
|
+
if (!node) return [];
|
|
810
|
+
if (node.collapsed) return this.collapsedPorts ? this.collapsedPorts(node) : [];
|
|
811
|
+
return node.ports;
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
// src/canvas/graph/connector_router.js
|
|
816
|
+
var CONNECTOR_STRINGS = Object.freeze({
|
|
817
|
+
nodeGone: "That node is no longer on the canvas.",
|
|
818
|
+
portGone: "That port is no longer on the canvas.",
|
|
819
|
+
portDisabled: "That port cannot be connected.",
|
|
820
|
+
selfReference: "A node cannot connect to itself on this canvas.",
|
|
821
|
+
portFull: (max) => max === 1 ? "That port already carries its one connection." : `That port already carries its ${max} connections.`
|
|
822
|
+
});
|
|
823
|
+
var say = (strings, key, ...args) => {
|
|
824
|
+
const s = strings[key];
|
|
825
|
+
return typeof s === "function" ? s(...args) : String(s);
|
|
826
|
+
};
|
|
827
|
+
var defaultEndsOf = (edge) => ({ from: edge?.fromPort ?? null, to: edge?.toPort ?? null });
|
|
828
|
+
function capacityOf(port) {
|
|
829
|
+
if (Number.isFinite(port?.maxConnections)) return port.maxConnections;
|
|
830
|
+
if (port?.allowMultiple === false) return 1;
|
|
831
|
+
return Infinity;
|
|
832
|
+
}
|
|
833
|
+
var ConnectorRouter = class {
|
|
834
|
+
/**
|
|
835
|
+
* @param {object} o
|
|
836
|
+
* @param {object} o.platform a `NodePlatform`
|
|
837
|
+
* @param {boolean} [o.selfReference] may a node connect to itself
|
|
838
|
+
* @param {(ctx: object) => object|null|undefined} [o.policy] the embedder's rules, asked last
|
|
839
|
+
* @param {(edge: object) => {from, to}} [o.endsOf] the port ids an edge uses at each end
|
|
840
|
+
* @param {('source'|'target')[]} [o.disabledEnds] which ends a disabled port refuses
|
|
841
|
+
* @param {object} [o.strings] the generic refusals' words
|
|
842
|
+
*/
|
|
843
|
+
constructor({
|
|
844
|
+
platform,
|
|
845
|
+
selfReference = false,
|
|
846
|
+
policy = null,
|
|
847
|
+
endsOf = null,
|
|
848
|
+
disabledEnds = ["source", "target"],
|
|
849
|
+
strings = null
|
|
850
|
+
} = {}) {
|
|
851
|
+
this.platform = platform;
|
|
852
|
+
this.selfReference = selfReference;
|
|
853
|
+
this.policy = typeof policy === "function" ? policy : null;
|
|
854
|
+
this.endsOf = typeof endsOf === "function" ? endsOf : defaultEndsOf;
|
|
855
|
+
this.disabledEnds = new Set(disabledEnds);
|
|
856
|
+
this.strings = Object.freeze({ ...CONNECTOR_STRINGS, ...strings || {} });
|
|
857
|
+
this.edges = /* @__PURE__ */ new Map();
|
|
858
|
+
}
|
|
859
|
+
hydrate(edges) {
|
|
860
|
+
this.edges.clear();
|
|
861
|
+
for (const edge of edges) this.edges.set(edge.id, edge);
|
|
862
|
+
}
|
|
863
|
+
/** Every edge already touching this node, in either direction. */
|
|
864
|
+
edgesFor(nodeId) {
|
|
865
|
+
return [...this.edges.values()].filter((e) => e.from === nodeId || e.to === nodeId);
|
|
866
|
+
}
|
|
867
|
+
/** How many edges (applied and `pending`) already use this port at this node. */
|
|
868
|
+
connectionsAt(nodeId, portId, { pendingEdges = [] } = {}) {
|
|
869
|
+
let n = 0;
|
|
870
|
+
for (const edge of [...this.edges.values(), ...pendingEdges]) {
|
|
871
|
+
const ends = this.endsOf(edge) || {};
|
|
872
|
+
if (edge.from === nodeId && ends.from === portId) n += 1;
|
|
873
|
+
if (edge.to === nodeId && ends.to === portId) n += 1;
|
|
874
|
+
}
|
|
875
|
+
return n;
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Can this drop become an edge?
|
|
879
|
+
*
|
|
880
|
+
* `source` and `target` are `{nodeId, portId}`. The answer is a verdict the
|
|
881
|
+
* caller can render directly — the reason strings ARE the notice text, so a
|
|
882
|
+
* policy should name the objects rather than describe the rule.
|
|
883
|
+
*/
|
|
884
|
+
canConnect(source, target, { pendingEdges = [] } = {}) {
|
|
885
|
+
const S = this.strings;
|
|
886
|
+
const fromNode = this.platform.get(source.nodeId);
|
|
887
|
+
const toNode = this.platform.get(target.nodeId);
|
|
888
|
+
if (!fromNode || !toNode) return { ok: false, reason: say(S, "nodeGone") };
|
|
889
|
+
const fromPort = this.platform.port(source.nodeId, source.portId);
|
|
890
|
+
const toPort = this.platform.port(target.nodeId, target.portId);
|
|
891
|
+
if (!fromPort || !toPort) return { ok: false, reason: say(S, "portGone") };
|
|
892
|
+
if (fromPort.disabled && this.disabledEnds.has("source")) {
|
|
893
|
+
return { ok: false, reason: fromPort.disabledReason || say(S, "portDisabled") };
|
|
894
|
+
}
|
|
895
|
+
if (toPort.disabled && this.disabledEnds.has("target")) {
|
|
896
|
+
return { ok: false, reason: toPort.disabledReason || say(S, "portDisabled") };
|
|
897
|
+
}
|
|
898
|
+
const selfReference = fromNode.id === toNode.id;
|
|
899
|
+
if (selfReference && !this.selfReference) return { ok: false, reason: say(S, "selfReference") };
|
|
900
|
+
for (const [node, port] of [[fromNode, fromPort], [toNode, toPort]]) {
|
|
901
|
+
const max = capacityOf(port);
|
|
902
|
+
if (max !== Infinity && this.connectionsAt(node.id, port.id, { pendingEdges }) >= max) {
|
|
903
|
+
return { ok: false, reason: say(S, "portFull", max) };
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
if (this.policy) {
|
|
907
|
+
const verdict = this.policy({
|
|
908
|
+
source,
|
|
909
|
+
target,
|
|
910
|
+
fromNode,
|
|
911
|
+
toNode,
|
|
912
|
+
fromPort,
|
|
913
|
+
toPort,
|
|
914
|
+
pendingEdges,
|
|
915
|
+
selfReference,
|
|
916
|
+
edges: [...this.edges.values()],
|
|
917
|
+
router: this
|
|
918
|
+
});
|
|
919
|
+
if (verdict && typeof verdict === "object") return verdict;
|
|
920
|
+
}
|
|
921
|
+
return { ok: true, selfReference };
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* Record a STAGED edge. Nothing here talks to a server — the embedder turns
|
|
925
|
+
* a staged edge into whatever its own write is, and only that makes it real.
|
|
926
|
+
*/
|
|
927
|
+
stage(edge) {
|
|
928
|
+
this.edges.set(edge.id, edge);
|
|
929
|
+
return edge;
|
|
930
|
+
}
|
|
931
|
+
unstage(id) {
|
|
932
|
+
const edge = this.edges.get(id);
|
|
933
|
+
this.edges.delete(id);
|
|
934
|
+
return edge || null;
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Re-map edges when a node's port set is rebuilt.
|
|
938
|
+
*
|
|
939
|
+
* A node gains or loses a port constantly in a live diagram. Matches by port
|
|
940
|
+
* id, drops what cannot be mapped, and reports both — a silently dropped
|
|
941
|
+
* edge is a line that vanished from the drawing while what it stands for
|
|
942
|
+
* still exists. `endsOf` (else the router's own) names the ports an edge
|
|
943
|
+
* uses; an end that names none is not checked.
|
|
944
|
+
*/
|
|
945
|
+
remapNodeConnections(nodeId, portIds, { endsOf = null } = {}) {
|
|
946
|
+
const ends = typeof endsOf === "function" ? endsOf : this.endsOf;
|
|
947
|
+
const available = new Set(portIds);
|
|
948
|
+
let remapped = 0;
|
|
949
|
+
const removed = [];
|
|
950
|
+
for (const [id, edge] of [...this.edges]) {
|
|
951
|
+
const at = ends(edge) || {};
|
|
952
|
+
const touches = [];
|
|
953
|
+
if (edge.from === nodeId && at.from !== null && at.from !== void 0) touches.push(at.from);
|
|
954
|
+
if (edge.to === nodeId && at.to !== null && at.to !== void 0) touches.push(at.to);
|
|
955
|
+
if (edge.from !== nodeId && edge.to !== nodeId) continue;
|
|
956
|
+
if (touches.every((portId) => available.has(portId))) {
|
|
957
|
+
remapped += 1;
|
|
958
|
+
continue;
|
|
959
|
+
}
|
|
960
|
+
this.edges.delete(id);
|
|
961
|
+
removed.push(edge);
|
|
962
|
+
}
|
|
963
|
+
return { remapped, removed };
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
|
|
521
967
|
export {
|
|
522
968
|
CanvasAdapter,
|
|
523
969
|
OBSTACLE_ROUTING_NODE_LIMIT,
|
|
@@ -527,6 +973,10 @@ export {
|
|
|
527
973
|
cardinality,
|
|
528
974
|
selfLoop,
|
|
529
975
|
returnEdge,
|
|
530
|
-
arrange
|
|
976
|
+
arrange,
|
|
977
|
+
layeredLayout,
|
|
978
|
+
NodePlatform,
|
|
979
|
+
CONNECTOR_STRINGS,
|
|
980
|
+
ConnectorRouter
|
|
531
981
|
};
|
|
532
|
-
//# sourceMappingURL=chunk-
|
|
982
|
+
//# sourceMappingURL=chunk-GOQLR5WR.js.map
|