visio-svelte-viewer 0.7.4 → 0.8.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.
@@ -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,4 @@
1
+ import type { Component } from 'svelte';
2
+ import type { ViewerController, DiagramToolbarProps } from './runtime.js';
3
+ declare const component: Component<{ mount(node: HTMLElement | null): void; class?: string }>;
4
+ export default component;
@@ -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,4 @@
1
+ import type { Component } from 'svelte';
2
+ import type { ViewerController, DiagramToolbarProps } from './runtime.js';
3
+ declare const component: Component<{ controller: ViewerController }>;
4
+ export default component;
@@ -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,4 @@
1
+ import type { Component } from 'svelte';
2
+ import type { ViewerController, DiagramToolbarProps } from './runtime.js';
3
+ declare const component: Component<{ toolbarProps: DiagramToolbarProps }>;
4
+ export default component;
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import { prepareDiagramBlock } from './runtime.js';
3
+ function theme(host: HTMLElement) { prepareDiagramBlock(host, 'toolbar'); }
4
+ import type { DiagramToolbarProps } from './runtime.js';
5
+ let { toolbarProps }: { toolbarProps: DiagramToolbarProps } = $props();
6
+ </script>
7
+ <div role="toolbar" use:theme>
8
+ <button type="button" disabled={!toolbarProps.canUndo} onclick={() => void toolbarProps.onUndo()}>{toolbarProps.labels.Undo}</button>
9
+ <button type="button" disabled={!toolbarProps.canRedo} onclick={() => void toolbarProps.onRedo()}>{toolbarProps.labels.Redo}</button>
10
+ <button type="button" onclick={toolbarProps.onFit}>{toolbarProps.labels['Fit to Window']}</button>
11
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { Component } from 'svelte';
2
+ import type { ViewerController, DiagramToolbarProps } from './runtime.js';
3
+ declare const component: Component<{ toolbarProps: DiagramToolbarProps }>;
4
+ export default component;
@@ -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, events, class: className, style, 'aria-label': ariaLabel }: Props = $props();
7
+ const options = $derived({ document, pageIndex, zoom, showToolbar, canEdit, ribbonAddIns, 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,8 @@
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';
package/dist/index.js CHANGED
@@ -1,7 +1,10 @@
1
- import { mountViewer, propertyKeys } from "ooxml-ui/visio";
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$4 = $.from_html(`<div></div>`);
150
153
  function VisioViewer($$anchor, $$props) {
151
154
  $.push($$props, true);
152
155
  const options = $.derived(() => ({
@@ -154,6 +157,7 @@ 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,
158
162
  events: $$props.events
159
163
  }));
@@ -269,7 +273,7 @@ function VisioViewer($$anchor, $$props) {
269
273
  exportSvg,
270
274
  createPrintSnapshot
271
275
  };
272
- var div = root();
276
+ var div = root$4();
273
277
  $.action(div, ($$node, $$action_arg) => attach?.($$node, $$action_arg), () => $.get(options));
274
278
  $.template_effect(() => {
275
279
  $.set_class(div, 1, $.clsx($$props.class));
@@ -280,4 +284,201 @@ function VisioViewer($$anchor, $$props) {
280
284
  return $.pop($$exports);
281
285
  }
282
286
  //#endregion
283
- export { VisioViewer, VisioViewer as default };
287
+ //#region packages/bindings/src/building-blocks.ts
288
+ function buildingBlock(key) {
289
+ const value = Reflect.get(ui, key);
290
+ if (typeof value !== "function") throw new Error("Update ooxml-ui to use Visio building blocks.");
291
+ return value;
292
+ }
293
+ /** Framework-neutral ownership only; each adapter supplies its own reactive state. */
294
+ function createBuildingBlockSession() {
295
+ const controller = new ViewerController(createWorkerParser());
296
+ let options = {};
297
+ let source;
298
+ let host = null;
299
+ let disposeCanvas;
300
+ let destroyed = false;
301
+ const stopEvents = controller.onEvent((name, detail) => {
302
+ if (name === "document-change") {
303
+ const change = detail;
304
+ options.onDocumentChange?.(change.document);
305
+ options.onDirtyChange?.(change.dirty);
306
+ } else if (name === "document-error") options.onDocumentError?.(detail);
307
+ });
308
+ const fit = () => {
309
+ if (host) buildingBlock("fitDiagramCanvas")(host, controller);
310
+ };
311
+ return {
312
+ controller,
313
+ mount(node) {
314
+ if (destroyed || node === host) return;
315
+ disposeCanvas?.();
316
+ disposeCanvas = void 0;
317
+ host = node;
318
+ if (node) disposeCanvas = buildingBlock("mountDiagramCanvas")(node, controller);
319
+ },
320
+ toolbar(locale = options.locale) {
321
+ return buildingBlock("diagramToolbarProps")(controller, fit, locale);
322
+ },
323
+ update(next) {
324
+ if (destroyed) return;
325
+ options = next;
326
+ controller.canEdit = next.canEdit !== false;
327
+ if (source === next.content) return;
328
+ source = next.content;
329
+ controller.cancelLoad();
330
+ if (!source) return;
331
+ const input = source;
332
+ controller.loadSource(async () => {
333
+ return input instanceof Blob ? new Uint8Array(await input.arrayBuffer()) : input;
334
+ }).catch(() => {});
335
+ },
336
+ destroy() {
337
+ if (destroyed) return;
338
+ destroyed = true;
339
+ disposeCanvas?.();
340
+ disposeCanvas = void 0;
341
+ host = null;
342
+ stopEvents();
343
+ controller.destroy();
344
+ }
345
+ };
346
+ }
347
+ /** Resolve the new optional-control theme API only when that control is mounted. */
348
+ function prepareDiagramBlock(host, kind) {
349
+ if (!host) return;
350
+ const prepare = Reflect.get(officeTheme, "prepareOfficeUiBlock");
351
+ if (typeof prepare !== "function") throw new Error("Update ooxml-ui to theme Visio building blocks.");
352
+ prepare(host, kind, "visio");
353
+ }
354
+ //#endregion
355
+ //#region packages/svelte/src/building-blocks.ts
356
+ /** Call during component initialization. Reactive option changes use blocks.update(options). */
357
+ function createViewerBuildingBlocks(options = {}) {
358
+ const source = "subscribe" in options ? options : void 0;
359
+ const initial = source ? get(source) : options;
360
+ const session = createBuildingBlockSession();
361
+ const state = writable(session.controller.state);
362
+ const locale = writable(initial.locale);
363
+ const stop = session.controller.subscribe((value) => state.set(value));
364
+ let stopOptions = () => {};
365
+ onDestroy(() => {
366
+ stopOptions();
367
+ stop();
368
+ session.destroy();
369
+ });
370
+ const update = (next) => {
371
+ locale.set(next.locale);
372
+ session.update(next);
373
+ };
374
+ if (source) stopOptions = source.subscribe(update);
375
+ else update(initial);
376
+ return {
377
+ controller: session.controller,
378
+ state: { subscribe: state.subscribe },
379
+ toolbarProps: derived([state, locale], ([, language]) => session.toolbar(language)),
380
+ loading: derived(state, (value) => value.loading),
381
+ error: derived(state, (value) => value.error ?? value.edit.error),
382
+ mode: derived(state, (value) => value.canEdit ? "edit" : "view"),
383
+ canvasProps: { mount: session.mount },
384
+ inspectorProps: { controller: session.controller },
385
+ update
386
+ };
387
+ }
388
+ //#endregion
389
+ //#region packages/svelte/src/DiagramCanvas.svelte
390
+ var root$3 = $.from_html(`<div></div>`);
391
+ function DiagramCanvas($$anchor, $$props) {
392
+ $.push($$props, true);
393
+ let host;
394
+ $.user_effect(() => {
395
+ const current = $$props.mount;
396
+ current(host);
397
+ return () => current(null);
398
+ });
399
+ var div = root$3();
400
+ $.bind_this(div, ($$value) => host = $$value, () => host);
401
+ $.template_effect(() => $.set_class(div, 1, $.clsx($$props.class)));
402
+ $.append($$anchor, div);
403
+ $.pop();
404
+ }
405
+ //#endregion
406
+ //#region packages/svelte/src/Toolbar.svelte
407
+ var root$2 = $.from_html(`<div role="toolbar"><button type="button"> </button> <button type="button"> </button> <button type="button"> </button></div>`);
408
+ function Toolbar($$anchor, $$props) {
409
+ $.push($$props, true);
410
+ function theme(host) {
411
+ prepareDiagramBlock(host, "toolbar");
412
+ }
413
+ var div = root$2();
414
+ var button = $.child(div);
415
+ var text = $.only_child(button, true);
416
+ var button_1 = $.sibling(button, 2);
417
+ var text_1 = $.only_child(button_1, true);
418
+ var button_2 = $.sibling(button_1, 2);
419
+ var text_2 = $.only_child(button_2, true);
420
+ $.reset(div);
421
+ $.action(div, ($$node) => theme?.($$node));
422
+ $.template_effect(() => {
423
+ button.disabled = !$$props.toolbarProps.canUndo;
424
+ $.set_text(text, $$props.toolbarProps.labels.Undo);
425
+ button_1.disabled = !$$props.toolbarProps.canRedo;
426
+ $.set_text(text_1, $$props.toolbarProps.labels.Redo);
427
+ $.set_text(text_2, $$props.toolbarProps.labels["Fit to Window"]);
428
+ });
429
+ $.delegated("click", button, () => void $$props.toolbarProps.onUndo());
430
+ $.delegated("click", button_1, () => void $$props.toolbarProps.onRedo());
431
+ $.delegated("click", button_2, function(...$$args) {
432
+ $$props.toolbarProps.onFit?.apply(this, $$args);
433
+ });
434
+ $.append($$anchor, div);
435
+ $.pop();
436
+ }
437
+ $.delegate(["click"]);
438
+ //#endregion
439
+ //#region packages/svelte/src/PageNavigation.svelte
440
+ var root$1 = $.from_html(`<option> </option>`);
441
+ var root_1 = $.from_html(`<select></select>`);
442
+ function PageNavigation($$anchor, $$props) {
443
+ $.push($$props, true);
444
+ function theme(host) {
445
+ prepareDiagramBlock(host, "tabs");
446
+ }
447
+ var select = root_1();
448
+ $.each(select, 23, () => $$props.toolbarProps.pages, (page) => page.id, ($$anchor, page, index) => {
449
+ var option = root$1();
450
+ var text = $.only_child(option, true);
451
+ var option_value = {};
452
+ $.template_effect(() => {
453
+ $.set_text(text, $.get(page).name);
454
+ if (option_value !== (option_value = $.get(index))) option.value = (option.__value = option_value) ?? "";
455
+ });
456
+ $.append($$anchor, option);
457
+ });
458
+ $.reset(select);
459
+ $.action(select, ($$node) => theme?.($$node));
460
+ var select_value;
461
+ $.init_select(select);
462
+ $.template_effect(() => {
463
+ $.set_attribute(select, "aria-label", $$props.toolbarProps.labels.Page);
464
+ if (select_value !== (select_value = $$props.toolbarProps.pageIndex)) select.value = (select.__value = select_value) ?? "", $.select_option(select, select_value);
465
+ });
466
+ $.delegated("change", select, (event) => $$props.toolbarProps.onPageChange(Number(event.currentTarget.value)));
467
+ $.append($$anchor, select);
468
+ $.pop();
469
+ }
470
+ $.delegate(["change"]);
471
+ //#endregion
472
+ //#region packages/svelte/src/Inspector.svelte
473
+ var root = $.from_html(`<div></div>`);
474
+ function Inspector($$anchor, $$props) {
475
+ $.push($$props, true);
476
+ let host;
477
+ $.user_effect(() => buildingBlock("mountDiagramInspector")(host, $$props.controller));
478
+ var div = root();
479
+ $.bind_this(div, ($$value) => host = $$value, () => host);
480
+ $.append($$anchor, div);
481
+ $.pop();
482
+ }
483
+ //#endregion
484
+ export { DiagramCanvas, Inspector, PageNavigation, Toolbar, VisioViewer, VisioViewer as default, createViewerBuildingBlocks };
@@ -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,12 +87,13 @@ 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, 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,
94
98
  events
95
99
  }));
@@ -191,4 +195,145 @@ function VisioViewer($$renderer, $$props) {
191
195
  });
192
196
  }
