@bpmnkit/plugins 0.0.10 → 0.0.12
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 +5 -1
- package/dist/ai-bridge/index.d.ts +2 -0
- package/dist/ai-bridge/index.js +5 -0
- package/dist/ai-bridge/panel.d.ts +1 -0
- package/dist/ai-bridge/panel.js +8 -1
- package/dist/command-palette/css.d.ts +1 -1
- package/dist/command-palette/css.js +69 -0
- package/dist/command-palette/index.d.ts +29 -0
- package/dist/command-palette/index.js +382 -52
- package/dist/command-palette-editor/index.d.ts +15 -10
- package/dist/command-palette-editor/index.js +96 -12
- package/dist/main-menu/css.d.ts +1 -1
- package/dist/main-menu/css.js +31 -0
- package/dist/main-menu/index.js +2 -0
- package/dist/tabs/css.js +67 -0
- package/dist/tabs/tabs-plugin.js +14 -12
- package/dist/token-highlight/css.js +4 -0
- package/dist/token-highlight/index.js +56 -15
- package/package.json +6 -6
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* (el) => { (el as HTMLElement).style.display = active ? "none" : ""; }
|
|
13
13
|
* );
|
|
14
14
|
* },
|
|
15
|
+
* onAskAI: (query) => aiBridgePlugin.ask(query),
|
|
15
16
|
* });
|
|
16
17
|
*
|
|
17
18
|
* const editor = new BpmnEditor({ container, xml, plugins: [palette] });
|
|
@@ -23,10 +24,160 @@ import { computeDiagramBounds } from "@bpmnkit/canvas";
|
|
|
23
24
|
import { Bpmn } from "@bpmnkit/core";
|
|
24
25
|
import { injectCommandPaletteStyles } from "./css.js";
|
|
25
26
|
export { COMMAND_PALETTE_CSS, COMMAND_PALETTE_STYLE_ID, injectCommandPaletteStyles, } from "./css.js";
|
|
27
|
+
// ── Matching ──────────────────────────────────────────────────────────────────
|
|
28
|
+
/**
|
|
29
|
+
* Returns true when every whitespace-separated word in `query` appears
|
|
30
|
+
* somewhere in `text` (case-insensitive). This lets "add gateway" match
|
|
31
|
+
* "Add Exclusive Gateway" even though it is not a contiguous substring.
|
|
32
|
+
*/
|
|
33
|
+
function wordsMatch(text, query) {
|
|
34
|
+
const target = text.toLowerCase();
|
|
35
|
+
return query
|
|
36
|
+
.toLowerCase()
|
|
37
|
+
.split(/\s+/)
|
|
38
|
+
.filter(Boolean)
|
|
39
|
+
.every((w) => target.includes(w));
|
|
40
|
+
}
|
|
41
|
+
// ── Docs registry ─────────────────────────────────────────────────────────────
|
|
42
|
+
const DOCS_BASE_DEFAULT = "https://docs.bpmnkit.com";
|
|
43
|
+
const DOC_ENTRIES = [
|
|
44
|
+
{
|
|
45
|
+
title: "Quick Start",
|
|
46
|
+
path: "/getting-started/quick-start/",
|
|
47
|
+
keywords: ["start", "install", "begin", "setup", "first", "hello", "quickstart"],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
title: "Installation",
|
|
51
|
+
path: "/getting-started/installation/",
|
|
52
|
+
keywords: ["install", "npm", "pnpm", "yarn", "add", "package", "require"],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
title: "Concepts",
|
|
56
|
+
path: "/getting-started/concepts/",
|
|
57
|
+
keywords: ["concept", "bpmn", "process", "element", "overview", "intro", "what"],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
title: "Building Processes",
|
|
61
|
+
path: "/guides/building-processes/",
|
|
62
|
+
keywords: ["build", "create", "process", "task", "flow", "sequence", "diagram", "guide"],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
title: "Gateways",
|
|
66
|
+
path: "/guides/gateways/",
|
|
67
|
+
keywords: [
|
|
68
|
+
"gateway",
|
|
69
|
+
"exclusive",
|
|
70
|
+
"parallel",
|
|
71
|
+
"inclusive",
|
|
72
|
+
"split",
|
|
73
|
+
"merge",
|
|
74
|
+
"xor",
|
|
75
|
+
"condition",
|
|
76
|
+
"branch",
|
|
77
|
+
"fork",
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
title: "Simulation",
|
|
82
|
+
path: "/guides/simulation/",
|
|
83
|
+
keywords: ["simulate", "run", "test", "engine", "execute", "play", "simulation"],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
title: "Deployment",
|
|
87
|
+
path: "/guides/deployment/",
|
|
88
|
+
keywords: ["deploy", "camunda", "cluster", "zeebe", "publish", "production", "upload"],
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
title: "AI Guide",
|
|
92
|
+
path: "/guides/ai/",
|
|
93
|
+
keywords: [
|
|
94
|
+
"ai",
|
|
95
|
+
"artificial",
|
|
96
|
+
"intelligence",
|
|
97
|
+
"llm",
|
|
98
|
+
"claude",
|
|
99
|
+
"copilot",
|
|
100
|
+
"gemini",
|
|
101
|
+
"assist",
|
|
102
|
+
"chat",
|
|
103
|
+
"improve",
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
title: "@bpmnkit/core",
|
|
108
|
+
path: "/packages/core/",
|
|
109
|
+
keywords: [
|
|
110
|
+
"core",
|
|
111
|
+
"parser",
|
|
112
|
+
"builder",
|
|
113
|
+
"xml",
|
|
114
|
+
"export",
|
|
115
|
+
"import",
|
|
116
|
+
"layout",
|
|
117
|
+
"compact",
|
|
118
|
+
"serialize",
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
title: "@bpmnkit/editor",
|
|
123
|
+
path: "/packages/editor/",
|
|
124
|
+
keywords: ["editor", "edit", "modeler", "interactive", "canvas", "plugin"],
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
title: "@bpmnkit/engine",
|
|
128
|
+
path: "/packages/engine/",
|
|
129
|
+
keywords: ["engine", "execute", "run", "simulate", "worker", "job", "token", "fire"],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
title: "@bpmnkit/api",
|
|
133
|
+
path: "/packages/api/",
|
|
134
|
+
keywords: ["api", "client", "camunda", "rest", "http", "zeebe", "operate", "instance"],
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
title: "@bpmnkit/canvas",
|
|
138
|
+
path: "/packages/canvas/",
|
|
139
|
+
keywords: ["canvas", "viewer", "svg", "render", "view", "display", "embed"],
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
title: "Connector Generator",
|
|
143
|
+
path: "/packages/connector-gen/",
|
|
144
|
+
keywords: ["connector", "openapi", "swagger", "template", "generate", "rest", "http", "api"],
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
title: "casen CLI",
|
|
148
|
+
path: "/cli/casen/",
|
|
149
|
+
keywords: [
|
|
150
|
+
"cli",
|
|
151
|
+
"command",
|
|
152
|
+
"terminal",
|
|
153
|
+
"casen",
|
|
154
|
+
"tui",
|
|
155
|
+
"profile",
|
|
156
|
+
"job",
|
|
157
|
+
"incident",
|
|
158
|
+
"process",
|
|
159
|
+
"mcp",
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
title: "casen connector",
|
|
164
|
+
path: "/cli/connector/",
|
|
165
|
+
keywords: ["connector", "cli", "generate", "api", "catalog", "swagger", "openapi"],
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
// Shown when the query is empty
|
|
169
|
+
const FEATURED_DOC_PATHS = new Set([
|
|
170
|
+
"/getting-started/quick-start/",
|
|
171
|
+
"/guides/building-processes/",
|
|
172
|
+
"/guides/ai/",
|
|
173
|
+
"/cli/casen/",
|
|
174
|
+
]);
|
|
26
175
|
// ── Module-level singleton — only one palette open at a time ──────────────────
|
|
27
176
|
let _closeCurrent = null;
|
|
28
177
|
// ── Icons ─────────────────────────────────────────────────────────────────────
|
|
29
178
|
const SEARCH_ICON = '<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="6.5" cy="6.5" r="4"/><line x1="10" y1="10" x2="14" y2="14"/></svg>';
|
|
179
|
+
const EXTERNAL_ICON = '<svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 2H2a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h7a1 1 0 0 0 1-1V7.5"/><polyline points="7.5 1 11 1 11 4.5"/><line x1="11" y1="1" x2="5.5" y2="6.5"/></svg>';
|
|
180
|
+
const AI_ICON = '<svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 0a.5.5 0 0 1 .46.31l1.46 3.46 3.46 1.46a.5.5 0 0 1 0 .94l-3.46 1.46L8.46 11.1a.5.5 0 0 1-.92 0L6.08 7.63 2.62 6.17a.5.5 0 0 1 0-.94l3.46-1.46L7.54.31A.5.5 0 0 1 8 0zm0 2.08L6.96 4.54a.5.5 0 0 1-.28.28L4.22 5.7l2.46 1.04a.5.5 0 0 1 .28.28L8 9.48l1.04-2.46a.5.5 0 0 1 .28-.28L11.78 5.7 9.32 4.82a.5.5 0 0 1-.28-.28L8 2.08zm5 8.42a.5.5 0 0 1 .46.31l.6 1.43 1.43.6a.5.5 0 0 1 0 .92l-1.43.6-.6 1.43a.5.5 0 0 1-.92 0l-.6-1.43-1.43-.6a.5.5 0 0 1 0-.92l1.43-.6.6-1.43A.5.5 0 0 1 13 10.5zm0 1.79-.27.63a.5.5 0 0 1-.28.28l-.63.27.63.27a.5.5 0 0 1 .28.28l.27.63.27-.63a.5.5 0 0 1 .28-.28l.63-.27-.63-.27a.5.5 0 0 1-.28-.28L13 12.29z"/></svg>';
|
|
30
181
|
// ── Theme helper ──────────────────────────────────────────────────────────────
|
|
31
182
|
function resolveTheme(theme) {
|
|
32
183
|
if (theme === "dark")
|
|
@@ -45,6 +196,13 @@ export function createCommandPalettePlugin(options = {}) {
|
|
|
45
196
|
let _isZenMode = false;
|
|
46
197
|
let _focusedIndex = 0;
|
|
47
198
|
let _lastDefs = null;
|
|
199
|
+
let _focusableItems = [];
|
|
200
|
+
// null = unknown/checking, true = running, false = not running
|
|
201
|
+
let _proxyReady = null;
|
|
202
|
+
// incremented on each palette open to discard stale fetch results
|
|
203
|
+
let _proxyCheckId = 0;
|
|
204
|
+
// navigation stack — each pushView() adds one level, Escape pops
|
|
205
|
+
const _viewStack = [];
|
|
48
206
|
const _extraCommands = [];
|
|
49
207
|
const _unsubs = [];
|
|
50
208
|
// ── Built-in commands (lazy — need _api set) ─────────────────────────────
|
|
@@ -147,6 +305,115 @@ export function createCommandPalettePlugin(options = {}) {
|
|
|
147
305
|
}
|
|
148
306
|
options.onZenModeChange?.(_isZenMode);
|
|
149
307
|
}
|
|
308
|
+
// ── Proxy check ───────────────────────────────────────────────────────────
|
|
309
|
+
function startProxyCheck() {
|
|
310
|
+
if (!options.onAskAI)
|
|
311
|
+
return;
|
|
312
|
+
_proxyReady = null;
|
|
313
|
+
const checkId = ++_proxyCheckId;
|
|
314
|
+
const serverUrl = options.aiServerUrl ?? "http://localhost:3033";
|
|
315
|
+
fetch(`${serverUrl}/status`, { signal: AbortSignal.timeout(3000) })
|
|
316
|
+
.then((res) => res.json())
|
|
317
|
+
.then((data) => {
|
|
318
|
+
if (checkId !== _proxyCheckId)
|
|
319
|
+
return;
|
|
320
|
+
_proxyReady = Boolean(data?.ready);
|
|
321
|
+
if (_isOpen && _inputEl)
|
|
322
|
+
renderList(_inputEl.value);
|
|
323
|
+
})
|
|
324
|
+
.catch(() => {
|
|
325
|
+
if (checkId !== _proxyCheckId)
|
|
326
|
+
return;
|
|
327
|
+
_proxyReady = false;
|
|
328
|
+
if (_isOpen && _inputEl)
|
|
329
|
+
renderList(_inputEl.value);
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
// ── Section builders ──────────────────────────────────────────────────────
|
|
333
|
+
function buildCommandItems(query) {
|
|
334
|
+
const all = [...builtinCommands(), ..._extraCommands];
|
|
335
|
+
const cmds = query
|
|
336
|
+
? all.filter((c) => wordsMatch(c.title, query) ||
|
|
337
|
+
(c.description != null && wordsMatch(c.description, query)))
|
|
338
|
+
: all;
|
|
339
|
+
return cmds.map((c) => ({
|
|
340
|
+
kind: "command",
|
|
341
|
+
title: c.title,
|
|
342
|
+
description: c.description,
|
|
343
|
+
action: c.action,
|
|
344
|
+
}));
|
|
345
|
+
}
|
|
346
|
+
function buildDocItems(query) {
|
|
347
|
+
const baseUrl = options.docsBaseUrl ?? DOCS_BASE_DEFAULT;
|
|
348
|
+
const entries = query.trim()
|
|
349
|
+
? DOC_ENTRIES.filter((e) => {
|
|
350
|
+
const q = query.toLowerCase();
|
|
351
|
+
return e.title.toLowerCase().includes(q) || e.keywords.some((k) => k.includes(q));
|
|
352
|
+
}).slice(0, 4)
|
|
353
|
+
: DOC_ENTRIES.filter((e) => FEATURED_DOC_PATHS.has(e.path));
|
|
354
|
+
return entries.map((e) => ({
|
|
355
|
+
kind: "doc",
|
|
356
|
+
title: e.title,
|
|
357
|
+
description: "docs ↗",
|
|
358
|
+
action() {
|
|
359
|
+
window.open(baseUrl + e.path, "_blank", "noopener");
|
|
360
|
+
closePalette();
|
|
361
|
+
},
|
|
362
|
+
}));
|
|
363
|
+
}
|
|
364
|
+
function buildAiItem(query) {
|
|
365
|
+
const ready = _proxyReady;
|
|
366
|
+
const description = ready === null
|
|
367
|
+
? "Checking server…"
|
|
368
|
+
: ready
|
|
369
|
+
? "Send to AI assistant ↵"
|
|
370
|
+
: "npx @bpmnkit/proxy — then reopen";
|
|
371
|
+
return {
|
|
372
|
+
kind: "ai",
|
|
373
|
+
title: `Ask AI: "${query.trim()}"`,
|
|
374
|
+
description,
|
|
375
|
+
disabled: ready !== true,
|
|
376
|
+
action() {
|
|
377
|
+
if (ready !== true)
|
|
378
|
+
return;
|
|
379
|
+
options.onAskAI?.(query.trim());
|
|
380
|
+
closePalette();
|
|
381
|
+
},
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function buildSections(query) {
|
|
385
|
+
// Pushed view: show only the pushed commands, no docs/AI
|
|
386
|
+
const activeView = _viewStack[_viewStack.length - 1];
|
|
387
|
+
if (activeView) {
|
|
388
|
+
const items = activeView.cmds
|
|
389
|
+
.filter((c) => !query ||
|
|
390
|
+
wordsMatch(c.title, query) ||
|
|
391
|
+
(c.description != null && wordsMatch(c.description, query)))
|
|
392
|
+
.map((c) => ({
|
|
393
|
+
kind: "command",
|
|
394
|
+
title: c.title,
|
|
395
|
+
description: c.description,
|
|
396
|
+
action: c.action,
|
|
397
|
+
}));
|
|
398
|
+
return items.length > 0 ? [{ items }] : [];
|
|
399
|
+
}
|
|
400
|
+
const sections = [];
|
|
401
|
+
const cmdItems = buildCommandItems(query);
|
|
402
|
+
if (cmdItems.length > 0)
|
|
403
|
+
sections.push({ items: cmdItems });
|
|
404
|
+
const docItems = buildDocItems(query);
|
|
405
|
+
if (docItems.length > 0)
|
|
406
|
+
sections.push({ label: "Documentation", items: docItems });
|
|
407
|
+
if (options.onAskAI && query.trim().length > 0) {
|
|
408
|
+
sections.push({ label: "AI", items: [buildAiItem(query)] });
|
|
409
|
+
}
|
|
410
|
+
// Show "Commands" label only when there are other sections too
|
|
411
|
+
const first = sections[0];
|
|
412
|
+
if (sections.length > 1 && first && !first.label && first.items.length > 0) {
|
|
413
|
+
first.label = "Commands";
|
|
414
|
+
}
|
|
415
|
+
return sections;
|
|
416
|
+
}
|
|
150
417
|
// ── Palette open / close ──────────────────────────────────────────────────
|
|
151
418
|
function openPalette() {
|
|
152
419
|
if (!_api)
|
|
@@ -155,6 +422,7 @@ export function createCommandPalettePlugin(options = {}) {
|
|
|
155
422
|
_closeCurrent = closePalette;
|
|
156
423
|
_isOpen = true;
|
|
157
424
|
_focusedIndex = 0;
|
|
425
|
+
startProxyCheck();
|
|
158
426
|
const isDark = resolveTheme(_api.getTheme()) === "dark";
|
|
159
427
|
const overlay = document.createElement("div");
|
|
160
428
|
overlay.className = isDark
|
|
@@ -175,7 +443,7 @@ export function createCommandPalettePlugin(options = {}) {
|
|
|
175
443
|
const input = document.createElement("input");
|
|
176
444
|
input.type = "text";
|
|
177
445
|
input.className = "bpmnkit-palette-input";
|
|
178
|
-
input.placeholder = "Search commands\u2026";
|
|
446
|
+
input.placeholder = "Search commands or docs\u2026";
|
|
179
447
|
input.setAttribute("autocomplete", "off");
|
|
180
448
|
input.setAttribute("spellcheck", "false");
|
|
181
449
|
searchRow.appendChild(input);
|
|
@@ -212,75 +480,113 @@ export function createCommandPalettePlugin(options = {}) {
|
|
|
212
480
|
if (!_isOpen)
|
|
213
481
|
return;
|
|
214
482
|
_isOpen = false;
|
|
483
|
+
_proxyCheckId++; // invalidate any pending fetch
|
|
484
|
+
_proxyReady = null;
|
|
485
|
+
_viewStack.length = 0;
|
|
215
486
|
if (_closeCurrent === closePalette)
|
|
216
487
|
_closeCurrent = null;
|
|
217
488
|
_overlayEl?.remove();
|
|
218
489
|
_overlayEl = null;
|
|
219
490
|
_inputEl = null;
|
|
220
491
|
_listEl = null;
|
|
492
|
+
_focusableItems = [];
|
|
221
493
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
494
|
+
function popView() {
|
|
495
|
+
_viewStack.pop();
|
|
496
|
+
const prev = _viewStack[_viewStack.length - 1];
|
|
497
|
+
if (_inputEl) {
|
|
498
|
+
_inputEl.value = "";
|
|
499
|
+
_inputEl.placeholder = prev?.placeholder ?? "Search commands or docs\u2026";
|
|
500
|
+
}
|
|
501
|
+
_focusedIndex = 0;
|
|
502
|
+
renderList("");
|
|
229
503
|
}
|
|
504
|
+
// ── List rendering ────────────────────────────────────────────────────────
|
|
230
505
|
function renderList(query) {
|
|
231
506
|
if (!_listEl)
|
|
232
507
|
return;
|
|
233
508
|
_listEl.innerHTML = "";
|
|
234
|
-
|
|
235
|
-
|
|
509
|
+
_focusableItems = [];
|
|
510
|
+
const sections = buildSections(query);
|
|
511
|
+
const totalItems = sections.reduce((n, s) => n + s.items.length, 0);
|
|
512
|
+
if (totalItems === 0) {
|
|
236
513
|
const empty = document.createElement("div");
|
|
237
514
|
empty.className = "bpmnkit-palette-empty";
|
|
238
|
-
|
|
515
|
+
const activeView = _viewStack[_viewStack.length - 1];
|
|
516
|
+
empty.textContent = activeView?.onConfirm
|
|
517
|
+
? "Press \u21b5 to confirm, Esc to go back"
|
|
518
|
+
: "No commands found";
|
|
239
519
|
_listEl.appendChild(empty);
|
|
240
520
|
return;
|
|
241
521
|
}
|
|
242
|
-
if (_focusedIndex >=
|
|
522
|
+
if (_focusedIndex >= totalItems)
|
|
243
523
|
_focusedIndex = 0;
|
|
244
|
-
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
? "bpmnkit-palette-item bpmnkit-palette-focused"
|
|
251
|
-
: "bpmnkit-palette-item";
|
|
252
|
-
item.setAttribute("role", "option");
|
|
253
|
-
item.setAttribute("aria-selected", String(i === _focusedIndex));
|
|
254
|
-
const titleEl = document.createElement("span");
|
|
255
|
-
titleEl.className = "bpmnkit-palette-item-title";
|
|
256
|
-
titleEl.textContent = cmd.title;
|
|
257
|
-
item.appendChild(titleEl);
|
|
258
|
-
if (cmd.description) {
|
|
259
|
-
const descEl = document.createElement("span");
|
|
260
|
-
descEl.className = "bpmnkit-palette-item-desc";
|
|
261
|
-
descEl.textContent = cmd.description;
|
|
262
|
-
item.appendChild(descEl);
|
|
524
|
+
for (const section of sections) {
|
|
525
|
+
if (section.label) {
|
|
526
|
+
const labelEl = document.createElement("div");
|
|
527
|
+
labelEl.className = "bpmnkit-palette-section";
|
|
528
|
+
labelEl.textContent = section.label;
|
|
529
|
+
_listEl.appendChild(labelEl);
|
|
263
530
|
}
|
|
264
|
-
item.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
531
|
+
for (const item of section.items) {
|
|
532
|
+
const focusableIdx = _focusableItems.length;
|
|
533
|
+
_focusableItems.push(item);
|
|
534
|
+
const el = document.createElement("div");
|
|
535
|
+
el.className = buildItemClass(item, focusableIdx);
|
|
536
|
+
el.setAttribute("role", "option");
|
|
537
|
+
el.setAttribute("aria-selected", String(focusableIdx === _focusedIndex));
|
|
538
|
+
el.setAttribute("aria-disabled", String(item.disabled ?? false));
|
|
539
|
+
// Leading icon
|
|
540
|
+
if (item.kind === "doc" || item.kind === "ai") {
|
|
541
|
+
const iconSpan = document.createElement("span");
|
|
542
|
+
iconSpan.className = "bpmnkit-palette-item-icon";
|
|
543
|
+
iconSpan.innerHTML = item.kind === "doc" ? EXTERNAL_ICON : AI_ICON;
|
|
544
|
+
el.appendChild(iconSpan);
|
|
545
|
+
}
|
|
546
|
+
const titleEl = document.createElement("span");
|
|
547
|
+
titleEl.className = "bpmnkit-palette-item-title";
|
|
548
|
+
titleEl.textContent = item.title;
|
|
549
|
+
el.appendChild(titleEl);
|
|
550
|
+
if (item.description) {
|
|
551
|
+
const descEl = document.createElement("span");
|
|
552
|
+
descEl.className = "bpmnkit-palette-item-desc";
|
|
553
|
+
descEl.textContent = item.description;
|
|
554
|
+
el.appendChild(descEl);
|
|
555
|
+
}
|
|
556
|
+
el.addEventListener("pointerenter", () => {
|
|
557
|
+
_focusedIndex = focusableIdx;
|
|
558
|
+
updateFocus();
|
|
559
|
+
});
|
|
560
|
+
el.addEventListener("pointerdown", (e) => {
|
|
561
|
+
e.preventDefault();
|
|
562
|
+
if (!item.disabled)
|
|
563
|
+
item.action();
|
|
564
|
+
});
|
|
565
|
+
_listEl.appendChild(el);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
function buildItemClass(item, idx) {
|
|
570
|
+
const classes = ["bpmnkit-palette-item"];
|
|
571
|
+
if (item.kind !== "command")
|
|
572
|
+
classes.push(`bpmnkit-palette-item--${item.kind}`);
|
|
573
|
+
if (item.disabled)
|
|
574
|
+
classes.push("bpmnkit-palette-item--disabled");
|
|
575
|
+
if (idx === _focusedIndex)
|
|
576
|
+
classes.push("bpmnkit-palette-focused");
|
|
577
|
+
return classes.join(" ");
|
|
274
578
|
}
|
|
275
579
|
function updateFocus() {
|
|
276
580
|
if (!_listEl)
|
|
277
581
|
return;
|
|
278
582
|
const items = _listEl.querySelectorAll(".bpmnkit-palette-item");
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
583
|
+
let focusableIdx = 0;
|
|
584
|
+
for (const el of items) {
|
|
585
|
+
const focused = focusableIdx === _focusedIndex;
|
|
586
|
+
el.classList.toggle("bpmnkit-palette-focused", focused);
|
|
587
|
+
el.setAttribute("aria-selected", String(focused));
|
|
588
|
+
focusableIdx++;
|
|
589
|
+
}
|
|
284
590
|
}
|
|
285
591
|
function scrollFocusedIntoView() {
|
|
286
592
|
if (!_listEl)
|
|
@@ -293,8 +599,7 @@ export function createCommandPalettePlugin(options = {}) {
|
|
|
293
599
|
function onPaletteKeyDown(e) {
|
|
294
600
|
if (!_listEl || !_inputEl)
|
|
295
601
|
return;
|
|
296
|
-
const
|
|
297
|
-
const count = cmds.length;
|
|
602
|
+
const count = _focusableItems.length;
|
|
298
603
|
if (e.key === "ArrowDown") {
|
|
299
604
|
e.preventDefault();
|
|
300
605
|
if (count > 0) {
|
|
@@ -313,13 +618,22 @@ export function createCommandPalettePlugin(options = {}) {
|
|
|
313
618
|
}
|
|
314
619
|
else if (e.key === "Enter") {
|
|
315
620
|
e.preventDefault();
|
|
316
|
-
const
|
|
317
|
-
if (
|
|
318
|
-
|
|
621
|
+
const activeView = _viewStack[_viewStack.length - 1];
|
|
622
|
+
if (activeView?.onConfirm) {
|
|
623
|
+
activeView.onConfirm(_inputEl.value);
|
|
624
|
+
closePalette();
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
const item = _focusableItems[_focusedIndex];
|
|
628
|
+
if (item && !item.disabled)
|
|
629
|
+
item.action();
|
|
319
630
|
}
|
|
320
631
|
else if (e.key === "Escape") {
|
|
321
632
|
e.preventDefault();
|
|
322
|
-
|
|
633
|
+
if (_viewStack.length > 0)
|
|
634
|
+
popView();
|
|
635
|
+
else
|
|
636
|
+
closePalette();
|
|
323
637
|
}
|
|
324
638
|
}
|
|
325
639
|
const onDocKeyDown = (e) => {
|
|
@@ -373,6 +687,22 @@ export function createCommandPalettePlugin(options = {}) {
|
|
|
373
687
|
}
|
|
374
688
|
};
|
|
375
689
|
},
|
|
690
|
+
pushView(cmds, opts = {}) {
|
|
691
|
+
if (!_isOpen)
|
|
692
|
+
return;
|
|
693
|
+
const view = {
|
|
694
|
+
cmds,
|
|
695
|
+
placeholder: opts.placeholder ?? "Select\u2026",
|
|
696
|
+
onConfirm: opts.onConfirm,
|
|
697
|
+
};
|
|
698
|
+
_viewStack.push(view);
|
|
699
|
+
if (_inputEl) {
|
|
700
|
+
_inputEl.value = "";
|
|
701
|
+
_inputEl.placeholder = view.placeholder;
|
|
702
|
+
}
|
|
703
|
+
_focusedIndex = 0;
|
|
704
|
+
renderList("");
|
|
705
|
+
},
|
|
376
706
|
};
|
|
377
707
|
}
|
|
378
708
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @bpmnkit/canvas-plugin-command-palette-editor — editor extension for the
|
|
3
|
-
* command palette plugin. Adds one command per BPMN element type.
|
|
3
|
+
* command palette plugin. Adds one command per BPMN element type. When
|
|
4
|
+
* executed, shows a second-step picker listing candidate source nodes to
|
|
5
|
+
* connect after. Falls back to `setTool` (free-click placement) when the
|
|
6
|
+
* diagram is empty.
|
|
4
7
|
*
|
|
5
8
|
* Must be used together with `@bpmnkit/canvas-plugin-command-palette`.
|
|
6
9
|
*
|
|
@@ -11,9 +14,7 @@
|
|
|
11
14
|
*
|
|
12
15
|
* let editorRef: BpmnEditor | null = null;
|
|
13
16
|
* const palette = createCommandPalettePlugin({ ... });
|
|
14
|
-
* const paletteEditor = createCommandPaletteEditorPlugin(palette, (
|
|
15
|
-
* editorRef?.setTool(tool);
|
|
16
|
-
* });
|
|
17
|
+
* const paletteEditor = createCommandPaletteEditorPlugin(palette, () => editorRef);
|
|
17
18
|
* const editor = new BpmnEditor({ container, xml, plugins: [palette, paletteEditor] });
|
|
18
19
|
* editorRef = editor;
|
|
19
20
|
* ```
|
|
@@ -21,15 +22,19 @@
|
|
|
21
22
|
* @packageDocumentation
|
|
22
23
|
*/
|
|
23
24
|
import type { CanvasPlugin } from "@bpmnkit/canvas";
|
|
25
|
+
import type { CreateShapeType } from "@bpmnkit/editor";
|
|
24
26
|
import type { CommandPalettePlugin } from "../command-palette/index.js";
|
|
27
|
+
/** Subset of BpmnEditor needed by this plugin. */
|
|
28
|
+
export interface EditorLike {
|
|
29
|
+
setTool(tool: string): void;
|
|
30
|
+
addConnectedElement(sourceId: string, type: CreateShapeType, name?: string): string | null;
|
|
31
|
+
}
|
|
25
32
|
/**
|
|
26
33
|
* Creates the editor command palette extension plugin.
|
|
27
34
|
*
|
|
28
|
-
* @param palette
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* editor (e.g. `editor.setTool`). May reference the editor lazily — it is
|
|
32
|
-
* only called when the user executes a command, well after construction.
|
|
35
|
+
* @param palette The base command palette plugin.
|
|
36
|
+
* @param getEditor Lazy getter returning the editor instance (or null before
|
|
37
|
+
* it is created). Called only when the user executes a command.
|
|
33
38
|
*/
|
|
34
|
-
export declare function createCommandPaletteEditorPlugin(palette: CommandPalettePlugin,
|
|
39
|
+
export declare function createCommandPaletteEditorPlugin(palette: CommandPalettePlugin, getEditor: () => EditorLike | null): CanvasPlugin;
|
|
35
40
|
//# sourceMappingURL=index.d.ts.map
|