@bpmn-nova/studio 0.3.0-preview → 0.3.2-preview

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.
Files changed (63) hide show
  1. package/README.md +245 -20
  2. package/dist/canvas.js +7 -4
  3. package/dist/context-menu.js +2 -2
  4. package/dist/controller.js +84 -6
  5. package/dist/index.d.ts +138 -38
  6. package/dist/index.js +12 -11
  7. package/dist/interactions.js +1 -1
  8. package/dist/modules/bpmn-model/index.d.ts +11 -0
  9. package/dist/modules/bpmn-model/index.js +703 -0
  10. package/dist/modules/core/containment.js +590 -0
  11. package/dist/modules/core/gateway.js +72 -0
  12. package/dist/modules/core/history.js +32 -0
  13. package/dist/modules/core/index.d.ts +268 -0
  14. package/dist/modules/core/index.js +7 -0
  15. package/dist/modules/core/layout.js +644 -0
  16. package/dist/modules/core/model.js +287 -0
  17. package/dist/modules/core/runtime-transition-route.js +360 -0
  18. package/dist/modules/core/scope.js +99 -0
  19. package/dist/modules/designer/index.d.ts +79 -0
  20. package/dist/modules/designer/index.js +607 -0
  21. package/dist/modules/engine-activiti/index.d.ts +19 -0
  22. package/dist/modules/engine-activiti/index.js +160 -0
  23. package/dist/modules/engine-flowable/index.d.ts +19 -0
  24. package/dist/modules/engine-flowable/index.js +160 -0
  25. package/dist/modules/export-svg/index.d.ts +112 -0
  26. package/dist/modules/export-svg/index.js +2 -0
  27. package/dist/modules/export-svg/preview.js +327 -0
  28. package/dist/modules/export-svg/render.js +718 -0
  29. package/dist/modules/icons/index.d.ts +24 -0
  30. package/dist/modules/icons/index.js +264 -0
  31. package/dist/modules/palette/index.d.ts +74 -0
  32. package/dist/modules/palette/index.js +99 -0
  33. package/dist/modules/palette/panel.js +99 -0
  34. package/dist/modules/properties/index.d.ts +20 -0
  35. package/dist/modules/properties/index.js +19 -0
  36. package/dist/modules/properties-activiti/index.d.ts +3 -0
  37. package/dist/modules/properties-activiti/index.js +97 -0
  38. package/dist/modules/properties-bpmn/index.d.ts +3 -0
  39. package/dist/modules/properties-bpmn/index.js +518 -0
  40. package/dist/modules/properties-core/index.d.ts +124 -0
  41. package/dist/modules/properties-core/index.js +312 -0
  42. package/dist/modules/properties-flowable/index.d.ts +3 -0
  43. package/dist/modules/properties-flowable/index.js +114 -0
  44. package/dist/modules/properties-renderer/index.d.ts +25 -0
  45. package/dist/modules/properties-renderer/index.js +491 -0
  46. package/dist/modules/renderer-svg/index.d.ts +118 -0
  47. package/dist/modules/renderer-svg/index.js +1460 -0
  48. package/dist/modules/runtime/index.d.ts +169 -0
  49. package/dist/modules/runtime/index.js +535 -0
  50. package/dist/modules/theme/index.d.ts +95 -0
  51. package/dist/modules/theme/index.js +368 -0
  52. package/dist/modules/viewer/index.d.ts +265 -0
  53. package/dist/modules/viewer/index.js +1011 -0
  54. package/dist/modules/viewer/runtime-content.js +123 -0
  55. package/dist/modules/viewer/runtime-details-motion.js +228 -0
  56. package/dist/modules/viewer/runtime-trace.js +574 -0
  57. package/dist/modules/viewer/timeline.js +276 -0
  58. package/dist/selection-layout.js +1 -1
  59. package/dist/shell.js +210 -26
  60. package/dist/styles.css +116 -7
  61. package/llms-full.txt +3082 -0
  62. package/llms.txt +225 -0
  63. package/package.json +39 -16