193
197
  //#endregion
194
- export { VisioViewer, VisioViewer as default };
198
+ //#region packages/bindings/src/building-blocks.ts
199
+ function buildingBlock(key) {
200
+ const value = Reflect.get(ui, key);
201
+ if (typeof value !== "function") throw new Error("Update ooxml-ui to use Visio building blocks.");
202
+ return value;
203
+ }
204
+ /** Framework-neutral ownership only; each adapter supplies its own reactive state. */
205
+ function createBuildingBlockSession() {
206
+ const controller = new ViewerController(createWorkerParser());
207
+ let options = {};
208
+ let source;
209
+ let host = null;
210
+ let disposeCanvas;
211
+ let destroyed = false;
212
+ const stopEvents = controller.onEvent((name, detail) => {
213
+ if (name === "document-change") {
214
+ const change = detail;
215
+ options.onDocumentChange?.(change.document);
216
+ options.onDirtyChange?.(change.dirty);
217
+ } else if (name === "document-error") options.onDocumentError?.(detail);
218
+ });
219
+ const fit = () => {
220
+ if (host) buildingBlock("fitDiagramCanvas")(host, controller);
221
+ };
222
+ return {
223
+ controller,
224
+ mount(node) {
225
+ if (destroyed || node === host) return;
226
+ disposeCanvas?.();
227
+ disposeCanvas = void 0;
228
+ host = node;
229
+ if (node) disposeCanvas = buildingBlock("mountDiagramCanvas")(node, controller);
230
+ },
231
+ toolbar(locale = options.locale) {
232
+ return buildingBlock("diagramToolbarProps")(controller, fit, locale);
233
+ },
234
+ update(next) {
235
+ if (destroyed) return;
236
+ options = next;
237
+ controller.canEdit = next.canEdit !== false;
238
+ if (source === next.content) return;
239
+ source = next.content;
240
+ controller.cancelLoad();
241
+ if (!source) return;
242
+ const input = source;
243
+ controller.loadSource(async () => {
244
+ return input instanceof Blob ? new Uint8Array(await input.arrayBuffer()) : input;
245
+ }).catch(() => {});
246
+ },
247
+ destroy() {
248
+ if (destroyed) return;
249
+ destroyed = true;
250
+ disposeCanvas?.();
251
+ disposeCanvas = void 0;
252
+ host = null;
253
+ stopEvents();
254
+ controller.destroy();
255
+ }
256
+ };
257
+ }
258
+ //#endregion
259
+ //#region packages/svelte/src/building-blocks.ts
260
+ /** Call during component initialization. Reactive option changes use blocks.update(options). */
261
+ function createViewerBuildingBlocks(options = {}) {
262
+ const source = "subscribe" in options ? options : void 0;
263
+ const initial = source ? get(source) : options;
264
+ const session = createBuildingBlockSession();
265
+ const state = writable(session.controller.state);
266
+ const locale = writable(initial.locale);
267
+ const stop = session.controller.subscribe((value) => state.set(value));
268
+ let stopOptions = () => {};
269
+ onDestroy(() => {
270
+ stopOptions();
271
+ stop();
272
+ session.destroy();
273
+ });
274
+ const update = (next) => {
275
+ locale.set(next.locale);
276
+ session.update(next);
277
+ };
278
+ if (source) stopOptions = source.subscribe(update);
279
+ else update(initial);
280
+ return {
281
+ controller: session.controller,
282
+ state: { subscribe: state.subscribe },
283
+ toolbarProps: derived([state, locale], ([, language]) => session.toolbar(language)),
284
+ loading: derived(state, (value) => value.loading),
285
+ error: derived(state, (value) => value.error ?? value.edit.error),
286
+ mode: derived(state, (value) => value.canEdit ? "edit" : "view"),
287
+ canvasProps: { mount: session.mount },
288
+ inspectorProps: { controller: session.controller },
289
+ update
290
+ };
291
+ }
292
+ //#endregion
293
+ //#region packages/svelte/src/DiagramCanvas.svelte
294
+ function DiagramCanvas($$renderer, $$props) {
295
+ $$renderer.component(($$renderer) => {
296
+ let { mount, class: className } = $$props;
297
+ $$renderer.push(`<div${$.attr_class($.clsx(className))}></div>`);
298
+ });
299
+ }
300
+ //#endregion
301
+ //#region packages/svelte/src/Toolbar.svelte
302
+ function Toolbar($$renderer, $$props) {
303
+ $$renderer.component(($$renderer) => {
304
+ let { toolbarProps } = $$props;
305
+ $$renderer.push(`<div role="toolbar"><button type="button"${$.attr("disabled", !toolbarProps.canUndo, true)}>${$.escape(toolbarProps.labels.Undo)}</button> <button type="button"${$.attr("disabled", !toolbarProps.canRedo, true)}>${$.escape(toolbarProps.labels.Redo)}</button> <button type="button">${$.escape(toolbarProps.labels["Fit to Window"])}</button></div>`);
306
+ });
307
+ }
308
+ //#endregion
309
+ //#region packages/svelte/src/PageNavigation.svelte
310
+ function PageNavigation($$renderer, $$props) {
311
+ $$renderer.component(($$renderer) => {
312
+ let { toolbarProps } = $$props;
313
+ $$renderer.select({
314
+ "aria-label": toolbarProps.labels.Page,
315
+ value: toolbarProps.pageIndex,
316
+ onchange: (event) => toolbarProps.onPageChange(Number(event.currentTarget.value))
317
+ }, ($$renderer) => {
318
+ $$renderer.push(`<!--[-->`);
319
+ const each_array = $.ensure_array_like(toolbarProps.pages);
320
+ for (let index = 0, $$length = each_array.length; index < $$length; index++) {
321
+ let page = each_array[index];
322
+ $$renderer.option({ value: index }, ($$renderer) => {
323
+ $$renderer.push(`${$.escape(page.name)}`);
324
+ });
325
+ }
326
+ $$renderer.push(`<!--]-->`);
327
+ });
328
+ });
329
+ }
330
+ //#endregion
331
+ //#region packages/svelte/src/Inspector.svelte
332
+ function Inspector($$renderer, $$props) {
333
+ $$renderer.component(($$renderer) => {
334
+ let { controller } = $$props;
335
+ $$renderer.push(`<div></div>`);
336
+ });
337
+ }
338
+ //#endregion
339
+ export { DiagramCanvas, Inspector, PageNavigation, Toolbar, VisioViewer, VisioViewer as default, createViewerBuildingBlocks };
@@ -1,2 +1,7 @@
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';
package/dist/runtime.d.ts CHANGED
@@ -1,3 +1,5 @@
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/svelte/src/building-blocks.js';
2
4
  export * from './types/src/index.js';
