visio-svelte-viewer 0.7.4 → 1.0.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.
- package/dist/DiagramCanvas.svelte +6 -0
- package/dist/DiagramCanvas.svelte.d.ts +4 -0
- package/dist/Inspector.svelte +7 -0
- package/dist/Inspector.svelte.d.ts +4 -0
- package/dist/PageNavigation.svelte +9 -0
- package/dist/PageNavigation.svelte.d.ts +4 -0
- package/dist/ShapesPane.svelte +7 -0
- package/dist/ShapesPane.svelte.d.ts +4 -0
- package/dist/Toolbar.svelte +28 -0
- package/dist/Toolbar.svelte.d.ts +4 -0
- package/dist/VisioViewer.svelte +2 -2
- package/dist/index.d.ts +6 -0
- package/dist/index.js +373 -5
- package/dist/index.server.js +276 -4
- package/dist/index.svelte.js +6 -0
- package/dist/runtime.d.ts +3 -0
- package/dist/runtime.js +210 -2
- package/dist/types/packages/bindings/src/building-blocks.d.ts +95 -0
- package/dist/types/packages/bindings/src/toolbar-controls.d.ts +41 -0
- package/dist/types/packages/svelte/src/building-blocks.d.ts +87 -0
- package/package.json +4 -4
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
let { mount, class: className }: { mount(node: HTMLElement | null): void; class?: string } = $props();
|
|
3
|
+
let host: HTMLDivElement;
|
|
4
|
+
$effect(() => { const current = mount; current(host); return () => current(null); });
|
|
5
|
+
</script>
|
|
6
|
+
<div bind:this={host} class={className}></div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { buildingBlock, type ViewerController } from './runtime.js';
|
|
3
|
+
let { controller }: { controller: ViewerController } = $props();
|
|
4
|
+
let host: HTMLDivElement;
|
|
5
|
+
$effect(() => buildingBlock('mountDiagramInspector')(host, controller));
|
|
6
|
+
</script>
|
|
7
|
+
<div bind:this={host}></div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { prepareDiagramBlock } from './runtime.js';
|
|
3
|
+
function theme(host: HTMLElement) { prepareDiagramBlock(host, 'tabs'); }
|
|
4
|
+
import type { DiagramToolbarProps } from './runtime.js';
|
|
5
|
+
let { toolbarProps }: { toolbarProps: DiagramToolbarProps } = $props();
|
|
6
|
+
</script>
|
|
7
|
+
<select use:theme aria-label={toolbarProps.labels.Page} value={toolbarProps.pageIndex} onchange={event => toolbarProps.onPageChange(Number(event.currentTarget.value))}>
|
|
8
|
+
{#each toolbarProps.pages as page, index (page.id)}<option value={index}>{page.name}</option>{/each}
|
|
9
|
+
</select>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { buildingBlock, type ViewerController } from './runtime.js';
|
|
3
|
+
let { controller, locale }: { controller: ViewerController; locale?: string | undefined } = $props();
|
|
4
|
+
let host: HTMLDivElement;
|
|
5
|
+
$effect(() => buildingBlock('mountDiagramShapes')(host, controller, { locale }));
|
|
6
|
+
</script>
|
|
7
|
+
<div bind:this={host}></div>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { prepareDiagramBlock } from './runtime.js';
|
|
3
|
+
import { toolbarGroups, type ToolbarGroupId } from './runtime.js';
|
|
4
|
+
function theme(host: HTMLElement) { prepareDiagramBlock(host, 'toolbar'); }
|
|
5
|
+
import type { DiagramToolbarProps } from './runtime.js';
|
|
6
|
+
let { toolbarProps, include }: { toolbarProps: DiagramToolbarProps; include?: readonly ToolbarGroupId[] } = $props();
|
|
7
|
+
const groups = $derived(toolbarGroups(toolbarProps, include));
|
|
8
|
+
</script>
|
|
9
|
+
<div role="toolbar" use:theme>
|
|
10
|
+
{#each groups as group (group.id)}
|
|
11
|
+
<span data-group={group.id}>
|
|
12
|
+
{#each group.controls as control (control.id)}
|
|
13
|
+
{#if control.kind === 'text'}
|
|
14
|
+
<span data-control={control.id}>{control.text}</span>
|
|
15
|
+
{:else if control.kind === 'button'}
|
|
16
|
+
<button type="button" data-control={control.id} disabled={control.disabled} aria-pressed={control.pressed} onclick={() => control.run()}>{control.label}</button>
|
|
17
|
+
{:else}
|
|
18
|
+
<span data-control="search">
|
|
19
|
+
<input type="search" aria-label={control.label} placeholder={control.label} value={control.query} oninput={(event) => control.change(event.currentTarget.value)} />
|
|
20
|
+
<span aria-live="polite">{control.summary}</span>
|
|
21
|
+
<button type="button" data-control={control.previous.id} disabled={control.previous.disabled} onclick={() => control.previous.run()}>{control.previous.label}</button>
|
|
22
|
+
<button type="button" data-control={control.next.id} disabled={control.next.disabled} onclick={() => control.next.run()}>{control.next.label}</button>
|
|
23
|
+
</span>
|
|
24
|
+
{/if}
|
|
25
|
+
{/each}
|
|
26
|
+
</span>
|
|
27
|
+
{/each}
|
|
28
|
+
</div>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Component } from 'svelte';
|
|
2
|
+
import type { ViewerController, DiagramToolbarProps, ToolbarGroupId } from './runtime.js';
|
|
3
|
+
declare const component: Component<{ toolbarProps: DiagramToolbarProps; include?: readonly ToolbarGroupId[] }>;
|
|
4
|
+
export default component;
|
package/dist/VisioViewer.svelte
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import { readonly, writable } from 'svelte/store';
|
|
4
4
|
import { mountFrameworkViewer, viewerHandle, viewerOptions, viewerStateSource, type ViewerState, type MountedViewer, type ViewerProps, type VsdxSource, type VisioEdit, type VisioShapeSelection, type SvgExportOptions, type CurrentPagePrintSnapshotOptions } from './runtime.js';
|
|
5
5
|
type Props = ViewerProps & { class?: string; style?: string; 'aria-label'?: string };
|
|
6
|
-
let { document, pageIndex, zoom, showToolbar, ribbonAddIns, events, class: className, style, 'aria-label': ariaLabel }: Props = $props();
|
|
7
|
-
const options = $derived({ document, pageIndex, zoom, showToolbar, ribbonAddIns, events } satisfies Required<ViewerProps>);
|
|
6
|
+
let { document, pageIndex, zoom, showToolbar, canEdit, ribbonAddIns, collaboration, events, class: className, style, 'aria-label': ariaLabel }: Props = $props();
|
|
7
|
+
const options = $derived({ document, pageIndex, zoom, showToolbar, canEdit, ribbonAddIns, collaboration, events } satisfies Required<ViewerProps>);
|
|
8
8
|
let binding: MountedViewer | undefined;
|
|
9
9
|
const handle = viewerHandle(() => binding);
|
|
10
10
|
// The component owns its state store, so subscribers made before mount still see updates.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
export * from './types/src/index.js';
|
|
2
2
|
export * from 'visio-core';
|
|
3
3
|
export { default, default as VisioViewer } from './VisioViewer.svelte';
|
|
4
|
+
export * from './types/packages/svelte/src/building-blocks.js';
|
|
5
|
+
export { default as DiagramCanvas } from './DiagramCanvas.svelte';
|
|
6
|
+
export { default as Toolbar } from './Toolbar.svelte';
|
|
7
|
+
export { default as PageNavigation } from './PageNavigation.svelte';
|
|
8
|
+
export { default as Inspector } from './Inspector.svelte';
|
|
9
|
+
export { default as ShapesPane } from './ShapesPane.svelte';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as ui from "ooxml-ui/visio";
|
|
2
|
+
import { ViewerController, createWorkerParser, mountViewer, propertyKeys } from "ooxml-ui/visio";
|
|
2
3
|
import "svelte/internal/disclose-version";
|
|
3
4
|
import * as $ from "svelte/internal/client";
|
|
4
|
-
import { readonly, writable } from "svelte/store";
|
|
5
|
+
import { derived, get, readonly, writable } from "svelte/store";
|
|
6
|
+
import { onDestroy } from "svelte";
|
|
7
|
+
import * as officeTheme from "ooxml-ui/theme";
|
|
5
8
|
export * from "ooxml-ui/visio";
|
|
6
9
|
export * from "visio-core";
|
|
7
10
|
//#region packages/bindings/src/common.ts
|
|
@@ -146,7 +149,7 @@ function viewerStateSource(current) {
|
|
|
146
149
|
}
|
|
147
150
|
//#endregion
|
|
148
151
|
//#region packages/bindings/src/VisioViewer.svelte
|
|
149
|
-
var root = $.from_html(`<div></div>`);
|
|
152
|
+
var root$5 = $.from_html(`<div></div>`);
|
|
150
153
|
function VisioViewer($$anchor, $$props) {
|
|
151
154
|
$.push($$props, true);
|
|
152
155
|
const options = $.derived(() => ({
|
|
@@ -154,7 +157,9 @@ function VisioViewer($$anchor, $$props) {
|
|
|
154
157
|
pageIndex: $$props.pageIndex,
|
|
155
158
|
zoom: $$props.zoom,
|
|
156
159
|
showToolbar: $$props.showToolbar,
|
|
160
|
+
canEdit: $$props.canEdit,
|
|
157
161
|
ribbonAddIns: $$props.ribbonAddIns,
|
|
162
|
+
collaboration: $$props.collaboration,
|
|
158
163
|
events: $$props.events
|
|
159
164
|
}));
|
|
160
165
|
let binding;
|
|
@@ -269,7 +274,7 @@ function VisioViewer($$anchor, $$props) {
|
|
|
269
274
|
exportSvg,
|
|
270
275
|
createPrintSnapshot
|
|
271
276
|
};
|
|
272
|
-
var div = root();
|
|
277
|
+
var div = root$5();
|
|
273
278
|
$.action(div, ($$node, $$action_arg) => attach?.($$node, $$action_arg), () => $.get(options));
|
|
274
279
|
$.template_effect(() => {
|
|
275
280
|
$.set_class(div, 1, $.clsx($$props.class));
|
|
@@ -280,4 +285,367 @@ function VisioViewer($$anchor, $$props) {
|
|
|
280
285
|
return $.pop($$exports);
|
|
281
286
|
}
|
|
282
287
|
//#endregion
|
|
283
|
-
|
|
288
|
+
//#region packages/bindings/src/building-blocks.ts
|
|
289
|
+
function buildingBlock(key) {
|
|
290
|
+
const value = Reflect.get(ui, key);
|
|
291
|
+
if (typeof value !== "function") throw new Error("Update ooxml-ui to use Visio building blocks.");
|
|
292
|
+
return value;
|
|
293
|
+
}
|
|
294
|
+
/** The mode a host sees: 'edit' only when permission is granted and the file can be saved back. */
|
|
295
|
+
function effectiveMode(state) {
|
|
296
|
+
return buildingBlock("diagramMode")(state);
|
|
297
|
+
}
|
|
298
|
+
/** Framework-neutral ownership only; each adapter supplies its own reactive state. */
|
|
299
|
+
function createBuildingBlockSession(initial = {}) {
|
|
300
|
+
const controller = new ViewerController(createWorkerParser());
|
|
301
|
+
controller.canEdit = initial.canEdit === true;
|
|
302
|
+
let options = initial;
|
|
303
|
+
let source;
|
|
304
|
+
let host = null;
|
|
305
|
+
let disposeCanvas;
|
|
306
|
+
let destroyed = false;
|
|
307
|
+
const stopEvents = controller.onEvent((name, detail) => {
|
|
308
|
+
if (name === "document-change") {
|
|
309
|
+
const change = detail;
|
|
310
|
+
options.onDocumentChange?.(change.document);
|
|
311
|
+
options.onDirtyChange?.(change.dirty);
|
|
312
|
+
} else if (name === "document-error") options.onDocumentError?.(detail);
|
|
313
|
+
});
|
|
314
|
+
const fit = () => {
|
|
315
|
+
if (host) buildingBlock("fitDiagramCanvas")(host, controller);
|
|
316
|
+
};
|
|
317
|
+
return {
|
|
318
|
+
controller,
|
|
319
|
+
mount(node) {
|
|
320
|
+
if (destroyed || node === host) return;
|
|
321
|
+
disposeCanvas?.();
|
|
322
|
+
disposeCanvas = void 0;
|
|
323
|
+
host = node;
|
|
324
|
+
if (node) disposeCanvas = buildingBlock("mountDiagramCanvas")(node, controller);
|
|
325
|
+
},
|
|
326
|
+
/** Flat control props; pass the framework's latest options so callbacks stay current. */
|
|
327
|
+
toolbar(latest = options) {
|
|
328
|
+
return buildingBlock("diagramToolbarProps")(controller, fit, latest.locale, {
|
|
329
|
+
onOpenFile: latest.onOpenFile,
|
|
330
|
+
onOpenPageSetup: latest.onOpenPageSetup,
|
|
331
|
+
onOpenSettings: latest.onOpenSettings,
|
|
332
|
+
onOpenShareDialog: latest.onOpenShareDialog
|
|
333
|
+
});
|
|
334
|
+
},
|
|
335
|
+
/** Acknowledge a host save: clears dirty and emits the dirty change. */
|
|
336
|
+
markClean() {
|
|
337
|
+
controller.markClean();
|
|
338
|
+
},
|
|
339
|
+
update(next) {
|
|
340
|
+
if (destroyed) return;
|
|
341
|
+
options = next;
|
|
342
|
+
controller.canEdit = next.canEdit === true;
|
|
343
|
+
if (source === next.content) return;
|
|
344
|
+
source = next.content;
|
|
345
|
+
controller.cancelLoad();
|
|
346
|
+
if (!source) return;
|
|
347
|
+
const input = source;
|
|
348
|
+
controller.loadSource(async () => {
|
|
349
|
+
return input instanceof Blob ? new Uint8Array(await input.arrayBuffer()) : input;
|
|
350
|
+
}).catch(() => {});
|
|
351
|
+
},
|
|
352
|
+
destroy() {
|
|
353
|
+
if (destroyed) return;
|
|
354
|
+
destroyed = true;
|
|
355
|
+
disposeCanvas?.();
|
|
356
|
+
disposeCanvas = void 0;
|
|
357
|
+
host = null;
|
|
358
|
+
stopEvents();
|
|
359
|
+
controller.destroy();
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
/** Resolve the new optional-control theme API only when that control is mounted. */
|
|
364
|
+
function prepareDiagramBlock(host, kind) {
|
|
365
|
+
if (!host) return;
|
|
366
|
+
const prepare = Reflect.get(officeTheme, "prepareOfficeUiBlock");
|
|
367
|
+
if (typeof prepare !== "function") throw new Error("Update ooxml-ui to theme Visio building blocks.");
|
|
368
|
+
prepare(host, kind, "visio");
|
|
369
|
+
}
|
|
370
|
+
//#endregion
|
|
371
|
+
//#region packages/svelte/src/building-blocks.ts
|
|
372
|
+
/** Call during component initialization. Reactive option changes use blocks.update(options). */
|
|
373
|
+
function createViewerBuildingBlocks(options = {}) {
|
|
374
|
+
const source = "subscribe" in options ? options : void 0;
|
|
375
|
+
const initial = source ? get(source) : options;
|
|
376
|
+
const session = createBuildingBlockSession(initial);
|
|
377
|
+
const state = writable(session.controller.state);
|
|
378
|
+
const latest = writable(initial);
|
|
379
|
+
const stop = session.controller.subscribe((value) => state.set(value));
|
|
380
|
+
let stopOptions = () => {};
|
|
381
|
+
onDestroy(() => {
|
|
382
|
+
stopOptions();
|
|
383
|
+
stop();
|
|
384
|
+
session.destroy();
|
|
385
|
+
});
|
|
386
|
+
const update = (next) => {
|
|
387
|
+
latest.set(next);
|
|
388
|
+
session.update(next);
|
|
389
|
+
};
|
|
390
|
+
if (source) stopOptions = source.subscribe(update);
|
|
391
|
+
else update(initial);
|
|
392
|
+
return {
|
|
393
|
+
controller: session.controller,
|
|
394
|
+
state: { subscribe: state.subscribe },
|
|
395
|
+
toolbarProps: derived([state, latest], ([, next]) => session.toolbar(next)),
|
|
396
|
+
loading: derived(state, (value) => value.loading),
|
|
397
|
+
error: derived(state, (value) => value.error ?? value.edit.error),
|
|
398
|
+
/** Effective permission: host `canEdit` and a drawing that can be saved back. */
|
|
399
|
+
mode: derived(state, (value) => effectiveMode(value)),
|
|
400
|
+
canvasProps: { mount: session.mount },
|
|
401
|
+
inspectorProps: { controller: session.controller },
|
|
402
|
+
shapesProps: derived(latest, (next) => ({
|
|
403
|
+
controller: session.controller,
|
|
404
|
+
locale: next.locale
|
|
405
|
+
})),
|
|
406
|
+
/** Acknowledge a host save: clears dirty and fires `onDirtyChange(false)`. */
|
|
407
|
+
markClean: () => session.markClean(),
|
|
408
|
+
update
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
//#endregion
|
|
412
|
+
//#region packages/svelte/src/DiagramCanvas.svelte
|
|
413
|
+
var root$4 = $.from_html(`<div></div>`);
|
|
414
|
+
function DiagramCanvas($$anchor, $$props) {
|
|
415
|
+
$.push($$props, true);
|
|
416
|
+
let host;
|
|
417
|
+
$.user_effect(() => {
|
|
418
|
+
const current = $$props.mount;
|
|
419
|
+
current(host);
|
|
420
|
+
return () => current(null);
|
|
421
|
+
});
|
|
422
|
+
var div = root$4();
|
|
423
|
+
$.bind_this(div, ($$value) => host = $$value, () => host);
|
|
424
|
+
$.template_effect(() => $.set_class(div, 1, $.clsx($$props.class)));
|
|
425
|
+
$.append($$anchor, div);
|
|
426
|
+
$.pop();
|
|
427
|
+
}
|
|
428
|
+
//#endregion
|
|
429
|
+
//#region packages/bindings/src/toolbar-controls.ts
|
|
430
|
+
var TOOLBAR_GROUPS = [
|
|
431
|
+
"file",
|
|
432
|
+
"history",
|
|
433
|
+
"zoom",
|
|
434
|
+
"selection",
|
|
435
|
+
"clipboard",
|
|
436
|
+
"tools",
|
|
437
|
+
"search"
|
|
438
|
+
];
|
|
439
|
+
var fire = (action) => () => {
|
|
440
|
+
Promise.resolve().then(action).catch(() => {});
|
|
441
|
+
};
|
|
442
|
+
var button = (id, label, enabled, action, pressed) => ({
|
|
443
|
+
kind: "button",
|
|
444
|
+
id,
|
|
445
|
+
label,
|
|
446
|
+
disabled: !enabled,
|
|
447
|
+
...pressed === void 0 ? {} : { pressed },
|
|
448
|
+
run: fire(action)
|
|
449
|
+
});
|
|
450
|
+
/**
|
|
451
|
+
* What the library Toolbar shows, as plain data every framework maps onto its own elements.
|
|
452
|
+
* Every control reflects `toolbarProps`: edit actions are disabled while the diagram is read-only,
|
|
453
|
+
* viewing actions (zoom, fit, search) never are, and a host dialog button appears only when the
|
|
454
|
+
* host supplied its callback.
|
|
455
|
+
*/
|
|
456
|
+
function toolbarGroups(props, include = TOOLBAR_GROUPS) {
|
|
457
|
+
const { labels } = props;
|
|
458
|
+
const has = props.pages.length > 0;
|
|
459
|
+
const groups = [];
|
|
460
|
+
const add = (id, controls) => {
|
|
461
|
+
if (include.includes(id) && controls.length) groups.push({
|
|
462
|
+
id,
|
|
463
|
+
controls
|
|
464
|
+
});
|
|
465
|
+
};
|
|
466
|
+
add("file", [
|
|
467
|
+
...props.onOpenFile ? [button("open", labels.Open, true, props.onOpenFile)] : [],
|
|
468
|
+
...props.onOpenPageSetup ? [button("page-setup", labels["Page Setup"], has, props.onOpenPageSetup)] : [],
|
|
469
|
+
...props.onOpenShareDialog ? [button("share", labels.Share, has, props.onOpenShareDialog)] : [],
|
|
470
|
+
...props.onOpenSettings ? [button("settings", labels.Options, true, props.onOpenSettings)] : []
|
|
471
|
+
]);
|
|
472
|
+
add("history", [button("undo", labels.Undo, props.canUndo, props.onUndo), button("redo", labels.Redo, props.canRedo, props.onRedo)]);
|
|
473
|
+
add("zoom", [
|
|
474
|
+
button("zoom-out", labels["Zoom Out"], props.canZoomOut, props.onZoomOut),
|
|
475
|
+
{
|
|
476
|
+
kind: "text",
|
|
477
|
+
id: "zoom",
|
|
478
|
+
text: `${Math.round(props.zoom * 100)}%`
|
|
479
|
+
},
|
|
480
|
+
button("zoom-in", labels["Zoom In"], props.canZoomIn, props.onZoomIn),
|
|
481
|
+
button("fit", labels["Fit to Window"], has, props.onFit)
|
|
482
|
+
]);
|
|
483
|
+
add("selection", [
|
|
484
|
+
button("duplicate", labels.Duplicate, props.canDuplicate, props.onDuplicate),
|
|
485
|
+
button("group", labels.Group, props.canGroup, props.onGroup),
|
|
486
|
+
button("ungroup", labels.Ungroup, props.canUngroup, props.onUngroup),
|
|
487
|
+
button("delete", labels.Delete, props.canDelete, props.onDelete)
|
|
488
|
+
]);
|
|
489
|
+
add("clipboard", [
|
|
490
|
+
button("cut", labels.Cut, props.canCut, props.onCut),
|
|
491
|
+
button("copy", labels.Copy, props.canCopy, props.onCopy),
|
|
492
|
+
button("paste", labels.Paste, props.canPaste, props.onPaste)
|
|
493
|
+
]);
|
|
494
|
+
add("tools", props.tools.map((tool) => button(`tool-${tool.id}`, tool.label, tool.id === "pointer" || props.canDraw, () => props.onToolChange(tool.id), tool.active)));
|
|
495
|
+
const { search } = props;
|
|
496
|
+
add("search", [{
|
|
497
|
+
kind: "search",
|
|
498
|
+
id: "search",
|
|
499
|
+
label: labels.Find,
|
|
500
|
+
query: search.query,
|
|
501
|
+
summary: search.query ? search.resultCount ? `${search.activeIndex >= 0 ? search.activeIndex + 1 : "-"} / ${search.resultCount}` : "0" : "",
|
|
502
|
+
previous: button("search-previous", labels["Previous Result"], search.resultCount > 0, props.onPreviousSearchResult),
|
|
503
|
+
next: button("search-next", labels["Next Result"], search.resultCount > 0, props.onNextSearchResult),
|
|
504
|
+
change: (query) => props.onSearchChange(query)
|
|
505
|
+
}]);
|
|
506
|
+
return groups;
|
|
507
|
+
}
|
|
508
|
+
//#endregion
|
|
509
|
+
//#region packages/svelte/src/Toolbar.svelte
|
|
510
|
+
var root$3 = $.from_html(`<span> </span>`);
|
|
511
|
+
var root_1$1 = $.from_html(`<button type="button"> </button>`);
|
|
512
|
+
var root_2 = $.from_html(`<span data-control="search"><input type="search"/> <span aria-live="polite"> </span> <button type="button"> </button> <button type="button"> </button></span>`);
|
|
513
|
+
var root_3 = $.from_html(`<span></span>`);
|
|
514
|
+
var root_4 = $.from_html(`<div role="toolbar"></div>`);
|
|
515
|
+
function Toolbar($$anchor, $$props) {
|
|
516
|
+
$.push($$props, true);
|
|
517
|
+
function theme(host) {
|
|
518
|
+
prepareDiagramBlock(host, "toolbar");
|
|
519
|
+
}
|
|
520
|
+
const groups = $.derived(() => toolbarGroups($$props.toolbarProps, $$props.include));
|
|
521
|
+
var div = root_4();
|
|
522
|
+
$.each(div, 21, () => $.get(groups), (group) => group.id, ($$anchor, group) => {
|
|
523
|
+
var span = root_3();
|
|
524
|
+
$.each(span, 21, () => $.get(group).controls, (control) => control.id, ($$anchor, control) => {
|
|
525
|
+
var fragment = $.comment();
|
|
526
|
+
var node = $.first_child(fragment);
|
|
527
|
+
var consequent = ($$anchor) => {
|
|
528
|
+
var span_1 = root$3();
|
|
529
|
+
var text = $.only_child(span_1, true);
|
|
530
|
+
$.template_effect(() => {
|
|
531
|
+
$.set_attribute(span_1, "data-control", $.get(control).id);
|
|
532
|
+
$.set_text(text, $.get(control).text);
|
|
533
|
+
});
|
|
534
|
+
$.append($$anchor, span_1);
|
|
535
|
+
};
|
|
536
|
+
var consequent_1 = ($$anchor) => {
|
|
537
|
+
var button = root_1$1();
|
|
538
|
+
var text_1 = $.only_child(button, true);
|
|
539
|
+
$.template_effect(() => {
|
|
540
|
+
$.set_attribute(button, "data-control", $.get(control).id);
|
|
541
|
+
button.disabled = $.get(control).disabled;
|
|
542
|
+
$.set_attribute(button, "aria-pressed", $.get(control).pressed);
|
|
543
|
+
$.set_text(text_1, $.get(control).label);
|
|
544
|
+
});
|
|
545
|
+
$.delegated("click", button, () => $.get(control).run());
|
|
546
|
+
$.append($$anchor, button);
|
|
547
|
+
};
|
|
548
|
+
var alternate = ($$anchor) => {
|
|
549
|
+
var span_2 = root_2();
|
|
550
|
+
var input = $.child(span_2);
|
|
551
|
+
$.remove_input_defaults(input);
|
|
552
|
+
var span_3 = $.sibling(input, 2);
|
|
553
|
+
var text_2 = $.only_child(span_3, true);
|
|
554
|
+
var button_1 = $.sibling(span_3, 2);
|
|
555
|
+
var text_3 = $.only_child(button_1, true);
|
|
556
|
+
var button_2 = $.sibling(button_1, 2);
|
|
557
|
+
var text_4 = $.only_child(button_2, true);
|
|
558
|
+
$.reset(span_2);
|
|
559
|
+
$.template_effect(() => {
|
|
560
|
+
$.set_attribute(input, "aria-label", $.get(control).label);
|
|
561
|
+
$.set_attribute(input, "placeholder", $.get(control).label);
|
|
562
|
+
$.set_value(input, $.get(control).query);
|
|
563
|
+
$.set_text(text_2, $.get(control).summary);
|
|
564
|
+
$.set_attribute(button_1, "data-control", $.get(control).previous.id);
|
|
565
|
+
button_1.disabled = $.get(control).previous.disabled;
|
|
566
|
+
$.set_text(text_3, $.get(control).previous.label);
|
|
567
|
+
$.set_attribute(button_2, "data-control", $.get(control).next.id);
|
|
568
|
+
button_2.disabled = $.get(control).next.disabled;
|
|
569
|
+
$.set_text(text_4, $.get(control).next.label);
|
|
570
|
+
});
|
|
571
|
+
$.delegated("input", input, (event) => $.get(control).change(event.currentTarget.value));
|
|
572
|
+
$.delegated("click", button_1, () => $.get(control).previous.run());
|
|
573
|
+
$.delegated("click", button_2, () => $.get(control).next.run());
|
|
574
|
+
$.append($$anchor, span_2);
|
|
575
|
+
};
|
|
576
|
+
$.if(node, ($$render) => {
|
|
577
|
+
if ($.get(control).kind === "text") $$render(consequent);
|
|
578
|
+
else if ($.get(control).kind === "button") $$render(consequent_1, 1);
|
|
579
|
+
else $$render(alternate, -1);
|
|
580
|
+
});
|
|
581
|
+
$.append($$anchor, fragment);
|
|
582
|
+
});
|
|
583
|
+
$.reset(span);
|
|
584
|
+
$.template_effect(() => $.set_attribute(span, "data-group", $.get(group).id));
|
|
585
|
+
$.append($$anchor, span);
|
|
586
|
+
});
|
|
587
|
+
$.reset(div);
|
|
588
|
+
$.action(div, ($$node) => theme?.($$node));
|
|
589
|
+
$.append($$anchor, div);
|
|
590
|
+
$.pop();
|
|
591
|
+
}
|
|
592
|
+
$.delegate(["click", "input"]);
|
|
593
|
+
//#endregion
|
|
594
|
+
//#region packages/svelte/src/PageNavigation.svelte
|
|
595
|
+
var root$2 = $.from_html(`<option> </option>`);
|
|
596
|
+
var root_1 = $.from_html(`<select></select>`);
|
|
597
|
+
function PageNavigation($$anchor, $$props) {
|
|
598
|
+
$.push($$props, true);
|
|
599
|
+
function theme(host) {
|
|
600
|
+
prepareDiagramBlock(host, "tabs");
|
|
601
|
+
}
|
|
602
|
+
var select = root_1();
|
|
603
|
+
$.each(select, 23, () => $$props.toolbarProps.pages, (page) => page.id, ($$anchor, page, index) => {
|
|
604
|
+
var option = root$2();
|
|
605
|
+
var text = $.only_child(option, true);
|
|
606
|
+
var option_value = {};
|
|
607
|
+
$.template_effect(() => {
|
|
608
|
+
$.set_text(text, $.get(page).name);
|
|
609
|
+
if (option_value !== (option_value = $.get(index))) option.value = (option.__value = option_value) ?? "";
|
|
610
|
+
});
|
|
611
|
+
$.append($$anchor, option);
|
|
612
|
+
});
|
|
613
|
+
$.reset(select);
|
|
614
|
+
$.action(select, ($$node) => theme?.($$node));
|
|
615
|
+
var select_value;
|
|
616
|
+
$.init_select(select);
|
|
617
|
+
$.template_effect(() => {
|
|
618
|
+
$.set_attribute(select, "aria-label", $$props.toolbarProps.labels.Page);
|
|
619
|
+
if (select_value !== (select_value = $$props.toolbarProps.pageIndex)) select.value = (select.__value = select_value) ?? "", $.select_option(select, select_value);
|
|
620
|
+
});
|
|
621
|
+
$.delegated("change", select, (event) => $$props.toolbarProps.onPageChange(Number(event.currentTarget.value)));
|
|
622
|
+
$.append($$anchor, select);
|
|
623
|
+
$.pop();
|
|
624
|
+
}
|
|
625
|
+
$.delegate(["change"]);
|
|
626
|
+
//#endregion
|
|
627
|
+
//#region packages/svelte/src/Inspector.svelte
|
|
628
|
+
var root$1 = $.from_html(`<div></div>`);
|
|
629
|
+
function Inspector($$anchor, $$props) {
|
|
630
|
+
$.push($$props, true);
|
|
631
|
+
let host;
|
|
632
|
+
$.user_effect(() => buildingBlock("mountDiagramInspector")(host, $$props.controller));
|
|
633
|
+
var div = root$1();
|
|
634
|
+
$.bind_this(div, ($$value) => host = $$value, () => host);
|
|
635
|
+
$.append($$anchor, div);
|
|
636
|
+
$.pop();
|
|
637
|
+
}
|
|
638
|
+
//#endregion
|
|
639
|
+
//#region packages/svelte/src/ShapesPane.svelte
|
|
640
|
+
var root = $.from_html(`<div></div>`);
|
|
641
|
+
function ShapesPane($$anchor, $$props) {
|
|
642
|
+
$.push($$props, true);
|
|
643
|
+
let host;
|
|
644
|
+
$.user_effect(() => buildingBlock("mountDiagramShapes")(host, $$props.controller, { locale: $$props.locale }));
|
|
645
|
+
var div = root();
|
|
646
|
+
$.bind_this(div, ($$value) => host = $$value, () => host);
|
|
647
|
+
$.append($$anchor, div);
|
|
648
|
+
$.pop();
|
|
649
|
+
}
|
|
650
|
+
//#endregion
|
|
651
|
+
export { DiagramCanvas, Inspector, PageNavigation, ShapesPane, Toolbar, VisioViewer, VisioViewer as default, createViewerBuildingBlocks };
|
package/dist/index.server.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import "ooxml-ui/visio";
|
|
1
|
+
import * as ui from "ooxml-ui/visio";
|
|
2
|
+
import { ViewerController, createWorkerParser } from "ooxml-ui/visio";
|
|
2
3
|
import * as $ from "svelte/internal/server";
|
|
3
|
-
import { readonly, writable } from "svelte/store";
|
|
4
|
+
import { derived, get, readonly, writable } from "svelte/store";
|
|
5
|
+
import { onDestroy } from "svelte";
|
|
6
|
+
import "ooxml-ui/theme";
|
|
4
7
|
export * from "ooxml-ui/visio";
|
|
5
8
|
export * from "visio-core";
|
|
6
9
|
//#region packages/bindings/src/common.ts
|
|
@@ -84,13 +87,15 @@ function viewerHandle(current) {
|
|
|
84
87
|
//#region packages/bindings/src/VisioViewer.svelte
|
|
85
88
|
function VisioViewer($$renderer, $$props) {
|
|
86
89
|
$$renderer.component(($$renderer) => {
|
|
87
|
-
let { document, pageIndex, zoom, showToolbar, ribbonAddIns, events, class: className, style, "aria-label": ariaLabel } = $$props;
|
|
90
|
+
let { document, pageIndex, zoom, showToolbar, canEdit, ribbonAddIns, collaboration, events, class: className, style, "aria-label": ariaLabel } = $$props;
|
|
88
91
|
$.derived(() => ({
|
|
89
92
|
document,
|
|
90
93
|
pageIndex,
|
|
91
94
|
zoom,
|
|
92
95
|
showToolbar,
|
|
96
|
+
canEdit,
|
|
93
97
|
ribbonAddIns,
|
|
98
|
+
collaboration,
|
|
94
99
|
events
|
|
95
100
|
}));
|
|
96
101
|
let binding;
|
|
@@ -191,4 +196,271 @@ function VisioViewer($$renderer, $$props) {
|
|
|
191
196
|
});
|
|
192
197
|
}
|
|
193
198
|
//#endregion
|
|
194
|
-
|
|
199
|
+
//#region packages/bindings/src/building-blocks.ts
|
|
200
|
+
function buildingBlock(key) {
|
|
201
|
+
const value = Reflect.get(ui, key);
|
|
202
|
+
if (typeof value !== "function") throw new Error("Update ooxml-ui to use Visio building blocks.");
|
|
203
|
+
return value;
|
|
204
|
+
}
|
|
205
|
+
/** The mode a host sees: 'edit' only when permission is granted and the file can be saved back. */
|
|
206
|
+
function effectiveMode(state) {
|
|
207
|
+
return buildingBlock("diagramMode")(state);
|
|
208
|
+
}
|
|
209
|
+
/** Framework-neutral ownership only; each adapter supplies its own reactive state. */
|
|
210
|
+
function createBuildingBlockSession(initial = {}) {
|
|
211
|
+
const controller = new ViewerController(createWorkerParser());
|
|
212
|
+
controller.canEdit = initial.canEdit === true;
|
|
213
|
+
let options = initial;
|
|
214
|
+
let source;
|
|
215
|
+
let host = null;
|
|
216
|
+
let disposeCanvas;
|
|
217
|
+
let destroyed = false;
|
|
218
|
+
const stopEvents = controller.onEvent((name, detail) => {
|
|
219
|
+
if (name === "document-change") {
|
|
220
|
+
const change = detail;
|
|
221
|
+
options.onDocumentChange?.(change.document);
|
|
222
|
+
options.onDirtyChange?.(change.dirty);
|
|
223
|
+
} else if (name === "document-error") options.onDocumentError?.(detail);
|
|
224
|
+
});
|
|
225
|
+
const fit = () => {
|
|
226
|
+
if (host) buildingBlock("fitDiagramCanvas")(host, controller);
|
|
227
|
+
};
|
|
228
|
+
return {
|
|
229
|
+
controller,
|
|
230
|
+
mount(node) {
|
|
231
|
+
if (destroyed || node === host) return;
|
|
232
|
+
disposeCanvas?.();
|
|
233
|
+
disposeCanvas = void 0;
|
|
234
|
+
host = node;
|
|
235
|
+
if (node) disposeCanvas = buildingBlock("mountDiagramCanvas")(node, controller);
|
|
236
|
+
},
|
|
237
|
+
/** Flat control props; pass the framework's latest options so callbacks stay current. */
|
|
238
|
+
toolbar(latest = options) {
|
|
239
|
+
return buildingBlock("diagramToolbarProps")(controller, fit, latest.locale, {
|
|
240
|
+
onOpenFile: latest.onOpenFile,
|
|
241
|
+
onOpenPageSetup: latest.onOpenPageSetup,
|
|
242
|
+
onOpenSettings: latest.onOpenSettings,
|
|
243
|
+
onOpenShareDialog: latest.onOpenShareDialog
|
|
244
|
+
});
|
|
245
|
+
},
|
|
246
|
+
/** Acknowledge a host save: clears dirty and emits the dirty change. */
|
|
247
|
+
markClean() {
|
|
248
|
+
controller.markClean();
|
|
249
|
+
},
|
|
250
|
+
update(next) {
|
|
251
|
+
if (destroyed) return;
|
|
252
|
+
options = next;
|
|
253
|
+
controller.canEdit = next.canEdit === true;
|
|
254
|
+
if (source === next.content) return;
|
|
255
|
+
source = next.content;
|
|
256
|
+
controller.cancelLoad();
|
|
257
|
+
if (!source) return;
|
|
258
|
+
const input = source;
|
|
259
|
+
controller.loadSource(async () => {
|
|
260
|
+
return input instanceof Blob ? new Uint8Array(await input.arrayBuffer()) : input;
|
|
261
|
+
}).catch(() => {});
|
|
262
|
+
},
|
|
263
|
+
destroy() {
|
|
264
|
+
if (destroyed) return;
|
|
265
|
+
destroyed = true;
|
|
266
|
+
disposeCanvas?.();
|
|
267
|
+
disposeCanvas = void 0;
|
|
268
|
+
host = null;
|
|
269
|
+
stopEvents();
|
|
270
|
+
controller.destroy();
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region packages/svelte/src/building-blocks.ts
|
|
276
|
+
/** Call during component initialization. Reactive option changes use blocks.update(options). */
|
|
277
|
+
function createViewerBuildingBlocks(options = {}) {
|
|
278
|
+
const source = "subscribe" in options ? options : void 0;
|
|
279
|
+
const initial = source ? get(source) : options;
|
|
280
|
+
const session = createBuildingBlockSession(initial);
|
|
281
|
+
const state = writable(session.controller.state);
|
|
282
|
+
const latest = writable(initial);
|
|
283
|
+
const stop = session.controller.subscribe((value) => state.set(value));
|
|
284
|
+
let stopOptions = () => {};
|
|
285
|
+
onDestroy(() => {
|
|
286
|
+
stopOptions();
|
|
287
|
+
stop();
|
|
288
|
+
session.destroy();
|
|
289
|
+
});
|
|
290
|
+
const update = (next) => {
|
|
291
|
+
latest.set(next);
|
|
292
|
+
session.update(next);
|
|
293
|
+
};
|
|
294
|
+
if (source) stopOptions = source.subscribe(update);
|
|
295
|
+
else update(initial);
|
|
296
|
+
return {
|
|
297
|
+
controller: session.controller,
|
|
298
|
+
state: { subscribe: state.subscribe },
|
|
299
|
+
toolbarProps: derived([state, latest], ([, next]) => session.toolbar(next)),
|
|
300
|
+
loading: derived(state, (value) => value.loading),
|
|
301
|
+
error: derived(state, (value) => value.error ?? value.edit.error),
|
|
302
|
+
/** Effective permission: host `canEdit` and a drawing that can be saved back. */
|
|
303
|
+
mode: derived(state, (value) => effectiveMode(value)),
|
|
304
|
+
canvasProps: { mount: session.mount },
|
|
305
|
+
inspectorProps: { controller: session.controller },
|
|
306
|
+
shapesProps: derived(latest, (next) => ({
|
|
307
|
+
controller: session.controller,
|
|
308
|
+
locale: next.locale
|
|
309
|
+
})),
|
|
310
|
+
/** Acknowledge a host save: clears dirty and fires `onDirtyChange(false)`. */
|
|
311
|
+
markClean: () => session.markClean(),
|
|
312
|
+
update
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region packages/svelte/src/DiagramCanvas.svelte
|
|
317
|
+
function DiagramCanvas($$renderer, $$props) {
|
|
318
|
+
$$renderer.component(($$renderer) => {
|
|
319
|
+
let { mount, class: className } = $$props;
|
|
320
|
+
$$renderer.push(`<div${$.attr_class($.clsx(className))}></div>`);
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
//#endregion
|
|
324
|
+
//#region packages/bindings/src/toolbar-controls.ts
|
|
325
|
+
var TOOLBAR_GROUPS = [
|
|
326
|
+
"file",
|
|
327
|
+
"history",
|
|
328
|
+
"zoom",
|
|
329
|
+
"selection",
|
|
330
|
+
"clipboard",
|
|
331
|
+
"tools",
|
|
332
|
+
"search"
|
|
333
|
+
];
|
|
334
|
+
var fire = (action) => () => {
|
|
335
|
+
Promise.resolve().then(action).catch(() => {});
|
|
336
|
+
};
|
|
337
|
+
var button = (id, label, enabled, action, pressed) => ({
|
|
338
|
+
kind: "button",
|
|
339
|
+
id,
|
|
340
|
+
label,
|
|
341
|
+
disabled: !enabled,
|
|
342
|
+
...pressed === void 0 ? {} : { pressed },
|
|
343
|
+
run: fire(action)
|
|
344
|
+
});
|
|
345
|
+
/**
|
|
346
|
+
* What the library Toolbar shows, as plain data every framework maps onto its own elements.
|
|
347
|
+
* Every control reflects `toolbarProps`: edit actions are disabled while the diagram is read-only,
|
|
348
|
+
* viewing actions (zoom, fit, search) never are, and a host dialog button appears only when the
|
|
349
|
+
* host supplied its callback.
|
|
350
|
+
*/
|
|
351
|
+
function toolbarGroups(props, include = TOOLBAR_GROUPS) {
|
|
352
|
+
const { labels } = props;
|
|
353
|
+
const has = props.pages.length > 0;
|
|
354
|
+
const groups = [];
|
|
355
|
+
const add = (id, controls) => {
|
|
356
|
+
if (include.includes(id) && controls.length) groups.push({
|
|
357
|
+
id,
|
|
358
|
+
controls
|
|
359
|
+
});
|
|
360
|
+
};
|
|
361
|
+
add("file", [
|
|
362
|
+
...props.onOpenFile ? [button("open", labels.Open, true, props.onOpenFile)] : [],
|
|
363
|
+
...props.onOpenPageSetup ? [button("page-setup", labels["Page Setup"], has, props.onOpenPageSetup)] : [],
|
|
364
|
+
...props.onOpenShareDialog ? [button("share", labels.Share, has, props.onOpenShareDialog)] : [],
|
|
365
|
+
...props.onOpenSettings ? [button("settings", labels.Options, true, props.onOpenSettings)] : []
|
|
366
|
+
]);
|
|
367
|
+
add("history", [button("undo", labels.Undo, props.canUndo, props.onUndo), button("redo", labels.Redo, props.canRedo, props.onRedo)]);
|
|
368
|
+
add("zoom", [
|
|
369
|
+
button("zoom-out", labels["Zoom Out"], props.canZoomOut, props.onZoomOut),
|
|
370
|
+
{
|
|
371
|
+
kind: "text",
|
|
372
|
+
id: "zoom",
|
|
373
|
+
text: `${Math.round(props.zoom * 100)}%`
|
|
374
|
+
},
|
|
375
|
+
button("zoom-in", labels["Zoom In"], props.canZoomIn, props.onZoomIn),
|
|
376
|
+
button("fit", labels["Fit to Window"], has, props.onFit)
|
|
377
|
+
]);
|
|
378
|
+
add("selection", [
|
|
379
|
+
button("duplicate", labels.Duplicate, props.canDuplicate, props.onDuplicate),
|
|
380
|
+
button("group", labels.Group, props.canGroup, props.onGroup),
|
|
381
|
+
button("ungroup", labels.Ungroup, props.canUngroup, props.onUngroup),
|
|
382
|
+
button("delete", labels.Delete, props.canDelete, props.onDelete)
|
|
383
|
+
]);
|
|
384
|
+
add("clipboard", [
|
|
385
|
+
button("cut", labels.Cut, props.canCut, props.onCut),
|
|
386
|
+
button("copy", labels.Copy, props.canCopy, props.onCopy),
|
|
387
|
+
button("paste", labels.Paste, props.canPaste, props.onPaste)
|
|
388
|
+
]);
|
|
389
|
+
add("tools", props.tools.map((tool) => button(`tool-${tool.id}`, tool.label, tool.id === "pointer" || props.canDraw, () => props.onToolChange(tool.id), tool.active)));
|
|
390
|
+
const { search } = props;
|
|
391
|
+
add("search", [{
|
|
392
|
+
kind: "search",
|
|
393
|
+
id: "search",
|
|
394
|
+
label: labels.Find,
|
|
395
|
+
query: search.query,
|
|
396
|
+
summary: search.query ? search.resultCount ? `${search.activeIndex >= 0 ? search.activeIndex + 1 : "-"} / ${search.resultCount}` : "0" : "",
|
|
397
|
+
previous: button("search-previous", labels["Previous Result"], search.resultCount > 0, props.onPreviousSearchResult),
|
|
398
|
+
next: button("search-next", labels["Next Result"], search.resultCount > 0, props.onNextSearchResult),
|
|
399
|
+
change: (query) => props.onSearchChange(query)
|
|
400
|
+
}]);
|
|
401
|
+
return groups;
|
|
402
|
+
}
|
|
403
|
+
//#endregion
|
|
404
|
+
//#region packages/svelte/src/Toolbar.svelte
|
|
405
|
+
function Toolbar($$renderer, $$props) {
|
|
406
|
+
$$renderer.component(($$renderer) => {
|
|
407
|
+
let { toolbarProps, include } = $$props;
|
|
408
|
+
const groups = $.derived(() => toolbarGroups(toolbarProps, include));
|
|
409
|
+
$$renderer.push(`<div role="toolbar"><!--[-->`);
|
|
410
|
+
const each_array = $.ensure_array_like(groups());
|
|
411
|
+
for (let $$index_1 = 0, $$length = each_array.length; $$index_1 < $$length; $$index_1++) {
|
|
412
|
+
let group = each_array[$$index_1];
|
|
413
|
+
$$renderer.push(`<span${$.attr("data-group", group.id)}><!--[-->`);
|
|
414
|
+
const each_array_1 = $.ensure_array_like(group.controls);
|
|
415
|
+
for (let $$index = 0, $$length = each_array_1.length; $$index < $$length; $$index++) {
|
|
416
|
+
let control = each_array_1[$$index];
|
|
417
|
+
if (control.kind === "text") $$renderer.push(`<!--[0--><span${$.attr("data-control", control.id)}>${$.escape(control.text)}</span>`);
|
|
418
|
+
else if (control.kind === "button") $$renderer.push(`<!--[1--><button type="button"${$.attr("data-control", control.id)}${$.attr("disabled", control.disabled, true)}${$.attr("aria-pressed", control.pressed)}>${$.escape(control.label)}</button>`);
|
|
419
|
+
else $$renderer.push(`<!--[-1--><span data-control="search"><input type="search"${$.attr("aria-label", control.label)}${$.attr("placeholder", control.label)}${$.attr("value", control.query)}/> <span aria-live="polite">${$.escape(control.summary)}</span> <button type="button"${$.attr("data-control", control.previous.id)}${$.attr("disabled", control.previous.disabled, true)}>${$.escape(control.previous.label)}</button> <button type="button"${$.attr("data-control", control.next.id)}${$.attr("disabled", control.next.disabled, true)}>${$.escape(control.next.label)}</button></span>`);
|
|
420
|
+
$$renderer.push(`<!--]-->`);
|
|
421
|
+
}
|
|
422
|
+
$$renderer.push(`<!--]--></span>`);
|
|
423
|
+
}
|
|
424
|
+
$$renderer.push(`<!--]--></div>`);
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
//#endregion
|
|
428
|
+
//#region packages/svelte/src/PageNavigation.svelte
|
|
429
|
+
function PageNavigation($$renderer, $$props) {
|
|
430
|
+
$$renderer.component(($$renderer) => {
|
|
431
|
+
let { toolbarProps } = $$props;
|
|
432
|
+
$$renderer.select({
|
|
433
|
+
"aria-label": toolbarProps.labels.Page,
|
|
434
|
+
value: toolbarProps.pageIndex,
|
|
435
|
+
onchange: (event) => toolbarProps.onPageChange(Number(event.currentTarget.value))
|
|
436
|
+
}, ($$renderer) => {
|
|
437
|
+
$$renderer.push(`<!--[-->`);
|
|
438
|
+
const each_array = $.ensure_array_like(toolbarProps.pages);
|
|
439
|
+
for (let index = 0, $$length = each_array.length; index < $$length; index++) {
|
|
440
|
+
let page = each_array[index];
|
|
441
|
+
$$renderer.option({ value: index }, ($$renderer) => {
|
|
442
|
+
$$renderer.push(`${$.escape(page.name)}`);
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
$$renderer.push(`<!--]-->`);
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
//#endregion
|
|
450
|
+
//#region packages/svelte/src/Inspector.svelte
|
|
451
|
+
function Inspector($$renderer, $$props) {
|
|
452
|
+
$$renderer.component(($$renderer) => {
|
|
453
|
+
let { controller } = $$props;
|
|
454
|
+
$$renderer.push(`<div></div>`);
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
//#endregion
|
|
458
|
+
//#region packages/svelte/src/ShapesPane.svelte
|
|
459
|
+
function ShapesPane($$renderer, $$props) {
|
|
460
|
+
$$renderer.component(($$renderer) => {
|
|
461
|
+
let { controller, locale } = $$props;
|
|
462
|
+
$$renderer.push(`<div></div>`);
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
//#endregion
|
|
466
|
+
export { DiagramCanvas, Inspector, PageNavigation, ShapesPane, Toolbar, VisioViewer, VisioViewer as default, createViewerBuildingBlocks };
|
package/dist/index.svelte.js
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
export * from './runtime.js';
|
|
2
2
|
export { default, default as VisioViewer } from './VisioViewer.svelte';
|
|
3
|
+
export { createViewerBuildingBlocks } from './runtime.js';
|
|
4
|
+
export { default as DiagramCanvas } from './DiagramCanvas.svelte';
|
|
5
|
+
export { default as Toolbar } from './Toolbar.svelte';
|
|
6
|
+
export { default as PageNavigation } from './PageNavigation.svelte';
|
|
7
|
+
export { default as Inspector } from './Inspector.svelte';
|
|
8
|
+
export { default as ShapesPane } from './ShapesPane.svelte';
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
export * from './types/packages/bindings/src/common.js';
|
|
2
|
+
export * from './types/packages/bindings/src/building-blocks.js';
|
|
3
|
+
export * from './types/packages/bindings/src/toolbar-controls.js';
|
|
4
|
+
export * from './types/packages/svelte/src/building-blocks.js';
|
|
2
5
|
export * from './types/src/index.js';
|
|
3
6
|
export * from 'visio-core';
|
package/dist/runtime.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as ui from "ooxml-ui/visio";
|
|
2
|
+
import { ViewerController, ViewerController as ViewerController$1, createWorkerParser, eventKeys, mountViewer, propertyKeys } from "ooxml-ui/visio";
|
|
3
|
+
import * as officeTheme from "ooxml-ui/theme";
|
|
4
|
+
import { onDestroy } from "svelte";
|
|
5
|
+
import { derived, get, writable } from "svelte/store";
|
|
2
6
|
export * from "ooxml-ui/visio";
|
|
3
7
|
export * from "visio-core";
|
|
4
8
|
//#region packages/bindings/src/common.ts
|
|
@@ -158,4 +162,208 @@ function withEventEmitter(props, emit) {
|
|
|
158
162
|
};
|
|
159
163
|
}
|
|
160
164
|
//#endregion
|
|
161
|
-
|
|
165
|
+
//#region packages/bindings/src/building-blocks.ts
|
|
166
|
+
function buildingBlock(key) {
|
|
167
|
+
const value = Reflect.get(ui, key);
|
|
168
|
+
if (typeof value !== "function") throw new Error("Update ooxml-ui to use Visio building blocks.");
|
|
169
|
+
return value;
|
|
170
|
+
}
|
|
171
|
+
/** The mode a host sees: 'edit' only when permission is granted and the file can be saved back. */
|
|
172
|
+
function effectiveMode(state) {
|
|
173
|
+
return buildingBlock("diagramMode")(state);
|
|
174
|
+
}
|
|
175
|
+
/** Framework-neutral ownership only; each adapter supplies its own reactive state. */
|
|
176
|
+
function createBuildingBlockSession(initial = {}) {
|
|
177
|
+
const controller = new ViewerController$1(createWorkerParser());
|
|
178
|
+
controller.canEdit = initial.canEdit === true;
|
|
179
|
+
let options = initial;
|
|
180
|
+
let source;
|
|
181
|
+
let host = null;
|
|
182
|
+
let disposeCanvas;
|
|
183
|
+
let destroyed = false;
|
|
184
|
+
const stopEvents = controller.onEvent((name, detail) => {
|
|
185
|
+
if (name === "document-change") {
|
|
186
|
+
const change = detail;
|
|
187
|
+
options.onDocumentChange?.(change.document);
|
|
188
|
+
options.onDirtyChange?.(change.dirty);
|
|
189
|
+
} else if (name === "document-error") options.onDocumentError?.(detail);
|
|
190
|
+
});
|
|
191
|
+
const fit = () => {
|
|
192
|
+
if (host) buildingBlock("fitDiagramCanvas")(host, controller);
|
|
193
|
+
};
|
|
194
|
+
return {
|
|
195
|
+
controller,
|
|
196
|
+
mount(node) {
|
|
197
|
+
if (destroyed || node === host) return;
|
|
198
|
+
disposeCanvas?.();
|
|
199
|
+
disposeCanvas = void 0;
|
|
200
|
+
host = node;
|
|
201
|
+
if (node) disposeCanvas = buildingBlock("mountDiagramCanvas")(node, controller);
|
|
202
|
+
},
|
|
203
|
+
/** Flat control props; pass the framework's latest options so callbacks stay current. */
|
|
204
|
+
toolbar(latest = options) {
|
|
205
|
+
return buildingBlock("diagramToolbarProps")(controller, fit, latest.locale, {
|
|
206
|
+
onOpenFile: latest.onOpenFile,
|
|
207
|
+
onOpenPageSetup: latest.onOpenPageSetup,
|
|
208
|
+
onOpenSettings: latest.onOpenSettings,
|
|
209
|
+
onOpenShareDialog: latest.onOpenShareDialog
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
/** Acknowledge a host save: clears dirty and emits the dirty change. */
|
|
213
|
+
markClean() {
|
|
214
|
+
controller.markClean();
|
|
215
|
+
},
|
|
216
|
+
update(next) {
|
|
217
|
+
if (destroyed) return;
|
|
218
|
+
options = next;
|
|
219
|
+
controller.canEdit = next.canEdit === true;
|
|
220
|
+
if (source === next.content) return;
|
|
221
|
+
source = next.content;
|
|
222
|
+
controller.cancelLoad();
|
|
223
|
+
if (!source) return;
|
|
224
|
+
const input = source;
|
|
225
|
+
controller.loadSource(async () => {
|
|
226
|
+
return input instanceof Blob ? new Uint8Array(await input.arrayBuffer()) : input;
|
|
227
|
+
}).catch(() => {});
|
|
228
|
+
},
|
|
229
|
+
destroy() {
|
|
230
|
+
if (destroyed) return;
|
|
231
|
+
destroyed = true;
|
|
232
|
+
disposeCanvas?.();
|
|
233
|
+
disposeCanvas = void 0;
|
|
234
|
+
host = null;
|
|
235
|
+
stopEvents();
|
|
236
|
+
controller.destroy();
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/** Resolve the new optional-control theme API only when that control is mounted. */
|
|
241
|
+
function prepareDiagramBlock(host, kind) {
|
|
242
|
+
if (!host) return;
|
|
243
|
+
const prepare = Reflect.get(officeTheme, "prepareOfficeUiBlock");
|
|
244
|
+
if (typeof prepare !== "function") throw new Error("Update ooxml-ui to theme Visio building blocks.");
|
|
245
|
+
prepare(host, kind, "visio");
|
|
246
|
+
}
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region packages/bindings/src/toolbar-controls.ts
|
|
249
|
+
var TOOLBAR_GROUPS = [
|
|
250
|
+
"file",
|
|
251
|
+
"history",
|
|
252
|
+
"zoom",
|
|
253
|
+
"selection",
|
|
254
|
+
"clipboard",
|
|
255
|
+
"tools",
|
|
256
|
+
"search"
|
|
257
|
+
];
|
|
258
|
+
var fire = (action) => () => {
|
|
259
|
+
Promise.resolve().then(action).catch(() => {});
|
|
260
|
+
};
|
|
261
|
+
var button = (id, label, enabled, action, pressed) => ({
|
|
262
|
+
kind: "button",
|
|
263
|
+
id,
|
|
264
|
+
label,
|
|
265
|
+
disabled: !enabled,
|
|
266
|
+
...pressed === void 0 ? {} : { pressed },
|
|
267
|
+
run: fire(action)
|
|
268
|
+
});
|
|
269
|
+
/**
|
|
270
|
+
* What the library Toolbar shows, as plain data every framework maps onto its own elements.
|
|
271
|
+
* Every control reflects `toolbarProps`: edit actions are disabled while the diagram is read-only,
|
|
272
|
+
* viewing actions (zoom, fit, search) never are, and a host dialog button appears only when the
|
|
273
|
+
* host supplied its callback.
|
|
274
|
+
*/
|
|
275
|
+
function toolbarGroups(props, include = TOOLBAR_GROUPS) {
|
|
276
|
+
const { labels } = props;
|
|
277
|
+
const has = props.pages.length > 0;
|
|
278
|
+
const groups = [];
|
|
279
|
+
const add = (id, controls) => {
|
|
280
|
+
if (include.includes(id) && controls.length) groups.push({
|
|
281
|
+
id,
|
|
282
|
+
controls
|
|
283
|
+
});
|
|
284
|
+
};
|
|
285
|
+
add("file", [
|
|
286
|
+
...props.onOpenFile ? [button("open", labels.Open, true, props.onOpenFile)] : [],
|
|
287
|
+
...props.onOpenPageSetup ? [button("page-setup", labels["Page Setup"], has, props.onOpenPageSetup)] : [],
|
|
288
|
+
...props.onOpenShareDialog ? [button("share", labels.Share, has, props.onOpenShareDialog)] : [],
|
|
289
|
+
...props.onOpenSettings ? [button("settings", labels.Options, true, props.onOpenSettings)] : []
|
|
290
|
+
]);
|
|
291
|
+
add("history", [button("undo", labels.Undo, props.canUndo, props.onUndo), button("redo", labels.Redo, props.canRedo, props.onRedo)]);
|
|
292
|
+
add("zoom", [
|
|
293
|
+
button("zoom-out", labels["Zoom Out"], props.canZoomOut, props.onZoomOut),
|
|
294
|
+
{
|
|
295
|
+
kind: "text",
|
|
296
|
+
id: "zoom",
|
|
297
|
+
text: `${Math.round(props.zoom * 100)}%`
|
|
298
|
+
},
|
|
299
|
+
button("zoom-in", labels["Zoom In"], props.canZoomIn, props.onZoomIn),
|
|
300
|
+
button("fit", labels["Fit to Window"], has, props.onFit)
|
|
301
|
+
]);
|
|
302
|
+
add("selection", [
|
|
303
|
+
button("duplicate", labels.Duplicate, props.canDuplicate, props.onDuplicate),
|
|
304
|
+
button("group", labels.Group, props.canGroup, props.onGroup),
|
|
305
|
+
button("ungroup", labels.Ungroup, props.canUngroup, props.onUngroup),
|
|
306
|
+
button("delete", labels.Delete, props.canDelete, props.onDelete)
|
|
307
|
+
]);
|
|
308
|
+
add("clipboard", [
|
|
309
|
+
button("cut", labels.Cut, props.canCut, props.onCut),
|
|
310
|
+
button("copy", labels.Copy, props.canCopy, props.onCopy),
|
|
311
|
+
button("paste", labels.Paste, props.canPaste, props.onPaste)
|
|
312
|
+
]);
|
|
313
|
+
add("tools", props.tools.map((tool) => button(`tool-${tool.id}`, tool.label, tool.id === "pointer" || props.canDraw, () => props.onToolChange(tool.id), tool.active)));
|
|
314
|
+
const { search } = props;
|
|
315
|
+
add("search", [{
|
|
316
|
+
kind: "search",
|
|
317
|
+
id: "search",
|
|
318
|
+
label: labels.Find,
|
|
319
|
+
query: search.query,
|
|
320
|
+
summary: search.query ? search.resultCount ? `${search.activeIndex >= 0 ? search.activeIndex + 1 : "-"} / ${search.resultCount}` : "0" : "",
|
|
321
|
+
previous: button("search-previous", labels["Previous Result"], search.resultCount > 0, props.onPreviousSearchResult),
|
|
322
|
+
next: button("search-next", labels["Next Result"], search.resultCount > 0, props.onNextSearchResult),
|
|
323
|
+
change: (query) => props.onSearchChange(query)
|
|
324
|
+
}]);
|
|
325
|
+
return groups;
|
|
326
|
+
}
|
|
327
|
+
//#endregion
|
|
328
|
+
//#region packages/svelte/src/building-blocks.ts
|
|
329
|
+
/** Call during component initialization. Reactive option changes use blocks.update(options). */
|
|
330
|
+
function createViewerBuildingBlocks(options = {}) {
|
|
331
|
+
const source = "subscribe" in options ? options : void 0;
|
|
332
|
+
const initial = source ? get(source) : options;
|
|
333
|
+
const session = createBuildingBlockSession(initial);
|
|
334
|
+
const state = writable(session.controller.state);
|
|
335
|
+
const latest = writable(initial);
|
|
336
|
+
const stop = session.controller.subscribe((value) => state.set(value));
|
|
337
|
+
let stopOptions = () => {};
|
|
338
|
+
onDestroy(() => {
|
|
339
|
+
stopOptions();
|
|
340
|
+
stop();
|
|
341
|
+
session.destroy();
|
|
342
|
+
});
|
|
343
|
+
const update = (next) => {
|
|
344
|
+
latest.set(next);
|
|
345
|
+
session.update(next);
|
|
346
|
+
};
|
|
347
|
+
if (source) stopOptions = source.subscribe(update);
|
|
348
|
+
else update(initial);
|
|
349
|
+
return {
|
|
350
|
+
controller: session.controller,
|
|
351
|
+
state: { subscribe: state.subscribe },
|
|
352
|
+
toolbarProps: derived([state, latest], ([, next]) => session.toolbar(next)),
|
|
353
|
+
loading: derived(state, (value) => value.loading),
|
|
354
|
+
error: derived(state, (value) => value.error ?? value.edit.error),
|
|
355
|
+
/** Effective permission: host `canEdit` and a drawing that can be saved back. */
|
|
356
|
+
mode: derived(state, (value) => effectiveMode(value)),
|
|
357
|
+
canvasProps: { mount: session.mount },
|
|
358
|
+
inspectorProps: { controller: session.controller },
|
|
359
|
+
shapesProps: derived(latest, (next) => ({
|
|
360
|
+
controller: session.controller,
|
|
361
|
+
locale: next.locale
|
|
362
|
+
})),
|
|
363
|
+
/** Acknowledge a host save: clears dirty and fires `onDirtyChange(false)`. */
|
|
364
|
+
markClean: () => session.markClean(),
|
|
365
|
+
update
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
//#endregion
|
|
369
|
+
export { TOOLBAR_GROUPS, ViewerController, buildingBlock, createBuildingBlockSession, createViewerBuildingBlocks, effectiveMode, eventKeys, mountFrameworkViewer, mountViewer, prepareDiagramBlock, propertyKeys, toolbarGroups, viewerHandle, viewerOptions, viewerStateSource, withEventEmitter };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { ViewerController, type VsdxSource } from 'ooxml-ui/visio';
|
|
2
|
+
import * as ui from 'ooxml-ui/visio';
|
|
3
|
+
/** Host-owned dialogs, as in the PowerPoint building blocks; omitted ones report not-enabled. */
|
|
4
|
+
export interface BuildingBlockHostCallbacks {
|
|
5
|
+
onOpenFile?: (() => void) | undefined;
|
|
6
|
+
onOpenPageSetup?: (() => void) | undefined;
|
|
7
|
+
onOpenSettings?: (() => void) | undefined;
|
|
8
|
+
onOpenShareDialog?: (() => void) | undefined;
|
|
9
|
+
}
|
|
10
|
+
export interface BuildingBlockOptions extends BuildingBlockHostCallbacks {
|
|
11
|
+
content?: VsdxSource | undefined;
|
|
12
|
+
/** Host edit permission. Read-only until it is `true`, so nothing is editable before the host says so. */
|
|
13
|
+
canEdit?: boolean | undefined;
|
|
14
|
+
locale?: string | undefined;
|
|
15
|
+
onDocumentChange?: ((document: NonNullable<ViewerController['state']['document']>) => void) | undefined;
|
|
16
|
+
onDirtyChange?: ((dirty: boolean) => void) | undefined;
|
|
17
|
+
onDocumentError?: ((error: Error) => void) | undefined;
|
|
18
|
+
}
|
|
19
|
+
type Api = Pick<typeof ui, 'mountDiagramCanvas' | 'fitDiagramCanvas' | 'mountDiagramInspector' | 'mountDiagramShapes' | 'diagramToolbarProps' | 'diagramMode'>;
|
|
20
|
+
export declare function buildingBlock<K extends keyof Api>(key: K): Api[K];
|
|
21
|
+
/** The mode a host sees: 'edit' only when permission is granted and the file can be saved back. */
|
|
22
|
+
export declare function effectiveMode(state: ViewerController['state']): 'edit' | 'view';
|
|
23
|
+
/** Framework-neutral ownership only; each adapter supplies its own reactive state. */
|
|
24
|
+
export declare function createBuildingBlockSession(initial?: BuildingBlockOptions): {
|
|
25
|
+
controller: ViewerController;
|
|
26
|
+
mount(node: HTMLElement | null): void;
|
|
27
|
+
/** Flat control props; pass the framework's latest options so callbacks stay current. */
|
|
28
|
+
toolbar(latest?: BuildingBlockOptions): {
|
|
29
|
+
labels: Readonly<Record<"Arc" | "Copy" | "Cut" | "Delete" | "Duplicate" | "Ellipse" | "Find" | "Fit to Window" | "Freeform" | "Group" | "Line" | "Next Result" | "Open" | "Options" | "Page" | "Page Setup" | "Paste" | "Pencil" | "Pointer Tool" | "Previous Result" | "Rectangle" | "Redo" | "Shapes" | "Share" | "Undo" | "Ungroup" | "Zoom In" | "Zoom Out", string>>;
|
|
30
|
+
mode: ui.DiagramMode;
|
|
31
|
+
canEdit: boolean;
|
|
32
|
+
pageIndex: number;
|
|
33
|
+
pages: {
|
|
34
|
+
id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
}[];
|
|
37
|
+
zoom: number;
|
|
38
|
+
selection: readonly import("ooxml-core/visio/ui").VisioShapeSelection[];
|
|
39
|
+
canUndo: boolean;
|
|
40
|
+
canRedo: boolean;
|
|
41
|
+
canDuplicate: boolean;
|
|
42
|
+
canGroup: boolean;
|
|
43
|
+
canUngroup: boolean;
|
|
44
|
+
canDelete: boolean;
|
|
45
|
+
canCut: boolean;
|
|
46
|
+
canCopy: boolean;
|
|
47
|
+
canPaste: boolean;
|
|
48
|
+
canDraw: boolean;
|
|
49
|
+
canZoomIn: boolean;
|
|
50
|
+
canZoomOut: boolean;
|
|
51
|
+
tool: ui.DiagramTool;
|
|
52
|
+
tools: ui.DiagramToolSummary[];
|
|
53
|
+
search: {
|
|
54
|
+
query: string;
|
|
55
|
+
resultCount: number;
|
|
56
|
+
activeIndex: number;
|
|
57
|
+
truncated: boolean;
|
|
58
|
+
};
|
|
59
|
+
onPageChange: (index: number) => void;
|
|
60
|
+
onZoomChange: (zoom: number) => void;
|
|
61
|
+
onZoomIn: () => void;
|
|
62
|
+
onZoomOut: () => void;
|
|
63
|
+
onFit: () => void;
|
|
64
|
+
onUndo: () => Promise<void>;
|
|
65
|
+
onRedo: () => Promise<void>;
|
|
66
|
+
onDuplicate: () => Promise<void>;
|
|
67
|
+
onGroup: () => Promise<void>;
|
|
68
|
+
onUngroup: () => Promise<void>;
|
|
69
|
+
onDelete: () => Promise<void>;
|
|
70
|
+
onCut: () => Promise<void>;
|
|
71
|
+
onCopy: () => Promise<void>;
|
|
72
|
+
onPaste: () => Promise<void>;
|
|
73
|
+
onToolChange: (tool: ui.DiagramTool) => void;
|
|
74
|
+
onTextChange: (pageId: string, shapeId: string, text: string) => Promise<void>;
|
|
75
|
+
onSearchChange: (query: string) => void;
|
|
76
|
+
onNextSearchResult: () => void;
|
|
77
|
+
onPreviousSearchResult: () => void;
|
|
78
|
+
canOpenFile: boolean;
|
|
79
|
+
canOpenPageSetup: boolean;
|
|
80
|
+
canOpenSettings: boolean;
|
|
81
|
+
canOpenShareDialog: boolean;
|
|
82
|
+
onOpenFile?: () => void;
|
|
83
|
+
onOpenPageSetup?: () => void;
|
|
84
|
+
onOpenSettings?: () => void;
|
|
85
|
+
onOpenShareDialog?: () => void;
|
|
86
|
+
};
|
|
87
|
+
/** Acknowledge a host save: clears dirty and emits the dirty change. */
|
|
88
|
+
markClean(): void;
|
|
89
|
+
update(next: BuildingBlockOptions): void;
|
|
90
|
+
destroy(): void;
|
|
91
|
+
};
|
|
92
|
+
export type BuildingBlockSession = ReturnType<typeof createBuildingBlockSession>;
|
|
93
|
+
export type { DiagramToolbarProps, DiagramToolbarLabels, DiagramToolbarHostCallbacks, DiagramMode, DiagramTool, ViewerController, } from 'ooxml-ui/visio';
|
|
94
|
+
/** Resolve the new optional-control theme API only when that control is mounted. */
|
|
95
|
+
export declare function prepareDiagramBlock(host: HTMLElement | null, kind: 'toolbar' | 'tabs'): void;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { DiagramToolbarProps } from 'ooxml-ui/visio';
|
|
2
|
+
/** The groups of the library toolbar; a host picks the ones it wants with `include`. */
|
|
3
|
+
export type ToolbarGroupId = 'file' | 'history' | 'zoom' | 'selection' | 'clipboard' | 'tools' | 'search';
|
|
4
|
+
export declare const TOOLBAR_GROUPS: readonly ToolbarGroupId[];
|
|
5
|
+
export interface ToolbarButton {
|
|
6
|
+
readonly kind: 'button';
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly label: string;
|
|
9
|
+
readonly disabled: boolean;
|
|
10
|
+
/** Set for toggles such as the drawing tools. */
|
|
11
|
+
readonly pressed?: boolean;
|
|
12
|
+
run(): void;
|
|
13
|
+
}
|
|
14
|
+
export interface ToolbarText {
|
|
15
|
+
readonly kind: 'text';
|
|
16
|
+
readonly id: string;
|
|
17
|
+
readonly text: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ToolbarSearch {
|
|
20
|
+
readonly kind: 'search';
|
|
21
|
+
readonly id: 'search';
|
|
22
|
+
readonly label: string;
|
|
23
|
+
readonly query: string;
|
|
24
|
+
/** Result summary for assistive technology, e.g. "2 of 5". */
|
|
25
|
+
readonly summary: string;
|
|
26
|
+
readonly previous: ToolbarButton;
|
|
27
|
+
readonly next: ToolbarButton;
|
|
28
|
+
change(query: string): void;
|
|
29
|
+
}
|
|
30
|
+
export type ToolbarControl = ToolbarButton | ToolbarText | ToolbarSearch;
|
|
31
|
+
export interface ToolbarGroup {
|
|
32
|
+
readonly id: ToolbarGroupId;
|
|
33
|
+
readonly controls: readonly ToolbarControl[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* What the library Toolbar shows, as plain data every framework maps onto its own elements.
|
|
37
|
+
* Every control reflects `toolbarProps`: edit actions are disabled while the diagram is read-only,
|
|
38
|
+
* viewing actions (zoom, fit, search) never are, and a host dialog button appears only when the
|
|
39
|
+
* host supplied its callback.
|
|
40
|
+
*/
|
|
41
|
+
export declare function toolbarGroups(props: DiagramToolbarProps, include?: readonly ToolbarGroupId[]): ToolbarGroup[];
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { type Readable } from 'svelte/store';
|
|
2
|
+
import { type BuildingBlockOptions } from '../../bindings/src/building-blocks.js';
|
|
3
|
+
/** Call during component initialization. Reactive option changes use blocks.update(options). */
|
|
4
|
+
export declare function createViewerBuildingBlocks(options?: BuildingBlockOptions | Readable<BuildingBlockOptions>): {
|
|
5
|
+
controller: import("ooxml-ui/visio").ViewerController;
|
|
6
|
+
state: {
|
|
7
|
+
subscribe: (this: void, run: import("svelte/store").Subscriber<import("ooxml-ui/visio").ViewerState>, invalidate?: () => void) => import("svelte/store").Unsubscriber;
|
|
8
|
+
};
|
|
9
|
+
toolbarProps: Readable<{
|
|
10
|
+
labels: Readonly<Record<"Arc" | "Copy" | "Cut" | "Delete" | "Duplicate" | "Ellipse" | "Find" | "Fit to Window" | "Freeform" | "Group" | "Line" | "Next Result" | "Open" | "Options" | "Page" | "Page Setup" | "Paste" | "Pencil" | "Pointer Tool" | "Previous Result" | "Rectangle" | "Redo" | "Shapes" | "Share" | "Undo" | "Ungroup" | "Zoom In" | "Zoom Out", string>>;
|
|
11
|
+
mode: import("ooxml-ui/visio").DiagramMode;
|
|
12
|
+
canEdit: boolean;
|
|
13
|
+
pageIndex: number;
|
|
14
|
+
pages: {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
}[];
|
|
18
|
+
zoom: number;
|
|
19
|
+
selection: readonly import("ooxml-ui/visio").VisioShapeSelection[];
|
|
20
|
+
canUndo: boolean;
|
|
21
|
+
canRedo: boolean;
|
|
22
|
+
canDuplicate: boolean;
|
|
23
|
+
canGroup: boolean;
|
|
24
|
+
canUngroup: boolean;
|
|
25
|
+
canDelete: boolean;
|
|
26
|
+
canCut: boolean;
|
|
27
|
+
canCopy: boolean;
|
|
28
|
+
canPaste: boolean;
|
|
29
|
+
canDraw: boolean;
|
|
30
|
+
canZoomIn: boolean;
|
|
31
|
+
canZoomOut: boolean;
|
|
32
|
+
tool: import("ooxml-ui/visio").DiagramTool;
|
|
33
|
+
tools: import("ooxml-ui/visio").DiagramToolSummary[];
|
|
34
|
+
search: {
|
|
35
|
+
query: string;
|
|
36
|
+
resultCount: number;
|
|
37
|
+
activeIndex: number;
|
|
38
|
+
truncated: boolean;
|
|
39
|
+
};
|
|
40
|
+
onPageChange: (index: number) => void;
|
|
41
|
+
onZoomChange: (zoom: number) => void;
|
|
42
|
+
onZoomIn: () => void;
|
|
43
|
+
onZoomOut: () => void;
|
|
44
|
+
onFit: () => void;
|
|
45
|
+
onUndo: () => Promise<void>;
|
|
46
|
+
onRedo: () => Promise<void>;
|
|
47
|
+
onDuplicate: () => Promise<void>;
|
|
48
|
+
onGroup: () => Promise<void>;
|
|
49
|
+
onUngroup: () => Promise<void>;
|
|
50
|
+
onDelete: () => Promise<void>;
|
|
51
|
+
onCut: () => Promise<void>;
|
|
52
|
+
onCopy: () => Promise<void>;
|
|
53
|
+
onPaste: () => Promise<void>;
|
|
54
|
+
onToolChange: (tool: import("ooxml-ui/visio").DiagramTool) => void;
|
|
55
|
+
onTextChange: (pageId: string, shapeId: string, text: string) => Promise<void>;
|
|
56
|
+
onSearchChange: (query: string) => void;
|
|
57
|
+
onNextSearchResult: () => void;
|
|
58
|
+
onPreviousSearchResult: () => void;
|
|
59
|
+
canOpenFile: boolean;
|
|
60
|
+
canOpenPageSetup: boolean;
|
|
61
|
+
canOpenSettings: boolean;
|
|
62
|
+
canOpenShareDialog: boolean;
|
|
63
|
+
onOpenFile?: () => void;
|
|
64
|
+
onOpenPageSetup?: () => void;
|
|
65
|
+
onOpenSettings?: () => void;
|
|
66
|
+
onOpenShareDialog?: () => void;
|
|
67
|
+
}>;
|
|
68
|
+
loading: Readable<boolean>;
|
|
69
|
+
error: Readable<Error | null>;
|
|
70
|
+
/** Effective permission: host `canEdit` and a drawing that can be saved back. */
|
|
71
|
+
mode: Readable<"edit" | "view">;
|
|
72
|
+
canvasProps: {
|
|
73
|
+
mount: (node: HTMLElement | null) => void;
|
|
74
|
+
};
|
|
75
|
+
inspectorProps: {
|
|
76
|
+
controller: import("ooxml-ui/visio").ViewerController;
|
|
77
|
+
};
|
|
78
|
+
shapesProps: Readable<{
|
|
79
|
+
controller: import("ooxml-ui/visio").ViewerController;
|
|
80
|
+
locale: string | undefined;
|
|
81
|
+
}>;
|
|
82
|
+
/** Acknowledge a host save: clears dirty and fires `onDirtyChange(false)`. */
|
|
83
|
+
markClean: () => void;
|
|
84
|
+
update: (next: BuildingBlockOptions) => void;
|
|
85
|
+
};
|
|
86
|
+
export type { BuildingBlockOptions, BuildingBlockHostCallbacks, DiagramToolbarProps, } from '../../bindings/src/building-blocks.js';
|
|
87
|
+
export type { ToolbarGroupId } from '../../bindings/src/toolbar-controls.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "visio-svelte-viewer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Local-first Visio viewer for svelte",
|
|
5
5
|
"homepage": "https://christophervr.github.io/ooxml/visio/",
|
|
6
6
|
"bugs": {
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"emf-converter": "4.21.0",
|
|
41
|
-
"ooxml-core": "^1.
|
|
42
|
-
"ooxml-ui": "^1.
|
|
43
|
-
"visio-core": "^0.
|
|
41
|
+
"ooxml-core": "^1.22.0",
|
|
42
|
+
"ooxml-ui": "^1.21.0",
|
|
43
|
+
"visio-core": "^1.0.0"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"svelte": "^5.0.0"
|