@@ -0,0 +1,123 @@
1
+ function element(tag, className, text) {
2
+ const node = document.createElement(tag);
3
+ if (className) node.className = className;
4
+ if (text !== undefined) node.textContent = text;
5
+ return node;
6
+ }
7
+
8
+ export function formatRuntimeAssetSize(value) {
9
+ const bytes = Number(value);
10
+ if (!Number.isFinite(bytes) || bytes < 0) return '';
11
+ if (bytes < 1024) return `${bytes} B`;
12
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(bytes < 10240 ? 1 : 0)} KB`;
13
+ return `${(bytes / (1024 * 1024)).toFixed(bytes < 1024 * 10240 ? 1 : 0)} MB`;
14
+ }
15
+
16
+ function assetMeta(asset) {
17
+ return [asset.mediaType, formatRuntimeAssetSize(asset.size)].filter(Boolean).join(' · ');
18
+ }
19
+
20
+ function unavailable(target, label = '资源不可用') {
21
+ target.classList.add('is-unavailable');
22
+ target.setAttribute('aria-disabled', 'true');
23
+ const state = target.querySelector('.mb-runtime-asset-state');
24
+ if (state) state.textContent = label;
25
+ }
26
+
27
+ function renderImage({ host, asset, action, resolveAsset, onPreview, compact, alt }) {
28
+ const button = element('button', 'mb-runtime-asset-image is-loading');
29
+ button.type = 'button';
30
+ button.setAttribute('aria-label', `预览图片:${alt || asset.name}`);
31
+ const state = element('span', 'mb-runtime-asset-state', '图片加载中');
32
+ button.appendChild(state);
33
+ host.appendChild(button);
34
+ Promise.resolve(resolveAsset?.(asset, 'thumbnail', action)).then((url) => {
35
+ if (!button.isConnected) return;
36
+ if (!url) { unavailable(button); return; }
37
+ const image = document.createElement('img');
38
+ image.alt = alt || asset.name;
39
+ image.loading = 'lazy';
40
+ image.addEventListener('error', () => {
41
+ if (!button.isConnected) return;
42
+ button.replaceChildren(element('span', 'mb-runtime-asset-state', '资源不可用'));
43
+ unavailable(button);
44
+ }, { once: true });
45
+ image.src = url;
46
+ button.replaceChildren(image);
47
+ button.classList.remove('is-loading');
48
+ button.addEventListener('click', () => onPreview?.(asset, action));
49
+ }).catch(() => { if (button.isConnected) unavailable(button); });
50
+ if (!compact) button.title = assetMeta(asset);
51
+ }
52
+
53
+ function renderFile({ host, asset, action, resolveAsset }) {
54
+ const link = element('a', 'mb-runtime-asset-file is-loading');
55
+ link.setAttribute('aria-label', `下载附件:${asset.name}`);
56
+ const copy = element('span', 'mb-runtime-asset-file-copy');
57
+ copy.append(element('strong', '', asset.name), element('small', '', assetMeta(asset)));
58
+ link.append(copy, element('span', 'mb-runtime-asset-state', '准备下载'));
59
+ host.appendChild(link);
60
+ Promise.resolve(resolveAsset?.(asset, 'download', action)).then((url) => {
61
+ if (!link.isConnected) return;
62
+ if (!url) { unavailable(link); return; }
63
+ link.href = url;
64
+ link.target = '_blank';
65
+ link.rel = 'noopener noreferrer';
66
+ link.download = asset.name;
67
+ link.classList.remove('is-loading');
68
+ link.querySelector('.mb-runtime-asset-state').textContent = '下载';
69
+ }).catch(() => { if (link.isConnected) unavailable(link); });
70
+ }
71
+
72
+ export function renderRuntimeApprovalContent({
73
+ container,
74
+ action,
75
+ resolveAsset,
76
+ onPreview,
77
+ compact = false,
78
+ imageLimit = compact ? 3 : Number.POSITIVE_INFINITY,
79
+ }) {
80
+ const content = action?.content || { plainText: '', blocks: [], assets: [] };
81
+ const assets = new Map((content.assets || []).map((asset) => [asset.id, asset]));
82
+ const root = element('div', `mb-runtime-action-content${compact ? ' is-compact' : ''}`);
83
+ const media = element('div', 'mb-runtime-action-media');
84
+ let imageCount = 0;
85
+ let rendered = 0;
86
+
87
+ (content.blocks || []).forEach((block) => {
88
+ if (block.type === 'paragraph') {
89
+ if (block.text) { root.appendChild(element('p', 'mb-runtime-action-paragraph', block.text)); rendered += 1; }
90
+ return;
91
+ }
92
+ if (block.type === 'image') {
93
+ imageCount += 1;
94
+ if (imageCount > imageLimit) return;
95
+ const asset = assets.get(block.assetId);
96
+ if (!asset || !asset.mediaType.startsWith('image/')) {
97
+ media.appendChild(element('span', 'mb-runtime-asset-unsupported', '图片资源不可用'));
98
+ } else {
99
+ renderImage({ host: media, asset, action, resolveAsset, onPreview, compact, alt: block.alt });
100
+ }
101
+ rendered += 1;
102
+ return;
103
+ }
104
+ if (block.type === 'file') {
105
+ const asset = assets.get(block.assetId);
106
+ if (!asset) media.appendChild(element('span', 'mb-runtime-asset-unsupported', '附件资源不可用'));
107
+ else renderFile({ host: media, asset, action, resolveAsset });
108
+ rendered += 1;
109
+ return;
110
+ }
111
+ root.appendChild(element('p', 'mb-runtime-asset-unsupported', `暂不支持的内容:${block.type || 'unknown'}`));
112
+ rendered += 1;
113
+ });
114
+
115
+ if (!content.blocks?.length && content.plainText) {
116
+ root.appendChild(element('p', 'mb-runtime-action-paragraph', content.plainText));
117
+ rendered += 1;
118
+ }
119
+ if (imageCount > imageLimit) media.appendChild(element('span', 'mb-runtime-asset-more', `+${imageCount - imageLimit}`));
120
+ if (media.childNodes.length) root.appendChild(media);
121
+ if (rendered || media.childNodes.length) container.appendChild(root);
122
+ return () => root.remove();
123
+ }
@@ -0,0 +1,228 @@
1
+ const DRAG_SLOP = 6;
2
+ const DISMISS_DISTANCE = 120;
3
+ const DISMISS_DISTANCE_RATIO = 0.25;
4
+ const DISMISS_VELOCITY = 0.65;
5
+ const VELOCITY_WINDOW = 100;
6
+ const EXIT_FALLBACK = 320;
7
+
8
+ function prefersReducedMotion() {
9
+ return typeof window !== 'undefined'
10
+ && typeof window.matchMedia === 'function'
11
+ && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
12
+ }
13
+
14
+ function clamp(value, minimum, maximum) {
15
+ return Math.min(maximum, Math.max(minimum, value));
16
+ }
17
+
18
+ export function createRuntimeDetailsMotionController({
19
+ layer,
20
+ panel,
21
+ handle = null,
22
+ placement,
23
+ dragToDismiss = false,
24
+ onDismissed,
25
+ }) {
26
+ let enterFrame = 0;
27
+ let settleFrame = 0;
28
+ let settleTimer = 0;
29
+ let exitTimer = 0;
30
+ let closing = false;
31
+ let disposed = false;
32
+ let pointer = null;
33
+
34
+ const canDrag = placement === 'bottom' && dragToDismiss && handle;
35
+
36
+ const clearSettle = () => {
37
+ if (settleFrame) cancelAnimationFrame(settleFrame);
38
+ if (settleTimer) clearTimeout(settleTimer);
39
+ settleFrame = 0;
40
+ settleTimer = 0;
41
+ layer.classList.remove('is-settling');
42
+ };
43
+
44
+ const resetDragStyles = () => {
45
+ layer.style.removeProperty('--mb-runtime-details-drag-offset');
46
+ layer.style.removeProperty('--mb-runtime-details-backdrop-progress');
47
+ layer.classList.remove('is-dragging');
48
+ };
49
+
50
+ const releasePointer = () => {
51
+ if (pointer && handle?.hasPointerCapture?.(pointer.id)) handle.releasePointerCapture(pointer.id);
52
+ pointer = null;
53
+ document.documentElement.classList.remove('mb-runtime-details-drag-active');
54
+ };
55
+
56
+ const removePointerListeners = () => {
57
+ if (!canDrag) return;
58
+ handle.removeEventListener('pointerdown', onPointerDown);
59
+ handle.removeEventListener('pointermove', onPointerMove);
60
+ handle.removeEventListener('pointerup', onPointerUp);
61
+ handle.removeEventListener('pointercancel', onPointerCancel);
62
+ };
63
+
64
+ const finish = (restoreFocus) => {
65
+ if (disposed) return;
66
+ disposed = true;
67
+ if (enterFrame) cancelAnimationFrame(enterFrame);
68
+ if (exitTimer) clearTimeout(exitTimer);
69
+ clearSettle();
70
+ releasePointer();
71
+ removePointerListeners();
72
+ panel.removeEventListener('transitionend', onExitTransitionEnd);
73
+ onDismissed({ restoreFocus });
74
+ };
75
+
76
+ const onExitTransitionEnd = (event) => {
77
+ if (event.target !== panel || event.propertyName !== 'transform') return;
78
+ finish(layer.dataset.runtimeDetailsRestoreFocus === 'true');
79
+ };
80
+
81
+ const dismiss = ({ immediate = false, restoreFocus = true } = {}) => {
82
+ if (disposed) return false;
83
+ layer.dataset.runtimeDetailsRestoreFocus = String(restoreFocus);
84
+ if (immediate || prefersReducedMotion()) {
85
+ finish(restoreFocus);
86
+ return true;
87
+ }
88
+ if (closing) return false;
89
+ closing = true;
90
+ if (enterFrame) cancelAnimationFrame(enterFrame);
91
+ clearSettle();
92
+ releasePointer();
93
+ panel.getBoundingClientRect();
94
+ layer.classList.remove('is-entering', 'is-open', 'is-dragging');
95
+ layer.classList.add('is-closing');
96
+ panel.addEventListener('transitionend', onExitTransitionEnd);
97
+ exitTimer = window.setTimeout(() => finish(restoreFocus), EXIT_FALLBACK);
98
+ return true;
99
+ };
100
+
101
+ const settle = () => {
102
+ clearSettle();
103
+ layer.classList.remove('is-dragging');
104
+ if (prefersReducedMotion()) {
105
+ resetDragStyles();
106
+ return;
107
+ }
108
+ layer.classList.add('is-settling');
109
+ panel.getBoundingClientRect();
110
+ settleFrame = requestAnimationFrame(() => {
111
+ settleFrame = 0;
112
+ layer.style.setProperty('--mb-runtime-details-drag-offset', '0px');
113
+ layer.style.setProperty('--mb-runtime-details-backdrop-progress', '1');
114
+ settleTimer = window.setTimeout(() => {
115
+ settleTimer = 0;
116
+ clearSettle();
117
+ resetDragStyles();
118
+ }, 220);
119
+ });
120
+ };
121
+
122
+ const resetPointer = () => {
123
+ releasePointer();
124
+ };
125
+
126
+ function onPointerDown(event) {
127
+ if (disposed || closing || pointer || (event.pointerType === 'mouse' && event.button !== 0)) return;
128
+ clearSettle();
129
+ pointer = {
130
+ id: event.pointerId,
131
+ startX: event.clientX,
132
+ startY: event.clientY,
133
+ dragging: false,
134
+ rejected: false,
135
+ height: Math.max(1, panel.getBoundingClientRect().height),
136
+ samples: [{ time: event.timeStamp, offset: 0 }],
137
+ };
138
+ handle.setPointerCapture?.(event.pointerId);
139
+ }
140
+
141
+ function onPointerMove(event) {
142
+ if (!pointer || event.pointerId !== pointer.id || pointer.rejected) return;
143
+ const deltaX = event.clientX - pointer.startX;
144
+ const deltaY = event.clientY - pointer.startY;
145
+ if (!pointer.dragging) {
146
+ if (Math.hypot(deltaX, deltaY) < DRAG_SLOP) return;
147
+ if (Math.abs(deltaY) <= Math.abs(deltaX) || deltaY < 0) {
148
+ pointer.rejected = true;
149
+ resetPointer();
150
+ return;
151
+ }
152
+ pointer.dragging = true;
153
+ layer.classList.add('is-dragging');
154
+ document.documentElement.classList.add('mb-runtime-details-drag-active');
155
+ }
156
+ event.preventDefault();
157
+ const offset = Math.max(0, deltaY);
158
+ const progress = 1 - clamp(offset / pointer.height, 0, 1);
159
+ layer.style.setProperty('--mb-runtime-details-drag-offset', `${offset}px`);
160
+ layer.style.setProperty('--mb-runtime-details-backdrop-progress', String(progress));
161
+ pointer.samples.push({ time: event.timeStamp, offset });
162
+ const cutoff = event.timeStamp - VELOCITY_WINDOW;
163
+ while (pointer.samples.length > 2 && pointer.samples[0].time < cutoff) pointer.samples.shift();
164
+ }
165
+
166
+ function onPointerUp(event) {
167
+ if (!pointer || event.pointerId !== pointer.id) return;
168
+ const activePointer = pointer;
169
+ const offset = Math.max(0, event.clientY - activePointer.startY);
170
+ activePointer.samples.push({ time: event.timeStamp, offset });
171
+ const cutoff = event.timeStamp - VELOCITY_WINDOW;
172
+ while (activePointer.samples.length > 2 && activePointer.samples[0].time < cutoff) activePointer.samples.shift();
173
+ const firstSample = activePointer.samples[0];
174
+ const lastSample = activePointer.samples.at(-1) || firstSample;
175
+ const elapsed = Math.max(1, lastSample.time - firstSample.time);
176
+ const velocity = (lastSample.offset - firstSample.offset) / elapsed;
177
+ const threshold = Math.min(DISMISS_DISTANCE, activePointer.height * DISMISS_DISTANCE_RATIO);
178
+ const shouldDismiss = activePointer.dragging
179
+ && (offset >= threshold || velocity >= DISMISS_VELOCITY);
180
+ resetPointer();
181
+ if (!activePointer.dragging) return;
182
+ if (shouldDismiss) dismiss({ restoreFocus: true });
183
+ else settle();
184
+ }
185
+
186
+ function onPointerCancel(event) {
187
+ if (!pointer || event.pointerId !== pointer.id) return;
188
+ const wasDragging = pointer.dragging;
189
+ resetPointer();
190
+ if (wasDragging) settle();
191
+ }
192
+
193
+ const enter = () => {
194
+ if (disposed || closing) return;
195
+ panel.getBoundingClientRect();
196
+ if (prefersReducedMotion()) {
197
+ layer.classList.remove('is-entering');
198
+ layer.classList.add('is-open');
199
+ return;
200
+ }
201
+ enterFrame = requestAnimationFrame(() => {
202
+ enterFrame = 0;
203
+ if (disposed || closing) return;
204
+ layer.classList.remove('is-entering');
205
+ layer.classList.add('is-open');
206
+ });
207
+ };
208
+
209
+ const destroy = () => {
210
+ if (disposed) return;
211
+ disposed = true;
212
+ if (enterFrame) cancelAnimationFrame(enterFrame);
213
+ if (exitTimer) clearTimeout(exitTimer);
214
+ clearSettle();
215
+ resetPointer();
216
+ removePointerListeners();
217
+ panel.removeEventListener('transitionend', onExitTransitionEnd);
218
+ };
219
+
220
+ if (canDrag) {
221
+ handle.addEventListener('pointerdown', onPointerDown);
222
+ handle.addEventListener('pointermove', onPointerMove);
223
+ handle.addEventListener('pointerup', onPointerUp);
224
+ handle.addEventListener('pointercancel', onPointerCancel);
225
+ }
226
+
227
+ return { enter, dismiss, destroy };
228
+ }