@baron1996/klinecharts-runtime 0.3.0 → 0.4.0

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 (45) hide show
  1. package/README.md +1 -1
  2. package/dist/drawing/capabilities.d.ts +36 -0
  3. package/dist/drawing/capabilities.d.ts.map +1 -0
  4. package/dist/drawing/capabilities.js +1 -0
  5. package/dist/drawing/legacy-runtime-capability.d.ts +8 -0
  6. package/dist/drawing/legacy-runtime-capability.d.ts.map +1 -0
  7. package/dist/drawing/legacy-runtime-capability.js +92 -0
  8. package/dist/drawing/projection-service.d.ts +80 -0
  9. package/dist/drawing/projection-service.d.ts.map +1 -0
  10. package/dist/drawing/projection-service.js +523 -0
  11. package/dist/drawing/runtime-capability-descriptor.d.ts +28 -0
  12. package/dist/drawing/runtime-capability-descriptor.d.ts.map +1 -0
  13. package/dist/drawing/runtime-capability-descriptor.js +1 -0
  14. package/dist/drawing/scene-runtime-factory.d.ts +15 -0
  15. package/dist/drawing/scene-runtime-factory.d.ts.map +1 -0
  16. package/dist/drawing/scene-runtime-factory.js +27 -0
  17. package/dist/drawing/session-controller.d.ts +53 -0
  18. package/dist/drawing/session-controller.d.ts.map +1 -0
  19. package/dist/drawing/session-controller.js +339 -0
  20. package/dist/drawing/workspace-events.d.ts +66 -0
  21. package/dist/drawing/workspace-events.d.ts.map +1 -0
  22. package/dist/drawing/workspace-events.js +12 -0
  23. package/dist/drawing/workspace-runtime.d.ts +60 -0
  24. package/dist/drawing/workspace-runtime.d.ts.map +1 -0
  25. package/dist/drawing/workspace-runtime.js +328 -0
  26. package/dist/index.d.ts +8 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +8 -1
  29. package/dist/runtime.d.ts +29 -3
  30. package/dist/runtime.d.ts.map +1 -1
  31. package/dist/runtime.js +97 -1
  32. package/dist/toolbar/standard-toolbar-styles.d.ts.map +1 -1
  33. package/dist/toolbar/standard-toolbar-styles.js +18 -0
  34. package/dist/toolbar/standard-toolbar.d.ts +4 -2
  35. package/dist/toolbar/standard-toolbar.d.ts.map +1 -1
  36. package/dist/toolbar/standard-toolbar.js +187 -31
  37. package/dist/toolbar/toolbar-icons.d.ts +26 -0
  38. package/dist/toolbar/toolbar-icons.d.ts.map +1 -1
  39. package/dist/toolbar/toolbar-icons.js +13 -0
  40. package/dist/toolbar/toolbar-tools.d.ts +6 -1
  41. package/dist/toolbar/toolbar-tools.d.ts.map +1 -1
  42. package/dist/toolbar/toolbar-tools.js +6 -0
  43. package/dist/types.d.ts +7 -4
  44. package/dist/types.d.ts.map +1 -1
  45. package/package.json +4 -3
