@bpmnkit/plugins 0.0.8
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 +153 -0
- package/dist/ai-bridge/css.d.ts +2 -0
- package/dist/ai-bridge/css.js +366 -0
- package/dist/ai-bridge/index.d.ts +44 -0
- package/dist/ai-bridge/index.js +132 -0
- package/dist/ai-bridge/panel.d.ts +27 -0
- package/dist/ai-bridge/panel.js +715 -0
- package/dist/ascii-view/css.d.ts +4 -0
- package/dist/ascii-view/css.js +83 -0
- package/dist/ascii-view/index.d.ts +25 -0
- package/dist/ascii-view/index.js +92 -0
- package/dist/command-palette/css.d.ts +4 -0
- package/dist/command-palette/css.js +157 -0
- package/dist/command-palette/index.d.ts +53 -0
- package/dist/command-palette/index.js +378 -0
- package/dist/command-palette-editor/index.d.ts +35 -0
- package/dist/command-palette-editor/index.js +60 -0
- package/dist/config-panel/css.d.ts +4 -0
- package/dist/config-panel/css.js +719 -0
- package/dist/config-panel/index.d.ts +36 -0
- package/dist/config-panel/index.js +73 -0
- package/dist/config-panel/renderer.d.ts +127 -0
- package/dist/config-panel/renderer.js +1162 -0
- package/dist/config-panel/types.d.ts +118 -0
- package/dist/config-panel/types.js +2 -0
- package/dist/config-panel-bpmn/index.d.ts +58 -0
- package/dist/config-panel-bpmn/index.js +1320 -0
- package/dist/config-panel-bpmn/template-engine.d.ts +17 -0
- package/dist/config-panel-bpmn/template-engine.js +307 -0
- package/dist/config-panel-bpmn/template-to-service-task.d.ts +30 -0
- package/dist/config-panel-bpmn/template-to-service-task.js +92 -0
- package/dist/config-panel-bpmn/template-types.d.ts +126 -0
- package/dist/config-panel-bpmn/template-types.js +6 -0
- package/dist/config-panel-bpmn/templates/generated.d.ts +3 -0
- package/dist/config-panel-bpmn/templates/generated.js +57865 -0
- package/dist/config-panel-bpmn/util.d.ts +46 -0
- package/dist/config-panel-bpmn/util.js +195 -0
- package/dist/dmn-editor/css.d.ts +3 -0
- package/dist/dmn-editor/css.js +667 -0
- package/dist/dmn-editor/dmn-editor.d.ts +34 -0
- package/dist/dmn-editor/dmn-editor.js +646 -0
- package/dist/dmn-editor/drd-canvas.d.ts +85 -0
- package/dist/dmn-editor/drd-canvas.js +1087 -0
- package/dist/dmn-editor/index.d.ts +3 -0
- package/dist/dmn-editor/index.js +2 -0
- package/dist/dmn-viewer/css.d.ts +3 -0
- package/dist/dmn-viewer/css.js +151 -0
- package/dist/dmn-viewer/dmn-viewer.d.ts +30 -0
- package/dist/dmn-viewer/dmn-viewer.js +160 -0
- package/dist/dmn-viewer/feel.d.ts +3 -0
- package/dist/dmn-viewer/feel.js +2 -0
- package/dist/dmn-viewer/index.d.ts +14 -0
- package/dist/dmn-viewer/index.js +12 -0
- package/dist/element-docs/content.d.ts +20 -0
- package/dist/element-docs/content.js +1032 -0
- package/dist/element-docs/index.d.ts +7 -0
- package/dist/element-docs/index.js +643 -0
- package/dist/feel-playground/css.d.ts +4 -0
- package/dist/feel-playground/css.js +292 -0
- package/dist/feel-playground/index.d.ts +4 -0
- package/dist/feel-playground/index.js +3 -0
- package/dist/feel-playground/playground-plugin.d.ts +14 -0
- package/dist/feel-playground/playground-plugin.js +292 -0
- package/dist/form-editor/css.d.ts +3 -0
- package/dist/form-editor/css.js +703 -0
- package/dist/form-editor/form-editor.d.ts +48 -0
- package/dist/form-editor/form-editor.js +1039 -0
- package/dist/form-editor/index.d.ts +3 -0
- package/dist/form-editor/index.js +2 -0
- package/dist/form-viewer/css.d.ts +3 -0
- package/dist/form-viewer/css.js +303 -0
- package/dist/form-viewer/form-viewer.d.ts +29 -0
- package/dist/form-viewer/form-viewer.js +376 -0
- package/dist/form-viewer/index.d.ts +12 -0
- package/dist/form-viewer/index.js +11 -0
- package/dist/history/checkpoint.d.ts +10 -0
- package/dist/history/checkpoint.js +92 -0
- package/dist/history/css.d.ts +2 -0
- package/dist/history/css.js +130 -0
- package/dist/history/history-panel.d.ts +12 -0
- package/dist/history/history-panel.js +142 -0
- package/dist/history/index.d.ts +5 -0
- package/dist/history/index.js +3 -0
- package/dist/main-menu/css.d.ts +4 -0
- package/dist/main-menu/css.js +272 -0
- package/dist/main-menu/index.d.ts +59 -0
- package/dist/main-menu/index.js +285 -0
- package/dist/minimap/css.d.ts +10 -0
- package/dist/minimap/css.js +54 -0
- package/dist/minimap/index.d.ts +38 -0
- package/dist/minimap/index.js +69 -0
- package/dist/minimap/minimap.d.ts +35 -0
- package/dist/minimap/minimap.js +166 -0
- package/dist/optimize/index.d.ts +21 -0
- package/dist/optimize/index.js +304 -0
- package/dist/process-runner/css.d.ts +2 -0
- package/dist/process-runner/css.js +467 -0
- package/dist/process-runner/index.d.ts +56 -0
- package/dist/process-runner/index.js +549 -0
- package/dist/storage/auto-save.d.ts +11 -0
- package/dist/storage/auto-save.js +44 -0
- package/dist/storage/css.d.ts +2 -0
- package/dist/storage/css.js +2 -0
- package/dist/storage/db.d.ts +99 -0
- package/dist/storage/db.js +116 -0
- package/dist/storage/dialog.d.ts +15 -0
- package/dist/storage/dialog.js +201 -0
- package/dist/storage/export.d.ts +3 -0
- package/dist/storage/export.js +137 -0
- package/dist/storage/index.d.ts +44 -0
- package/dist/storage/index.js +201 -0
- package/dist/storage/sidebar.d.ts +2 -0
- package/dist/storage/sidebar.js +2 -0
- package/dist/storage/storage-api.d.ts +76 -0
- package/dist/storage/storage-api.js +342 -0
- package/dist/storage/types.d.ts +44 -0
- package/dist/storage/types.js +2 -0
- package/dist/storage-tabs-bridge/index.d.ts +96 -0
- package/dist/storage-tabs-bridge/index.js +502 -0
- package/dist/tabs/css.d.ts +3 -0
- package/dist/tabs/css.js +642 -0
- package/dist/tabs/file-resolver.d.ts +71 -0
- package/dist/tabs/file-resolver.js +46 -0
- package/dist/tabs/index.d.ts +15 -0
- package/dist/tabs/index.js +13 -0
- package/dist/tabs/tabs-plugin.d.ts +250 -0
- package/dist/tabs/tabs-plugin.js +1119 -0
- package/dist/token-highlight/css.d.ts +2 -0
- package/dist/token-highlight/css.js +81 -0
- package/dist/token-highlight/index.d.ts +44 -0
- package/dist/token-highlight/index.js +164 -0
- package/dist/watermark/css.d.ts +10 -0
- package/dist/watermark/css.js +54 -0
- package/dist/watermark/index.d.ts +48 -0
- package/dist/watermark/index.js +64 -0
- package/dist/zoom-controls/css.d.ts +4 -0
- package/dist/zoom-controls/css.js +48 -0
- package/dist/zoom-controls/index.d.ts +36 -0
- package/dist/zoom-controls/index.js +111 -0
- package/package.json +121 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bpmnkit/canvas-plugin-main-menu — main menu plugin for `@bpmnkit/canvas`.
|
|
3
|
+
*
|
|
4
|
+
* Adds a panel in the top-right corner of the canvas with an optional title
|
|
5
|
+
* and a menu button. The menu lets users switch between light, dark, and
|
|
6
|
+
* automatic (OS-preference) color themes. Supports drill-down navigation,
|
|
7
|
+
* dynamic items, and a programmatic API for title/items injection.
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
import { injectMainMenuStyles } from "./css.js";
|
|
12
|
+
export { MAIN_MENU_CSS, MAIN_MENU_STYLE_ID, injectMainMenuStyles } from "./css.js";
|
|
13
|
+
const DOTS_ICON = '<svg viewBox="0 0 16 16" fill="currentColor"><circle cx="3.5" cy="8" r="1.3"/><circle cx="8" cy="8" r="1.3"/><circle cx="12.5" cy="8" r="1.3"/></svg>';
|
|
14
|
+
const CHECK_ICON = '<svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1.5,6 4.5,9 10.5,3"/></svg>';
|
|
15
|
+
const MOON_ICON = '<svg viewBox="0 0 16 16" fill="currentColor"><path d="M13 9.5a6 6 0 1 1-7.5-7.5 7 7 0 0 0 7.5 7.5z"/></svg>';
|
|
16
|
+
const SUN_ICON = '<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><circle cx="8" cy="8" r="2.8"/><line x1="8" y1="1.5" x2="8" y2="3"/><line x1="8" y1="13" x2="8" y2="14.5"/><line x1="1.5" y1="8" x2="3" y2="8"/><line x1="13" y1="8" x2="14.5" y2="8"/><line x1="3.3" y1="3.3" x2="4.4" y2="4.4"/><line x1="11.6" y1="11.6" x2="12.7" y2="12.7"/><line x1="3.3" y1="12.7" x2="4.4" y2="11.6"/><line x1="11.6" y1="4.4" x2="12.7" y2="3.3"/></svg>';
|
|
17
|
+
const AUTO_ICON = '<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><circle cx="8" cy="8" r="5.5"/><path d="M8 8V3.5"/><path d="M8 8l3.2 2"/></svg>';
|
|
18
|
+
const BACK_ICON = '<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="10,3 5,8 10,13"/></svg>';
|
|
19
|
+
const ARROW_ICON = '<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="6,3 11,8 6,13"/></svg>';
|
|
20
|
+
const THEMES = [
|
|
21
|
+
{ value: "dark", label: "Dark", icon: MOON_ICON },
|
|
22
|
+
{ value: "light", label: "Light", icon: SUN_ICON },
|
|
23
|
+
{ value: "auto", label: "System", icon: AUTO_ICON },
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* Creates a main menu plugin instance.
|
|
27
|
+
*
|
|
28
|
+
* Each call returns a fresh plugin — pass one instance per canvas.
|
|
29
|
+
*/
|
|
30
|
+
export function createMainMenuPlugin(options = {}) {
|
|
31
|
+
let dropdownEl = null;
|
|
32
|
+
let panelEl = null;
|
|
33
|
+
let titleEl = null;
|
|
34
|
+
let isOpen = false;
|
|
35
|
+
let navStack = [];
|
|
36
|
+
let dynamicItemsFn = null;
|
|
37
|
+
let currentTheme = "light";
|
|
38
|
+
let _setTheme = () => { };
|
|
39
|
+
const offPointerDown = { fn: (_e) => { } };
|
|
40
|
+
const api = {
|
|
41
|
+
setTitle(text) {
|
|
42
|
+
if (titleEl)
|
|
43
|
+
titleEl.textContent = text;
|
|
44
|
+
},
|
|
45
|
+
setDynamicItems(fn) {
|
|
46
|
+
dynamicItemsFn = fn;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
function buildRootItems() {
|
|
50
|
+
const dynamic = dynamicItemsFn ? dynamicItemsFn() : [];
|
|
51
|
+
const staticItems = options.menuItems ?? [];
|
|
52
|
+
const themeSection = [
|
|
53
|
+
{ type: "separator" },
|
|
54
|
+
{
|
|
55
|
+
type: "drill",
|
|
56
|
+
label: "Theme",
|
|
57
|
+
items: () => THEMES.map((t) => ({
|
|
58
|
+
label: t.label,
|
|
59
|
+
icon: t.icon,
|
|
60
|
+
onClick: () => {
|
|
61
|
+
currentTheme = t.value;
|
|
62
|
+
_setTheme(t.value);
|
|
63
|
+
closeDropdown();
|
|
64
|
+
},
|
|
65
|
+
})),
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
const beforeTheme = [...dynamic, ...staticItems];
|
|
69
|
+
return [...beforeTheme, ...themeSection];
|
|
70
|
+
}
|
|
71
|
+
function resolveItems(items) {
|
|
72
|
+
return typeof items === "function" ? items() : items;
|
|
73
|
+
}
|
|
74
|
+
function closeDropdown() {
|
|
75
|
+
dropdownEl?.classList.remove("open");
|
|
76
|
+
isOpen = false;
|
|
77
|
+
}
|
|
78
|
+
function buildLevelContent(dropdown) {
|
|
79
|
+
const slot = document.createElement("div");
|
|
80
|
+
slot.className = "bpmnkit-menu-level";
|
|
81
|
+
const level = navStack[navStack.length - 1];
|
|
82
|
+
if (!level)
|
|
83
|
+
return slot;
|
|
84
|
+
if (navStack.length > 1) {
|
|
85
|
+
const backRow = document.createElement("div");
|
|
86
|
+
backRow.className = "bpmnkit-menu-back-row";
|
|
87
|
+
const backBtn = document.createElement("button");
|
|
88
|
+
backBtn.className = "bpmnkit-menu-back-btn";
|
|
89
|
+
backBtn.type = "button";
|
|
90
|
+
backBtn.innerHTML = BACK_ICON;
|
|
91
|
+
backBtn.addEventListener("click", () => {
|
|
92
|
+
navStack.pop();
|
|
93
|
+
renderLevel(dropdown, "back");
|
|
94
|
+
});
|
|
95
|
+
const levelTitle = document.createElement("span");
|
|
96
|
+
levelTitle.className = "bpmnkit-menu-level-title";
|
|
97
|
+
levelTitle.textContent = level.title ?? "";
|
|
98
|
+
backRow.append(backBtn, levelTitle);
|
|
99
|
+
slot.appendChild(backRow);
|
|
100
|
+
const sep = document.createElement("div");
|
|
101
|
+
sep.className = "bpmnkit-menu-drop-sep";
|
|
102
|
+
slot.appendChild(sep);
|
|
103
|
+
}
|
|
104
|
+
for (const item of level.items) {
|
|
105
|
+
slot.appendChild(buildItemEl(item, dropdown));
|
|
106
|
+
}
|
|
107
|
+
return slot;
|
|
108
|
+
}
|
|
109
|
+
function renderLevel(dropdown, direction) {
|
|
110
|
+
const newSlot = buildLevelContent(dropdown);
|
|
111
|
+
if (direction === "initial") {
|
|
112
|
+
dropdown.textContent = "";
|
|
113
|
+
dropdown.appendChild(newSlot);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const oldSlot = dropdown.querySelector(".bpmnkit-menu-level");
|
|
117
|
+
// Freeze width so the dropdown doesn't shrink/grow during animation
|
|
118
|
+
dropdown.style.minWidth = `${dropdown.offsetWidth}px`;
|
|
119
|
+
// Exit: absolutely positioned so it doesn't affect layout
|
|
120
|
+
if (oldSlot) {
|
|
121
|
+
oldSlot.style.cssText = "position:absolute;inset:0;pointer-events:none;z-index:0;";
|
|
122
|
+
oldSlot.classList.add(direction === "forward" ? "bpmnkit-menu-level--out-left" : "bpmnkit-menu-level--out-right");
|
|
123
|
+
}
|
|
124
|
+
// Enter: on top, drives height
|
|
125
|
+
newSlot.classList.add(direction === "forward" ? "bpmnkit-menu-level--in-right" : "bpmnkit-menu-level--in-left");
|
|
126
|
+
dropdown.appendChild(newSlot);
|
|
127
|
+
setTimeout(() => {
|
|
128
|
+
oldSlot?.remove();
|
|
129
|
+
newSlot.classList.remove("bpmnkit-menu-level--in-right", "bpmnkit-menu-level--in-left");
|
|
130
|
+
dropdown.style.minWidth = "";
|
|
131
|
+
}, 200);
|
|
132
|
+
}
|
|
133
|
+
function buildItemEl(item, dropdown) {
|
|
134
|
+
if ("type" in item && item.type === "separator") {
|
|
135
|
+
const sep = document.createElement("div");
|
|
136
|
+
sep.className = "bpmnkit-menu-drop-sep";
|
|
137
|
+
return sep;
|
|
138
|
+
}
|
|
139
|
+
if ("type" in item && item.type === "info") {
|
|
140
|
+
const row = document.createElement("div");
|
|
141
|
+
row.className = "bpmnkit-menu-info-row";
|
|
142
|
+
const textSpan = document.createElement("span");
|
|
143
|
+
textSpan.className = "bpmnkit-menu-info-text";
|
|
144
|
+
textSpan.textContent = item.text;
|
|
145
|
+
row.appendChild(textSpan);
|
|
146
|
+
if (item.actionLabel && item.onAction) {
|
|
147
|
+
const actionBtn = document.createElement("button");
|
|
148
|
+
actionBtn.className = "bpmnkit-menu-info-action";
|
|
149
|
+
actionBtn.type = "button";
|
|
150
|
+
actionBtn.textContent = item.actionLabel;
|
|
151
|
+
const onAction = item.onAction;
|
|
152
|
+
actionBtn.addEventListener("click", () => {
|
|
153
|
+
closeDropdown();
|
|
154
|
+
onAction();
|
|
155
|
+
});
|
|
156
|
+
row.appendChild(actionBtn);
|
|
157
|
+
}
|
|
158
|
+
return row;
|
|
159
|
+
}
|
|
160
|
+
if ("type" in item && item.type === "drill") {
|
|
161
|
+
const btn = document.createElement("button");
|
|
162
|
+
btn.className = "bpmnkit-menu-item";
|
|
163
|
+
btn.type = "button";
|
|
164
|
+
const checkSpan = document.createElement("span");
|
|
165
|
+
checkSpan.className = "bpmnkit-menu-item-check";
|
|
166
|
+
btn.appendChild(checkSpan);
|
|
167
|
+
const iconSpan = document.createElement("span");
|
|
168
|
+
iconSpan.className = "bpmnkit-menu-item-icon";
|
|
169
|
+
if (item.icon)
|
|
170
|
+
iconSpan.innerHTML = item.icon;
|
|
171
|
+
btn.appendChild(iconSpan);
|
|
172
|
+
const labelSpan = document.createElement("span");
|
|
173
|
+
labelSpan.className = "bpmnkit-menu-item-label";
|
|
174
|
+
labelSpan.textContent = item.label;
|
|
175
|
+
btn.appendChild(labelSpan);
|
|
176
|
+
const arrowSpan = document.createElement("span");
|
|
177
|
+
arrowSpan.className = "bpmnkit-menu-item-arrow";
|
|
178
|
+
arrowSpan.innerHTML = ARROW_ICON;
|
|
179
|
+
btn.appendChild(arrowSpan);
|
|
180
|
+
const drillItems = item.items;
|
|
181
|
+
btn.addEventListener("click", () => {
|
|
182
|
+
navStack.push({ title: item.label, items: resolveItems(drillItems) });
|
|
183
|
+
renderLevel(dropdown, "forward");
|
|
184
|
+
});
|
|
185
|
+
return btn;
|
|
186
|
+
}
|
|
187
|
+
// MenuAction
|
|
188
|
+
const action = item;
|
|
189
|
+
const btn = document.createElement("button");
|
|
190
|
+
btn.className = "bpmnkit-menu-item";
|
|
191
|
+
btn.type = "button";
|
|
192
|
+
const checkSpan = document.createElement("span");
|
|
193
|
+
checkSpan.className = "bpmnkit-menu-item-check";
|
|
194
|
+
// Show check mark for active theme when inside a drill level
|
|
195
|
+
const themeMatch = THEMES.find((t) => t.label === action.label);
|
|
196
|
+
if (themeMatch && themeMatch.value === currentTheme) {
|
|
197
|
+
checkSpan.innerHTML = CHECK_ICON;
|
|
198
|
+
}
|
|
199
|
+
btn.appendChild(checkSpan);
|
|
200
|
+
const iconSpan = document.createElement("span");
|
|
201
|
+
iconSpan.className = "bpmnkit-menu-item-icon";
|
|
202
|
+
if (action.icon)
|
|
203
|
+
iconSpan.innerHTML = action.icon;
|
|
204
|
+
btn.appendChild(iconSpan);
|
|
205
|
+
const labelSpan = document.createElement("span");
|
|
206
|
+
labelSpan.className = "bpmnkit-menu-item-label";
|
|
207
|
+
labelSpan.textContent = action.label;
|
|
208
|
+
btn.appendChild(labelSpan);
|
|
209
|
+
btn.addEventListener("click", () => {
|
|
210
|
+
closeDropdown();
|
|
211
|
+
action.onClick();
|
|
212
|
+
});
|
|
213
|
+
return btn;
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
name: "main-menu",
|
|
217
|
+
api,
|
|
218
|
+
install(canvasApi) {
|
|
219
|
+
injectMainMenuStyles();
|
|
220
|
+
currentTheme = canvasApi.getTheme();
|
|
221
|
+
_setTheme = (t) => canvasApi.setTheme(t);
|
|
222
|
+
// ── Panel ────────────────────────────────────────────────────
|
|
223
|
+
const panel = document.createElement("div");
|
|
224
|
+
panel.className = "bpmnkit-main-menu-panel";
|
|
225
|
+
if (options.title) {
|
|
226
|
+
const title = document.createElement("span");
|
|
227
|
+
title.className = "bpmnkit-main-menu-title";
|
|
228
|
+
title.textContent = options.title;
|
|
229
|
+
panel.appendChild(title);
|
|
230
|
+
titleEl = title;
|
|
231
|
+
const sep = document.createElement("div");
|
|
232
|
+
sep.className = "bpmnkit-main-menu-sep";
|
|
233
|
+
panel.appendChild(sep);
|
|
234
|
+
}
|
|
235
|
+
const menuBtn = document.createElement("button");
|
|
236
|
+
menuBtn.className = "bpmnkit-menu-btn";
|
|
237
|
+
menuBtn.type = "button";
|
|
238
|
+
menuBtn.setAttribute("aria-label", "Main menu");
|
|
239
|
+
menuBtn.title = "Main menu";
|
|
240
|
+
menuBtn.innerHTML = DOTS_ICON;
|
|
241
|
+
panel.appendChild(menuBtn);
|
|
242
|
+
canvasApi.container.appendChild(panel);
|
|
243
|
+
panelEl = panel;
|
|
244
|
+
// ── Dropdown ─────────────────────────────────────────────────
|
|
245
|
+
const dropdown = document.createElement("div");
|
|
246
|
+
dropdown.className = "bpmnkit-menu-dropdown";
|
|
247
|
+
document.body.appendChild(dropdown);
|
|
248
|
+
dropdownEl = dropdown;
|
|
249
|
+
menuBtn.addEventListener("pointerdown", (e) => {
|
|
250
|
+
e.stopPropagation();
|
|
251
|
+
});
|
|
252
|
+
menuBtn.addEventListener("click", () => {
|
|
253
|
+
if (isOpen) {
|
|
254
|
+
closeDropdown();
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
navStack = [{ items: buildRootItems() }];
|
|
258
|
+
renderLevel(dropdown, "initial");
|
|
259
|
+
const rect = menuBtn.getBoundingClientRect();
|
|
260
|
+
dropdown.style.top = `${rect.bottom + 6}px`;
|
|
261
|
+
dropdown.style.right = `${window.innerWidth - rect.right}px`;
|
|
262
|
+
dropdown.style.left = "auto";
|
|
263
|
+
dropdown.classList.add("open");
|
|
264
|
+
isOpen = true;
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
offPointerDown.fn = (e) => {
|
|
268
|
+
if (isOpen && !dropdown.contains(e.target)) {
|
|
269
|
+
closeDropdown();
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
document.addEventListener("pointerdown", offPointerDown.fn);
|
|
273
|
+
},
|
|
274
|
+
uninstall() {
|
|
275
|
+
document.removeEventListener("pointerdown", offPointerDown.fn);
|
|
276
|
+
dropdownEl?.remove();
|
|
277
|
+
dropdownEl = null;
|
|
278
|
+
panelEl?.remove();
|
|
279
|
+
panelEl = null;
|
|
280
|
+
titleEl = null;
|
|
281
|
+
isOpen = false;
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** ID used to prevent duplicate style injection. */
|
|
2
|
+
export declare const MINIMAP_STYLE_ID = "bpmnkit-minimap-styles-v1";
|
|
3
|
+
/** CSS for the minimap plugin, injected once into `<head>`. */
|
|
4
|
+
export declare const MINIMAP_CSS = "\n.bpmnkit-minimap {\n position: absolute;\n bottom: 12px;\n right: 12px;\n width: 160px;\n height: 100px;\n background: var(--bpmnkit-overlay-bg, rgba(248, 249, 250, 0.92));\n border: 1px solid var(--bpmnkit-overlay-border, rgba(0, 0, 0, 0.12));\n border-radius: 6px;\n overflow: hidden;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);\n cursor: crosshair;\n}\n.bpmnkit-minimap > svg {\n display: block;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.bpmnkit-minimap-shape {\n fill: var(--bpmnkit-shape-stroke, #404040);\n opacity: 0.45;\n}\n.bpmnkit-minimap-edge {\n stroke: var(--bpmnkit-shape-stroke, #404040);\n stroke-width: 0.5;\n fill: none;\n opacity: 0.35;\n}\n.bpmnkit-minimap-viewport {\n fill: var(--bpmnkit-viewport-fill, var(--bpmnkit-accent-subtle, rgba(26,86,219,0.12)));\n stroke: var(--bpmnkit-viewport-stroke, var(--bpmnkit-accent, #1a56db));\n stroke-width: 1;\n}\n";
|
|
5
|
+
/**
|
|
6
|
+
* Injects the minimap stylesheet into `<head>` if not already present.
|
|
7
|
+
* Safe to call multiple times — only one `<style>` tag is ever inserted.
|
|
8
|
+
*/
|
|
9
|
+
export declare function injectMinimapStyles(): void;
|
|
10
|
+
//# sourceMappingURL=css.d.ts.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** ID used to prevent duplicate style injection. */
|
|
2
|
+
export const MINIMAP_STYLE_ID = "bpmnkit-minimap-styles-v1";
|
|
3
|
+
/** CSS for the minimap plugin, injected once into `<head>`. */
|
|
4
|
+
export const MINIMAP_CSS = `
|
|
5
|
+
.bpmnkit-minimap {
|
|
6
|
+
position: absolute;
|
|
7
|
+
bottom: 12px;
|
|
8
|
+
right: 12px;
|
|
9
|
+
width: 160px;
|
|
10
|
+
height: 100px;
|
|
11
|
+
background: var(--bpmnkit-overlay-bg, rgba(248, 249, 250, 0.92));
|
|
12
|
+
border: 1px solid var(--bpmnkit-overlay-border, rgba(0, 0, 0, 0.12));
|
|
13
|
+
border-radius: 6px;
|
|
14
|
+
overflow: hidden;
|
|
15
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
|
16
|
+
cursor: crosshair;
|
|
17
|
+
}
|
|
18
|
+
.bpmnkit-minimap > svg {
|
|
19
|
+
display: block;
|
|
20
|
+
width: 100%;
|
|
21
|
+
height: 100%;
|
|
22
|
+
pointer-events: none;
|
|
23
|
+
}
|
|
24
|
+
.bpmnkit-minimap-shape {
|
|
25
|
+
fill: var(--bpmnkit-shape-stroke, #404040);
|
|
26
|
+
opacity: 0.45;
|
|
27
|
+
}
|
|
28
|
+
.bpmnkit-minimap-edge {
|
|
29
|
+
stroke: var(--bpmnkit-shape-stroke, #404040);
|
|
30
|
+
stroke-width: 0.5;
|
|
31
|
+
fill: none;
|
|
32
|
+
opacity: 0.35;
|
|
33
|
+
}
|
|
34
|
+
.bpmnkit-minimap-viewport {
|
|
35
|
+
fill: var(--bpmnkit-viewport-fill, var(--bpmnkit-accent-subtle, rgba(26,86,219,0.12)));
|
|
36
|
+
stroke: var(--bpmnkit-viewport-stroke, var(--bpmnkit-accent, #1a56db));
|
|
37
|
+
stroke-width: 1;
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
/**
|
|
41
|
+
* Injects the minimap stylesheet into `<head>` if not already present.
|
|
42
|
+
* Safe to call multiple times — only one `<style>` tag is ever inserted.
|
|
43
|
+
*/
|
|
44
|
+
export function injectMinimapStyles() {
|
|
45
|
+
if (typeof document === "undefined")
|
|
46
|
+
return;
|
|
47
|
+
if (document.getElementById(MINIMAP_STYLE_ID))
|
|
48
|
+
return;
|
|
49
|
+
const style = document.createElement("style");
|
|
50
|
+
style.id = MINIMAP_STYLE_ID;
|
|
51
|
+
style.textContent = MINIMAP_CSS;
|
|
52
|
+
document.head.appendChild(style);
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=css.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bpmnkit/canvas-plugin-minimap — minimap navigation plugin for `@bpmnkit/canvas`.
|
|
3
|
+
*
|
|
4
|
+
* Adds a 160×100 overview panel in the bottom-right corner of the canvas.
|
|
5
|
+
* Clicking the minimap pans the main viewport to that position.
|
|
6
|
+
*
|
|
7
|
+
* ## Usage
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { BpmnCanvas } from "@bpmnkit/canvas";
|
|
10
|
+
* import { createMinimapPlugin } from "@bpmnkit/canvas-plugin-minimap";
|
|
11
|
+
*
|
|
12
|
+
* const canvas = new BpmnCanvas({
|
|
13
|
+
* container: document.getElementById("app")!,
|
|
14
|
+
* xml: myBpmnXml,
|
|
15
|
+
* plugins: [createMinimapPlugin()],
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @packageDocumentation
|
|
20
|
+
*/
|
|
21
|
+
import type { CanvasPlugin } from "@bpmnkit/canvas";
|
|
22
|
+
export { Minimap } from "./minimap.js";
|
|
23
|
+
export { MINIMAP_CSS, MINIMAP_STYLE_ID, injectMinimapStyles } from "./css.js";
|
|
24
|
+
/**
|
|
25
|
+
* Creates a minimap plugin instance.
|
|
26
|
+
*
|
|
27
|
+
* Each call returns a fresh plugin — pass one instance per canvas.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const canvas = new BpmnCanvas({
|
|
32
|
+
* container,
|
|
33
|
+
* plugins: [createMinimapPlugin()],
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function createMinimapPlugin(): CanvasPlugin;
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bpmnkit/canvas-plugin-minimap — minimap navigation plugin for `@bpmnkit/canvas`.
|
|
3
|
+
*
|
|
4
|
+
* Adds a 160×100 overview panel in the bottom-right corner of the canvas.
|
|
5
|
+
* Clicking the minimap pans the main viewport to that position.
|
|
6
|
+
*
|
|
7
|
+
* ## Usage
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { BpmnCanvas } from "@bpmnkit/canvas";
|
|
10
|
+
* import { createMinimapPlugin } from "@bpmnkit/canvas-plugin-minimap";
|
|
11
|
+
*
|
|
12
|
+
* const canvas = new BpmnCanvas({
|
|
13
|
+
* container: document.getElementById("app")!,
|
|
14
|
+
* xml: myBpmnXml,
|
|
15
|
+
* plugins: [createMinimapPlugin()],
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @packageDocumentation
|
|
20
|
+
*/
|
|
21
|
+
import { injectMinimapStyles } from "./css.js";
|
|
22
|
+
import { Minimap } from "./minimap.js";
|
|
23
|
+
export { Minimap } from "./minimap.js";
|
|
24
|
+
export { MINIMAP_CSS, MINIMAP_STYLE_ID, injectMinimapStyles } from "./css.js";
|
|
25
|
+
/**
|
|
26
|
+
* Creates a minimap plugin instance.
|
|
27
|
+
*
|
|
28
|
+
* Each call returns a fresh plugin — pass one instance per canvas.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const canvas = new BpmnCanvas({
|
|
33
|
+
* container,
|
|
34
|
+
* plugins: [createMinimapPlugin()],
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function createMinimapPlugin() {
|
|
39
|
+
let minimap = null;
|
|
40
|
+
const unsubs = [];
|
|
41
|
+
return {
|
|
42
|
+
name: "minimap",
|
|
43
|
+
install(api) {
|
|
44
|
+
injectMinimapStyles();
|
|
45
|
+
minimap = new Minimap(api.container, (diagX, diagY) => {
|
|
46
|
+
const { scale } = api.getViewport();
|
|
47
|
+
api.setViewport({
|
|
48
|
+
tx: api.svg.clientWidth / 2 - diagX * scale,
|
|
49
|
+
ty: api.svg.clientHeight / 2 - diagY * scale,
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
unsubs.push(api.on("diagram:load", (defs) => {
|
|
53
|
+
minimap?.update(defs);
|
|
54
|
+
}), api.on("viewport:change", (state) => {
|
|
55
|
+
minimap?.syncViewport(state, api.svg.clientWidth, api.svg.clientHeight);
|
|
56
|
+
}), api.on("diagram:clear", () => {
|
|
57
|
+
minimap?.clear();
|
|
58
|
+
}));
|
|
59
|
+
},
|
|
60
|
+
uninstall() {
|
|
61
|
+
for (const off of unsubs)
|
|
62
|
+
off();
|
|
63
|
+
unsubs.length = 0;
|
|
64
|
+
minimap?.destroy();
|
|
65
|
+
minimap = null;
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ViewportState } from "@bpmnkit/canvas";
|
|
2
|
+
import type { BpmnDefinitions } from "@bpmnkit/core";
|
|
3
|
+
/**
|
|
4
|
+
* A scaled-down overview of the BPMN diagram that shows the current viewport
|
|
5
|
+
* position as a highlighted rectangle.
|
|
6
|
+
*
|
|
7
|
+
* Clicking the minimap pans the canvas to that position.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Minimap {
|
|
10
|
+
/** Invoked when the user clicks the minimap to request a viewport pan. */
|
|
11
|
+
private readonly _onNavigate;
|
|
12
|
+
private readonly _host;
|
|
13
|
+
private readonly _svg;
|
|
14
|
+
private readonly _shapesG;
|
|
15
|
+
private readonly _edgesG;
|
|
16
|
+
private readonly _viewportRect;
|
|
17
|
+
private _scale;
|
|
18
|
+
private _offsetX;
|
|
19
|
+
private _offsetY;
|
|
20
|
+
private readonly _mmW;
|
|
21
|
+
private readonly _mmH;
|
|
22
|
+
constructor(container: HTMLElement,
|
|
23
|
+
/** Invoked when the user clicks the minimap to request a viewport pan. */
|
|
24
|
+
_onNavigate: (diagX: number, diagY: number) => void);
|
|
25
|
+
/** Updates the minimap with shapes and edges from a newly loaded diagram. */
|
|
26
|
+
update(defs: BpmnDefinitions): void;
|
|
27
|
+
/** Clears the minimap content. */
|
|
28
|
+
clear(): void;
|
|
29
|
+
/** Syncs the viewport indicator rectangle with the current pan/zoom state. */
|
|
30
|
+
syncViewport(state: ViewportState, svgWidth: number, svgHeight: number): void;
|
|
31
|
+
/** Removes the minimap from the DOM. */
|
|
32
|
+
destroy(): void;
|
|
33
|
+
private readonly _onClick;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=minimap.d.ts.map
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
const NS = "http://www.w3.org/2000/svg";
|
|
2
|
+
function svgEl(tag) {
|
|
3
|
+
return document.createElementNS(NS, tag);
|
|
4
|
+
}
|
|
5
|
+
function attr(el, attrs) {
|
|
6
|
+
for (const [k, v] of Object.entries(attrs))
|
|
7
|
+
el.setAttribute(k, String(v));
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A scaled-down overview of the BPMN diagram that shows the current viewport
|
|
11
|
+
* position as a highlighted rectangle.
|
|
12
|
+
*
|
|
13
|
+
* Clicking the minimap pans the canvas to that position.
|
|
14
|
+
*/
|
|
15
|
+
export class Minimap {
|
|
16
|
+
_onNavigate;
|
|
17
|
+
_host;
|
|
18
|
+
_svg;
|
|
19
|
+
_shapesG;
|
|
20
|
+
_edgesG;
|
|
21
|
+
_viewportRect;
|
|
22
|
+
// Minimap-space transform from diagram-space coordinates
|
|
23
|
+
_scale = 1;
|
|
24
|
+
_offsetX = 0;
|
|
25
|
+
_offsetY = 0;
|
|
26
|
+
// Minimap pixel dimensions
|
|
27
|
+
_mmW = 160;
|
|
28
|
+
_mmH = 100;
|
|
29
|
+
constructor(container,
|
|
30
|
+
/** Invoked when the user clicks the minimap to request a viewport pan. */
|
|
31
|
+
_onNavigate) {
|
|
32
|
+
this._onNavigate = _onNavigate;
|
|
33
|
+
this._host = document.createElement("div");
|
|
34
|
+
this._host.className = "bpmnkit-minimap";
|
|
35
|
+
this._host.setAttribute("aria-hidden", "true");
|
|
36
|
+
this._svg = document.createElementNS(NS, "svg");
|
|
37
|
+
attr(this._svg, {
|
|
38
|
+
viewBox: `0 0 ${this._mmW} ${this._mmH}`,
|
|
39
|
+
preserveAspectRatio: "none",
|
|
40
|
+
});
|
|
41
|
+
this._host.appendChild(this._svg);
|
|
42
|
+
this._edgesG = svgEl("g");
|
|
43
|
+
this._shapesG = svgEl("g");
|
|
44
|
+
this._viewportRect = svgEl("rect");
|
|
45
|
+
attr(this._viewportRect, { class: "bpmnkit-minimap-viewport", rx: 1 });
|
|
46
|
+
this._svg.appendChild(this._edgesG);
|
|
47
|
+
this._svg.appendChild(this._shapesG);
|
|
48
|
+
this._svg.appendChild(this._viewportRect);
|
|
49
|
+
container.appendChild(this._host);
|
|
50
|
+
this._host.addEventListener("click", this._onClick);
|
|
51
|
+
}
|
|
52
|
+
/** Updates the minimap with shapes and edges from a newly loaded diagram. */
|
|
53
|
+
update(defs) {
|
|
54
|
+
this._edgesG.innerHTML = "";
|
|
55
|
+
this._shapesG.innerHTML = "";
|
|
56
|
+
const plane = defs.diagrams[0]?.plane;
|
|
57
|
+
if (!plane)
|
|
58
|
+
return;
|
|
59
|
+
// Compute diagram bounding box
|
|
60
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
61
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
62
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
63
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
64
|
+
for (const s of plane.shapes) {
|
|
65
|
+
minX = Math.min(minX, s.bounds.x);
|
|
66
|
+
minY = Math.min(minY, s.bounds.y);
|
|
67
|
+
maxX = Math.max(maxX, s.bounds.x + s.bounds.width);
|
|
68
|
+
maxY = Math.max(maxY, s.bounds.y + s.bounds.height);
|
|
69
|
+
}
|
|
70
|
+
for (const e of plane.edges) {
|
|
71
|
+
for (const wp of e.waypoints) {
|
|
72
|
+
minX = Math.min(minX, wp.x);
|
|
73
|
+
minY = Math.min(minY, wp.y);
|
|
74
|
+
maxX = Math.max(maxX, wp.x);
|
|
75
|
+
maxY = Math.max(maxY, wp.y);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!Number.isFinite(minX))
|
|
79
|
+
return;
|
|
80
|
+
const padding = 8;
|
|
81
|
+
const dW = maxX - minX;
|
|
82
|
+
const dH = maxY - minY;
|
|
83
|
+
const scaleX = (this._mmW - padding * 2) / dW;
|
|
84
|
+
const scaleY = (this._mmH - padding * 2) / dH;
|
|
85
|
+
this._scale = Math.min(scaleX, scaleY);
|
|
86
|
+
this._offsetX = padding + (this._mmW - padding * 2 - dW * this._scale) / 2 - minX * this._scale;
|
|
87
|
+
this._offsetY = padding + (this._mmH - padding * 2 - dH * this._scale) / 2 - minY * this._scale;
|
|
88
|
+
// Render simplified shapes (just rects/circles)
|
|
89
|
+
for (const s of plane.shapes) {
|
|
90
|
+
const x = s.bounds.x * this._scale + this._offsetX;
|
|
91
|
+
const y = s.bounds.y * this._scale + this._offsetY;
|
|
92
|
+
const w = s.bounds.width * this._scale;
|
|
93
|
+
const h = s.bounds.height * this._scale;
|
|
94
|
+
// Approximate shape type from size: very small square → event or gateway
|
|
95
|
+
const isSmall = w < 10;
|
|
96
|
+
if (isSmall) {
|
|
97
|
+
const circle = svgEl("circle");
|
|
98
|
+
attr(circle, {
|
|
99
|
+
cx: x + w / 2,
|
|
100
|
+
cy: y + h / 2,
|
|
101
|
+
r: Math.max(w / 2, 2),
|
|
102
|
+
class: "bpmnkit-minimap-shape",
|
|
103
|
+
});
|
|
104
|
+
this._shapesG.appendChild(circle);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
const rect = svgEl("rect");
|
|
108
|
+
attr(rect, {
|
|
109
|
+
x,
|
|
110
|
+
y,
|
|
111
|
+
width: Math.max(w, 1),
|
|
112
|
+
height: Math.max(h, 1),
|
|
113
|
+
rx: 1,
|
|
114
|
+
class: "bpmnkit-minimap-shape",
|
|
115
|
+
});
|
|
116
|
+
this._shapesG.appendChild(rect);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Render simplified edges
|
|
120
|
+
for (const e of plane.edges) {
|
|
121
|
+
if (e.waypoints.length < 2)
|
|
122
|
+
continue;
|
|
123
|
+
const pts = e.waypoints
|
|
124
|
+
.map((wp) => `${wp.x * this._scale + this._offsetX},${wp.y * this._scale + this._offsetY}`)
|
|
125
|
+
.join(" ");
|
|
126
|
+
const poly = svgEl("polyline");
|
|
127
|
+
attr(poly, { points: pts, class: "bpmnkit-minimap-edge" });
|
|
128
|
+
this._edgesG.appendChild(poly);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** Clears the minimap content. */
|
|
132
|
+
clear() {
|
|
133
|
+
this._edgesG.innerHTML = "";
|
|
134
|
+
this._shapesG.innerHTML = "";
|
|
135
|
+
attr(this._viewportRect, { x: 0, y: 0, width: 0, height: 0 });
|
|
136
|
+
}
|
|
137
|
+
/** Syncs the viewport indicator rectangle with the current pan/zoom state. */
|
|
138
|
+
syncViewport(state, svgWidth, svgHeight) {
|
|
139
|
+
// Visible diagram area in diagram coordinates
|
|
140
|
+
const left = -state.tx / state.scale;
|
|
141
|
+
const top = -state.ty / state.scale;
|
|
142
|
+
const visW = svgWidth / state.scale;
|
|
143
|
+
const visH = svgHeight / state.scale;
|
|
144
|
+
// Map to minimap coordinates
|
|
145
|
+
const mx = left * this._scale + this._offsetX;
|
|
146
|
+
const my = top * this._scale + this._offsetY;
|
|
147
|
+
const mw = visW * this._scale;
|
|
148
|
+
const mh = visH * this._scale;
|
|
149
|
+
attr(this._viewportRect, { x: mx, y: my, width: Math.max(mw, 2), height: Math.max(mh, 2) });
|
|
150
|
+
}
|
|
151
|
+
/** Removes the minimap from the DOM. */
|
|
152
|
+
destroy() {
|
|
153
|
+
this._host.removeEventListener("click", this._onClick);
|
|
154
|
+
this._host.remove();
|
|
155
|
+
}
|
|
156
|
+
_onClick = (e) => {
|
|
157
|
+
const rect = this._host.getBoundingClientRect();
|
|
158
|
+
const mmX = e.clientX - rect.left;
|
|
159
|
+
const mmY = e.clientY - rect.top;
|
|
160
|
+
// Convert minimap coordinates to diagram coordinates
|
|
161
|
+
const diagX = (mmX - this._offsetX) / this._scale;
|
|
162
|
+
const diagY = (mmY - this._offsetY) / this._scale;
|
|
163
|
+
this._onNavigate(diagX, diagY);
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=minimap.js.map
|