3
5
  export * from 'visio-core';
package/dist/runtime.js CHANGED
@@ -1,4 +1,8 @@
1
- import { ViewerController, eventKeys, mountViewer, propertyKeys } from "ooxml-ui/visio";
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,106 @@ function withEventEmitter(props, emit) {
158
162
  };
159
163
  }
160
164
  //#endregion
161
- export { ViewerController, eventKeys, mountFrameworkViewer, mountViewer, propertyKeys, viewerHandle, viewerOptions, viewerStateSource, withEventEmitter };
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
+ /** Framework-neutral ownership only; each adapter supplies its own reactive state. */
172
+ function createBuildingBlockSession() {
173
+ const controller = new ViewerController$1(createWorkerParser());
174
+ let options = {};
175
+ let source;
176
+ let host = null;
177
+ let disposeCanvas;
178
+ let destroyed = false;
179
+ const stopEvents = controller.onEvent((name, detail) => {
180
+ if (name === "document-change") {
181
+ const change = detail;
182
+ options.onDocumentChange?.(change.document);
183
+ options.onDirtyChange?.(change.dirty);
184
+ } else if (name === "document-error") options.onDocumentError?.(detail);
185
+ });
186
+ const fit = () => {
187
+ if (host) buildingBlock("fitDiagramCanvas")(host, controller);
188
+ };
189
+ return {
190
+ controller,
191
+ mount(node) {
192
+ if (destroyed || node === host) return;
193
+ disposeCanvas?.();
194
+ disposeCanvas = void 0;
195
+ host = node;
196
+ if (node) disposeCanvas = buildingBlock("mountDiagramCanvas")(node, controller);
197
+ },
198
+ toolbar(locale = options.locale) {
199
+ return buildingBlock("diagramToolbarProps")(controller, fit, locale);
200
+ },
201
+ update(next) {
202
+ if (destroyed) return;
203
+ options = next;
204
+ controller.canEdit = next.canEdit !== false;
205
+ if (source === next.content) return;
206
+ source = next.content;
207
+ controller.cancelLoad();
208
+ if (!source) return;
209
+ const input = source;
210
+ controller.loadSource(async () => {
211
+ return input instanceof Blob ? new Uint8Array(await input.arrayBuffer()) : input;
212
+ }).catch(() => {});
213
+ },
214
+ destroy() {
215
+ if (destroyed) return;
216
+ destroyed = true;
217
+ disposeCanvas?.();
218
+ disposeCanvas = void 0;
219
+ host = null;
220
+ stopEvents();
221
+ controller.destroy();
222
+ }
223
+ };
224
+ }
225
+ /** Resolve the new optional-control theme API only when that control is mounted. */
226
+ function prepareDiagramBlock(host, kind) {
227
+ if (!host) return;
228
+ const prepare = Reflect.get(officeTheme, "prepareOfficeUiBlock");
229
+ if (typeof prepare !== "function") throw new Error("Update ooxml-ui to theme Visio building blocks.");
230
+ prepare(host, kind, "visio");
231
+ }
232
+ //#endregion
233
+ //#region packages/svelte/src/building-blocks.ts
234
+ /** Call during component initialization. Reactive option changes use blocks.update(options). */
235
+ function createViewerBuildingBlocks(options = {}) {
236
+ const source = "subscribe" in options ? options : void 0;
237
+ const initial = source ? get(source) : options;
238
+ const session = createBuildingBlockSession();
239
+ const state = writable(session.controller.state);
240
+ const locale = writable(initial.locale);
241
+ const stop = session.controller.subscribe((value) => state.set(value));
242
+ let stopOptions = () => {};
243
+ onDestroy(() => {
244
+ stopOptions();
245
+ stop();
246
+ session.destroy();
247
+ });
248
+ const update = (next) => {
249
+ locale.set(next.locale);
250
+ session.update(next);
251
+ };
252
+ if (source) stopOptions = source.subscribe(update);
253
+ else update(initial);
254
+ return {
255
+ controller: session.controller,
256
+ state: { subscribe: state.subscribe },
257
+ toolbarProps: derived([state, locale], ([, language]) => session.toolbar(language)),
258
+ loading: derived(state, (value) => value.loading),
259
+ error: derived(state, (value) => value.error ?? value.edit.error),
260
+ mode: derived(state, (value) => value.canEdit ? "edit" : "view"),
261
+ canvasProps: { mount: session.mount },
262
+ inspectorProps: { controller: session.controller },
263
+ update
264
+ };
265
+ }
266
+ //#endregion
267
+ export { ViewerController, buildingBlock, createBuildingBlockSession, createViewerBuildingBlocks, eventKeys, mountFrameworkViewer, mountViewer, prepareDiagramBlock, propertyKeys, viewerHandle, viewerOptions, viewerStateSource, withEventEmitter };
@@ -0,0 +1,53 @@
1
+ import { ViewerController, type VsdxSource } from 'ooxml-ui/visio';
2
+ import * as ui from 'ooxml-ui/visio';
3
+ export interface BuildingBlockOptions {
4
+ content?: VsdxSource | undefined;
5
+ canEdit?: boolean | undefined;
6
+ locale?: string | undefined;
7
+ onDocumentChange?: ((document: NonNullable<ViewerController['state']['document']>) => void) | undefined;
8
+ onDirtyChange?: ((dirty: boolean) => void) | undefined;
9
+ onDocumentError?: ((error: Error) => void) | undefined;
10
+ }
11
+ type Api = Pick<typeof ui, 'mountDiagramCanvas' | 'fitDiagramCanvas' | 'mountDiagramInspector' | 'diagramToolbarProps'>;
12
+ export declare function buildingBlock<K extends keyof Api>(key: K): Api[K];
13
+ /** Framework-neutral ownership only; each adapter supplies its own reactive state. */
14
+ export declare function createBuildingBlockSession(): {
15
+ controller: ViewerController;
16
+ mount(node: HTMLElement | null): void;
17
+ toolbar(locale?: string | undefined): {
18
+ labels: {
19
+ [k: string]: string;
20
+ };
21
+ canEdit: boolean;
22
+ pageIndex: number;
23
+ pages: {
24
+ id: string;
25
+ name: string;
26
+ }[];
27
+ zoom: number;
28
+ selection: readonly import("ooxml-core/visio/ui").VisioShapeSelection[];
29
+ canUndo: boolean;
30
+ canRedo: boolean;
31
+ canDuplicate: boolean;
32
+ canGroup: boolean;
33
+ canUngroup: boolean;
34
+ onPageChange: (index: number) => void;
35
+ onZoomChange: (zoom: number) => void;
36
+ onFit: () => void;
37
+ onUndo: () => Promise<void>;
38
+ onRedo: () => Promise<void>;
39
+ onDuplicate: () => Promise<void>;
40
+ onGroup: () => Promise<void>;
41
+ onUngroup: () => Promise<void>;
42
+ onTextChange: (pageId: string, shapeId: string, text: string) => Promise<void>;
43
+ onSearchChange: (query: string) => void;
44
+ onNextSearchResult: () => void;
45
+ onPreviousSearchResult: () => void;
46
+ };
47
+ update(next: BuildingBlockOptions): void;
48
+ destroy(): void;
49
+ };
50
+ export type BuildingBlockSession = ReturnType<typeof createBuildingBlockSession>;
51
+ export type { DiagramToolbarProps, ViewerController } from 'ooxml-ui/visio';
52
+ /** Resolve the new optional-control theme API only when that control is mounted. */
53
+ export declare function prepareDiagramBlock(host: HTMLElement | null, kind: 'toolbar' | 'tabs'): void;
@@ -0,0 +1,50 @@
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: {
11
+ [k: string]: string;
12
+ };
13
+ canEdit: boolean;
14
+ pageIndex: number;
15
+ pages: {
16
+ id: string;
17
+ name: string;
18
+ }[];
19
+ zoom: number;
20
+ selection: readonly import("ooxml-ui/visio").VisioShapeSelection[];
21
+ canUndo: boolean;
22
+ canRedo: boolean;
23
+ canDuplicate: boolean;
24
+ canGroup: boolean;
25
+ canUngroup: boolean;
26
+ onPageChange: (index: number) => void;
27
+ onZoomChange: (zoom: number) => void;
28
+ onFit: () => void;
29
+ onUndo: () => Promise<void>;
30
+ onRedo: () => Promise<void>;
31
+ onDuplicate: () => Promise<void>;
32
+ onGroup: () => Promise<void>;
33
+ onUngroup: () => Promise<void>;
34
+ onTextChange: (pageId: string, shapeId: string, text: string) => Promise<void>;
35
+ onSearchChange: (query: string) => void;
36
+ onNextSearchResult: () => void;
37
+ onPreviousSearchResult: () => void;
38
+ }>;
39
+ loading: Readable<boolean>;
40
+ error: Readable<Error | null>;
41
+ mode: Readable<"edit" | "view">;
42
+ canvasProps: {
43
+ mount: (node: HTMLElement | null) => void;
44
+ };
45
+ inspectorProps: {
46
+ controller: import("ooxml-ui/visio").ViewerController;
47
+ };
48
+ update: (next: BuildingBlockOptions) => void;
49
+ };
50
+ export type { BuildingBlockOptions, DiagramToolbarProps } from '../../bindings/src/building-blocks.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "visio-svelte-viewer",
3
- "version": "0.7.4",
3
+ "version": "0.8.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.19.2",
42
- "ooxml-ui": "^1.18.3",
43
- "visio-core": "^0.4.1"
41
+ "ooxml-core": "^1.20.0",
42
+ "ooxml-ui": "^1.19.0",
43
+ "visio-core": "^0.5.0"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "svelte": "^5.0.0"