@@ -0,0 +1,339 @@
1
+ import { hashCanonicalDrawingDocument, } from '@baron1996/kline-scene-schema';
2
+ import { DrawingProjectionService, } from './projection-service.js';
3
+ import { deepFreeze } from './workspace-events.js';
4
+ export class DrawingSessionError extends Error {
5
+ code;
6
+ path;
7
+ constructor(code, path, message) {
8
+ super(message);
9
+ this.name = 'DrawingSessionError';
10
+ this.code = code;
11
+ this.path = path;
12
+ }
13
+ }
14
+ /**
15
+ * 场景无关的 Drawing 会话状态机。
16
+ * 所有变更都走 candidate 校验/投影/展示/确认链;进度事件永不改 confirmed。
17
+ */
18
+ export class DrawingSessionController {
19
+ #options;
20
+ #state = 'ready';
21
+ #confirmed = [];
22
+ #candidate = null;
23
+ #selectedId = null;
24
+ #requestSequence = 0;
25
+ #suppressEngineEvents = false;
26
+ #unsubscribeEngine;
27
+ constructor(options) {
28
+ this.#options = options;
29
+ this.#unsubscribeEngine = options.engine.subscribeDrawingEvents((event) => this.#handleEngineEvent(event));
30
+ }
31
+ get state() {
32
+ return this.#state;
33
+ }
34
+ get confirmedDrawings() {
35
+ this.#assertUsable();
36
+ return this.#confirmed.map((drawing) => structuredClone(drawing));
37
+ }
38
+ get selectedId() {
39
+ return this.#selectedId;
40
+ }
41
+ restoreConfirmed(drawings) {
42
+ this.#assertUsable();
43
+ this.#suppressEngineEvents = true;
44
+ try {
45
+ this.#confirmed = drawings.map((drawing) => structuredClone(drawing));
46
+ this.#options.engine.restoreDrawings(this.#confirmed);
47
+ }
48
+ finally {
49
+ this.#suppressEngineEvents = false;
50
+ }
51
+ }
52
+ startCreate(type, options) {
53
+ this.#assertReady();
54
+ this.#state = 'interacting';
55
+ try {
56
+ return this.#options.engine.startDrawing({
57
+ id: options?.id ?? `drawing-${++this.#requestSequence}`,
58
+ type: type,
59
+ target: structuredClone(this.#options.target),
60
+ styles: options?.styles ?? defaultStyles(),
61
+ ...(options?.text === undefined ? {} : { text: options.text }),
62
+ });
63
+ }
64
+ catch (error) {
65
+ this.#state = 'ready';
66
+ throw error;
67
+ }
68
+ }
69
+ updateDrawingStyles(id, styles) {
70
+ this.#assertReady();
71
+ return this.#options.engine.updateDrawingStyles(id, styles);
72
+ }
73
+ updateDrawingText(id, text) {
74
+ this.#assertReady();
75
+ return this.#options.engine.updateDrawingText(id, text);
76
+ }
77
+ removeDrawing(id) {
78
+ this.#assertReady();
79
+ return this.#options.engine.removeDrawing(id);
80
+ }
81
+ selectDrawing(id) {
82
+ this.#assertUsable();
83
+ this.#selectedId = id;
84
+ this.#options.engine.selectDrawing(id);
85
+ this.#options.emit({
86
+ type: 'selection-changed',
87
+ id,
88
+ });
89
+ }
90
+ commitDrawingChange(requestId, canonicalHash) {
91
+ this.#assertUsable();
92
+ if (this.#state !== 'awaiting-host-confirmation') {
93
+ throw new DrawingSessionError('DRAWING_CHANGE_IN_PROGRESS', '/drawings', 'There is no host-confirmed candidate waiting for commit.');
94
+ }
95
+ const candidate = this.#candidate;
96
+ if (candidate === null || candidate.requestId !== requestId) {
97
+ throw new DrawingSessionError('DRAWING_CHANGE_REJECTED', '/drawings', `Unknown drawing change request: ${requestId}.`);
98
+ }
99
+ if (candidate.canonicalHash !== canonicalHash) {
100
+ throw new DrawingSessionError('DRAWING_CHANGE_HASH_MISMATCH', '/drawings', 'Candidate canonical hash does not match the requested commit.');
101
+ }
102
+ this.#commitCandidate(candidate);
103
+ return true;
104
+ }
105
+ rejectDrawingChange(requestId) {
106
+ this.#assertUsable();
107
+ if (this.#state !== 'awaiting-host-confirmation') {
108
+ throw new DrawingSessionError('DRAWING_CHANGE_IN_PROGRESS', '/drawings', 'There is no host-confirmed candidate waiting for rejection.');
109
+ }
110
+ const candidate = this.#candidate;
111
+ if (candidate === null || candidate.requestId !== requestId) {
112
+ throw new DrawingSessionError('DRAWING_CHANGE_REJECTED', '/drawings', `Unknown drawing change request: ${requestId}.`);
113
+ }
114
+ try {
115
+ if (candidate.before !== undefined) {
116
+ this.#options.engine.restoreDrawing(candidate.before);
117
+ }
118
+ else {
119
+ this.#options.engine.removeDrawing(candidate.after.id);
120
+ }
121
+ }
122
+ catch (error) {
123
+ this.#enterTerminalError('DRAWING_PROJECTION_INVALID', `Failed to restore the rejected candidate: ${String(error)}`);
124
+ return false;
125
+ }
126
+ this.#candidate = null;
127
+ this.#state = 'ready';
128
+ this.#options.emit({
129
+ type: 'drawing-rejected',
130
+ requestId,
131
+ drawing: structuredClone(candidate.after),
132
+ document: structuredClone(candidate.document),
133
+ canonicalHash: candidate.canonicalHash,
134
+ });
135
+ return true;
136
+ }
137
+ enterTerminalError(code, message) {
138
+ this.#enterTerminalError(code, message);
139
+ }
140
+ destroy() {
141
+ if (this.#state === 'destroyed') {
142
+ return;
143
+ }
144
+ this.#state = 'destroyed';
145
+ this.#candidate = null;
146
+ this.#confirmed = [];
147
+ this.#unsubscribeEngine();
148
+ }
149
+ #handleEngineEvent(event) {
150
+ if (this.#suppressEngineEvents ||
151
+ this.#state === 'destroyed' ||
152
+ this.#state === 'terminal-error') {
153
+ return;
154
+ }
155
+ try {
156
+ if (event.type === 'created' || event.type === 'updated') {
157
+ if (event.drawing === undefined) {
158
+ return;
159
+ }
160
+ void this.#onMutation({
161
+ operation: event.type === 'created' ? 'create' : 'update',
162
+ ...(this.#confirmed.find((drawing) => drawing.id === event.id) === undefined
163
+ ? {}
164
+ : {
165
+ before: this.#confirmed.find((drawing) => drawing.id === event.id),
166
+ }),
167
+ after: event.drawing,
168
+ }).catch((error) => {
169
+ this.#options.emit({
170
+ type: 'workspace-error',
171
+ code: error instanceof DrawingSessionError
172
+ ? error.code
173
+ : 'DRAWING_PROJECTION_INVALID',
174
+ message: error instanceof Error
175
+ ? error.message
176
+ : String(error),
177
+ });
178
+ });
179
+ return;
180
+ }
181
+ if (event.type === 'removed') {
182
+ const before = this.#confirmed.find((drawing) => drawing.id === event.id);
183
+ if (before === undefined) {
184
+ return;
185
+ }
186
+ void this.#onMutation({
187
+ operation: 'delete',
188
+ before,
189
+ after: before,
190
+ }).catch((error) => {
191
+ this.#options.emit({
192
+ type: 'workspace-error',
193
+ code: error instanceof DrawingSessionError
194
+ ? error.code
195
+ : 'DRAWING_PROJECTION_INVALID',
196
+ message: error instanceof Error
197
+ ? error.message
198
+ : String(error),
199
+ });
200
+ });
201
+ return;
202
+ }
203
+ if (event.type === 'selected' || event.type === 'deselected') {
204
+ this.#selectedId = event.type === 'selected' ? event.id : null;
205
+ this.#options.emit({ type: 'selection-changed', id: this.#selectedId });
206
+ }
207
+ }
208
+ catch (error) {
209
+ if (error instanceof DrawingSessionError) {
210
+ this.#options.emit({
211
+ type: 'workspace-error',
212
+ code: error.code,
213
+ message: error.message,
214
+ });
215
+ }
216
+ }
217
+ }
218
+ async #onMutation(input) {
219
+ if (this.#state === 'awaiting-host-confirmation') {
220
+ throw new DrawingSessionError('DRAWING_CHANGE_IN_PROGRESS', '/drawings', 'A host-confirmed candidate is pending; new mutations are rejected.');
221
+ }
222
+ if (this.#state === 'interacting' && input.operation !== 'create') {
223
+ return;
224
+ }
225
+ const candidateDocument = this.#options.buildDocument(this.#confirmedWith(input.operation, input.before, input.after));
226
+ try {
227
+ const projected = this.#options.projectionService.projectDocument({
228
+ scene: this.#options.scene,
229
+ drawings: candidateDocument,
230
+ });
231
+ if (input.after !== undefined && input.operation !== 'delete') {
232
+ const projectedDrawing = projected.drawings.find((drawing) => drawing.drawing.id === input.after.id);
233
+ if (projectedDrawing === undefined) {
234
+ throw new DrawingSessionError('DRAWING_PROJECTION_INVALID', `/drawings/${input.after.id}`, 'Candidate Drawing cannot be projected on the current Scene.');
235
+ }
236
+ }
237
+ }
238
+ catch (error) {
239
+ if (error instanceof DrawingSessionError) {
240
+ this.#restoreBefore(input.before, input.after);
241
+ this.#options.emit({
242
+ type: 'workspace-error',
243
+ code: error.code,
244
+ message: error.message,
245
+ });
246
+ }
247
+ return;
248
+ }
249
+ const canonicalHash = await hashCanonicalDrawingDocument(candidateDocument);
250
+ const candidate = {
251
+ requestId: `change-${++this.#requestSequence}`,
252
+ operation: input.operation,
253
+ ...(input.before === undefined ? {} : { before: structuredClone(input.before) }),
254
+ after: structuredClone(input.after),
255
+ document: structuredClone(candidateDocument),
256
+ canonicalHash,
257
+ };
258
+ this.#candidate = candidate;
259
+ this.#options.emit(deepFreeze({
260
+ type: 'drawing-candidate',
261
+ requestId: candidate.requestId,
262
+ operation: input.operation,
263
+ ...(input.before === undefined ? {} : { before: structuredClone(input.before) }),
264
+ candidate: structuredClone(input.after),
265
+ candidateDocument: structuredClone(candidateDocument),
266
+ canonicalHash,
267
+ }));
268
+ if (this.#options.commitMode === 'immediate') {
269
+ this.#commitCandidate(candidate);
270
+ }
271
+ else {
272
+ this.#state = 'awaiting-host-confirmation';
273
+ }
274
+ }
275
+ #confirmedWith(operation, before, after) {
276
+ if (operation === 'delete') {
277
+ return this.#confirmed.filter((drawing) => drawing.id !== after.id);
278
+ }
279
+ if (before === undefined) {
280
+ return [...this.#confirmed, structuredClone(after)];
281
+ }
282
+ return this.#confirmed.map((drawing) => drawing.id === before.id ? structuredClone(after) : drawing);
283
+ }
284
+ #commitCandidate(candidate) {
285
+ this.#confirmed = this.#confirmedWith(candidate.operation, candidate.before, candidate.after);
286
+ this.#candidate = null;
287
+ this.#state = 'ready';
288
+ this.#options.emit({
289
+ type: 'drawing-committed',
290
+ requestId: candidate.requestId,
291
+ drawing: structuredClone(candidate.after),
292
+ document: structuredClone(candidate.document),
293
+ canonicalHash: candidate.canonicalHash,
294
+ });
295
+ }
296
+ #restoreBefore(before, after) {
297
+ try {
298
+ if (before !== undefined) {
299
+ this.#options.engine.restoreDrawing(before);
300
+ }
301
+ else {
302
+ this.#options.engine.removeDrawing(after.id);
303
+ }
304
+ }
305
+ catch (error) {
306
+ this.#enterTerminalError('DRAWING_PROJECTION_INVALID', `Failed to restore the rejected candidate: ${String(error)}`);
307
+ }
308
+ }
309
+ #enterTerminalError(code, message) {
310
+ this.#state = 'terminal-error';
311
+ this.#candidate = null;
312
+ this.#options.emit({ type: 'workspace-error', code, message });
313
+ }
314
+ #assertUsable() {
315
+ if (this.#state === 'terminal-error' || this.#state === 'destroyed') {
316
+ throw new DrawingSessionError('DRAWABLE_WORKSPACE_RUNTIME_DESTROYED', '/', 'The Workspace Runtime is in a destroy-only state.');
317
+ }
318
+ }
319
+ #assertReady() {
320
+ this.#assertUsable();
321
+ if (this.#state !== 'ready') {
322
+ throw new DrawingSessionError('DRAWING_CHANGE_IN_PROGRESS', '/drawings', 'Another Drawing mutation is already in progress.');
323
+ }
324
+ }
325
+ }
326
+ function defaultStyles() {
327
+ return {
328
+ line: { color: 'rgba(41, 98, 255, 1)', size: 1, style: 'solid' },
329
+ fill: { color: 'rgba(41, 98, 255, 0.15)' },
330
+ text: {
331
+ color: 'rgba(255, 255, 255, 1)',
332
+ size: 12,
333
+ family: 'Baron Sans',
334
+ weight: 'normal',
335
+ backgroundColor: 'rgba(41, 98, 255, 1)',
336
+ borderColor: 'rgba(41, 98, 255, 1)',
337
+ },
338
+ };
339
+ }
@@ -0,0 +1,66 @@
1
+ import type { ChartScene, DrawingDocument, TimeSeriesScene } from '@baron1996/kline-scene-schema';
2
+ import type { EngineDrawingSnapshot } from '@baron1996/klinecharts-adapter';
3
+ import type { ActiveMainSeriesType } from '@baron1996/klinecharts-adapter';
4
+ export declare const WORKSPACE_EVENT_PROTOCOL: "@baron1996/drawable-workspace-events";
5
+ export declare const WORKSPACE_EVENT_PROTOCOL_VERSION: "1.0.0";
6
+ export interface WorkspaceEventEnvelope {
7
+ readonly protocol: typeof WORKSPACE_EVENT_PROTOCOL;
8
+ readonly protocolVersion: typeof WORKSPACE_EVENT_PROTOCOL_VERSION;
9
+ readonly runtimeId: string;
10
+ readonly sequence: number;
11
+ }
12
+ export type WorkspaceDrawingOperation = 'create' | 'update' | 'style-change' | 'text-change' | 'delete' | 'select' | 'deselect';
13
+ export interface DrawingCandidateEventPayload {
14
+ readonly requestId: string;
15
+ readonly operation: WorkspaceDrawingOperation;
16
+ readonly before?: EngineDrawingSnapshot;
17
+ readonly candidate: EngineDrawingSnapshot;
18
+ readonly candidateDocument: DrawingDocument;
19
+ readonly canonicalHash: string;
20
+ }
21
+ export interface WorkspaceSceneSnapshot {
22
+ readonly kind: 'chart' | 'time-series';
23
+ readonly document: ChartScene | TimeSeriesScene;
24
+ }
25
+ export type WorkspaceRuntimeEvent = ({
26
+ readonly type: 'drawing-candidate';
27
+ } & DrawingCandidateEventPayload) | ({
28
+ readonly type: 'drawing-committed';
29
+ readonly requestId: string;
30
+ readonly drawing: EngineDrawingSnapshot;
31
+ readonly document: DrawingDocument;
32
+ readonly canonicalHash: string;
33
+ }) | ({
34
+ readonly type: 'drawing-rejected';
35
+ readonly requestId: string;
36
+ readonly drawing: EngineDrawingSnapshot;
37
+ readonly document: DrawingDocument;
38
+ readonly canonicalHash: string;
39
+ }) | {
40
+ readonly type: 'selection-changed';
41
+ readonly id: string | null;
42
+ } | {
43
+ readonly type: 'scene-replaced';
44
+ readonly scene: WorkspaceSceneSnapshot;
45
+ } | {
46
+ readonly type: 'value-axis-scale-changed';
47
+ readonly scale: 'linear' | 'logarithmic';
48
+ } | {
49
+ readonly type: 'main-series-presentation-changed';
50
+ readonly activeType: ActiveMainSeriesType;
51
+ } | {
52
+ readonly type: 'host-action-requested';
53
+ readonly actionId: string;
54
+ readonly drawingId: string | null;
55
+ } | {
56
+ readonly type: 'workspace-error';
57
+ readonly code: string;
58
+ readonly message: string;
59
+ } | {
60
+ readonly type: 'destroyed';
61
+ };
62
+ export type WorkspaceRuntimeEventEnvelope = WorkspaceRuntimeEvent & WorkspaceEventEnvelope;
63
+ export type WorkspaceRuntimeListener = (event: WorkspaceRuntimeEventEnvelope) => void;
64
+ /** 深冻结快照,避免监听器修改事件载荷。 */
65
+ export declare function deepFreeze<T>(value: T): T;
66
+ //# sourceMappingURL=workspace-events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-events.d.ts","sourceRoot":"","sources":["../../src/drawing/workspace-events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export const WORKSPACE_EVENT_PROTOCOL = '@baron1996/drawable-workspace-events';
2
+ export const WORKSPACE_EVENT_PROTOCOL_VERSION = '1.0.0';
3
+ /** 深冻结快照,避免监听器修改事件载荷。 */
4
+ export function deepFreeze(value) {
5
+ if (value !== null && typeof value === 'object') {
6
+ for (const child of Object.values(value)) {
7
+ deepFreeze(child);
8
+ }
9
+ Object.freeze(value);
10
+ }
11
+ return value;
12
+ }
@@ -0,0 +1,60 @@
1
+ import type { ChartScene, DrawableWorkspaceDocument, Drawing, DrawingDocument, TimeSeriesScene } from '@baron1996/kline-scene-schema';
2
+ import type { EngineDrawingSnapshot, MainSeriesPresentation } from '@baron1996/klinecharts-adapter';
3
+ import type { DrawingRuntimeCapability, RuntimeAuxiliaryCapability } from './capabilities.js';
4
+ import type { HostActionDescriptor, RuntimeCapabilityDescriptor } from './runtime-capability-descriptor.js';
5
+ import { type WorkspaceRuntimeListener } from './workspace-events.js';
6
+ export interface DrawableWorkspaceRuntimeOptions {
7
+ readonly commitMode: 'immediate' | 'host-confirmed';
8
+ readonly onEvent?: WorkspaceRuntimeListener;
9
+ readonly hostActions?: readonly HostActionDescriptor[];
10
+ }
11
+ export interface DrawableWorkspaceRuntimeHandle extends DrawingRuntimeCapability, RuntimeAuxiliaryCapability {
12
+ }
13
+ /**
14
+ * 组合 Scene Adapter、Drawing 会话与公共能力的工作区 Runtime。
15
+ * confirmed 文档唯一权威;宿主持久化只消费候选事件。
16
+ */
17
+ export declare class DrawableWorkspaceRuntime implements DrawableWorkspaceRuntimeHandle {
18
+ #private;
19
+ private constructor();
20
+ static create(container: HTMLElement, value: unknown, options: DrawableWorkspaceRuntimeOptions): Promise<DrawableWorkspaceRuntime>;
21
+ startDrawing(type: Drawing['type'], options?: {
22
+ readonly text?: string;
23
+ readonly id?: string;
24
+ readonly styles?: Drawing['styles'];
25
+ }): string;
26
+ listDrawings(): readonly EngineDrawingSnapshot[];
27
+ getDrawing(id: string): EngineDrawingSnapshot | undefined;
28
+ updateDrawingStyles(id: string, styles: Drawing['styles']): EngineDrawingSnapshot;
29
+ updateDrawingText(id: string, text: string): EngineDrawingSnapshot;
30
+ removeDrawing(id: string): boolean;
31
+ requestDrawingDelete(id: string): void;
32
+ selectDrawing(id: string | null): void;
33
+ getSelectedDrawingId(): string | undefined;
34
+ hitTestDrawing(point: {
35
+ readonly x: number;
36
+ readonly y: number;
37
+ }): string | null;
38
+ subscribe(listener: WorkspaceRuntimeListener): () => void;
39
+ getRuntimeCapabilityDescriptor(options?: {
40
+ readonly hostActions?: readonly HostActionDescriptor[];
41
+ }): RuntimeCapabilityDescriptor;
42
+ exportDrawingDocument(): DrawingDocument;
43
+ exportWorkspace(): DrawableWorkspaceDocument;
44
+ exportArtifact(fileName?: string): {
45
+ readonly bytes: Uint8Array;
46
+ readonly mediaType: 'application/json';
47
+ readonly fileName: string;
48
+ };
49
+ setValueAxisScale(scale: 'linear' | 'logarithmic'): Promise<ChartScene>;
50
+ setMainSeriesPresentation(presentation: MainSeriesPresentation): {
51
+ readonly activeType: string;
52
+ };
53
+ replaceScene(scene: ChartScene | TimeSeriesScene): ChartScene | TimeSeriesScene;
54
+ commitDrawingChange(requestId: string, canonicalHash: string): boolean;
55
+ rejectDrawingChange(requestId: string): boolean;
56
+ requestHostAction(actionId: string, drawingId?: string | null): void;
57
+ destroy(): void;
58
+ }
59
+ export declare function createDrawableWorkspaceRuntime(container: HTMLElement, workspace: unknown, options: DrawableWorkspaceRuntimeOptions): Promise<DrawableWorkspaceRuntime>;
60
+ //# sourceMappingURL=workspace-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-runtime.d.ts","sourceRoot":"","sources":["../../src/drawing/workspace-runtime.ts"],"names":[],"mappings":"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"}