visio-solid-viewer 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,9 +1,89 @@
1
1
  # visio-solid-viewer
2
2
 
3
- Local-first Visio viewer for solid.
3
+ [![npm version](https://img.shields.io/npm/v/visio-solid-viewer.svg)](https://www.npmjs.com/package/visio-solid-viewer)
4
+ [![license](https://img.shields.io/npm/l/visio-solid-viewer.svg)](https://github.com/ChristopherVR/visio-viewer/blob/main/LICENSE)
5
+ [![types](https://img.shields.io/npm/types/visio-solid-viewer.svg)](https://www.npmjs.com/package/visio-solid-viewer)
4
6
 
5
- `npm install visio-solid-viewer`
7
+ > A browser Visio `.vsdx` viewer for Solid 1.9 or later within Solid 1. This package ships the functional viewer and its framework adapter.
6
8
 
7
- Exports the shared viewer API and the framework adapter. Files stay in the browser. Rendering and editing are beta features; native Visio parity is not established.
9
+ [Live demo](https://christophervr.github.io/visio-viewer/demo/) | [npm](https://www.npmjs.com/package/visio-solid-viewer) | [Full docs](https://christophervr.github.io/visio-viewer/) | [Source](https://github.com/ChristopherVR/visio-viewer)
8
10
 
9
- [Guide](https://christophervr.github.io/visio-viewer/docs/)
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install visio-solid-viewer
15
+ ```
16
+
17
+ ## Quick start
18
+
19
+ ```tsx
20
+ import { VisioViewer, type ViewerHandle } from 'visio-solid-viewer';
21
+
22
+ export function Diagram() {
23
+ let viewer: ViewerHandle | undefined;
24
+ return (
25
+ <>
26
+ <input
27
+ type="file"
28
+ accept=".vsdx"
29
+ onChange={async (event) => {
30
+ const file = event.currentTarget.files?.[0];
31
+ if (file) await viewer?.load(file);
32
+ }}
33
+ />
34
+ <VisioViewer
35
+ viewerRef={(handle) => {
36
+ viewer = handle;
37
+ }}
38
+ showToolbar
39
+ style={{ height: '600px' }}
40
+ />
41
+ </>
42
+ );
43
+ }
44
+ ```
45
+
46
+ ## Features
47
+
48
+ | Feature | Description |
49
+ | ---------- | ------------------------------------------------------------------- |
50
+ | Viewing | One SVG renderer, page selection, zoom, layers and text search. |
51
+ | Editing | Core-validated text and geometry operations with bounded undo/redo. |
52
+ | Export | Source-backed VSDX copies, static SVG and print snapshots. |
53
+ | Frameworks | One shared `<visio-viewer>` UI behind six adapters. |
54
+
55
+ ## API
56
+
57
+ The shared properties are `document` (a parsed `VisioDocument`, or `null` to clear),
58
+ `pageIndex` (zero-based), `zoom` (`1` means 100%), `showToolbar` and `events`.
59
+ The callback map uses `document-load`, `document-change`, `document-error`,
60
+ `page-change`, `zoom-change` and `shape-select`. File loading uses the imperative
61
+ `load(File | Blob | Uint8Array | ArrayBuffer)` handle; `document` is not a file URL.
62
+ Provide a height for the viewer host. Mount and load files in the browser.
63
+
64
+ The handle supports `fit()`, `replacePlainText(pageId, shapeId, text)`,
65
+ `applyEdits(edits)`, `undo()`, `redo()` and `exportVsdx()`.
66
+ `exportVsdx()` returns `{ bytes, dirty, diagnostics }`; saving or downloading those
67
+ bytes is the application's responsibility. Load original bytes through `load()`
68
+ to enable source-backed editing and export. Handles are usable after mount.
69
+
70
+ Every viewer package includes the same browser UI and re-exports the
71
+ `visio-core` document API. Parsing and editing belong to `ooxml-core/visio`;
72
+ framework bindings only manage lifecycle, properties and events.
73
+
74
+ ## Limitations
75
+
76
+ Rendering and editing are beta features. Supported text and geometry edits are
77
+ bounded by core validation; unsupported operations reject and diagnostics report
78
+ limitations. Native Visio layout parity and lossless export are not established.
79
+ Files stay in the browser unless your application sends them elsewhere.
80
+
81
+ ## Documentation
82
+
83
+ [Viewer guide](https://christophervr.github.io/visio-viewer/docs/) |
84
+ [Demo](https://christophervr.github.io/visio-viewer/demo/) |
85
+ [Source](https://github.com/ChristopherVR/visio-viewer)
86
+
87
+ ## License
88
+
89
+ Apache-2.0.
package/dist/index.js CHANGED
@@ -2470,6 +2470,77 @@ summary::marker { color:var(--_vv-muted); font-size:10px; }
2470
2470
  .zoom-controls [data-action="in"],.zoom-controls [data-action="out"] { min-width:44px; }
2471
2471
  .layer-controls input { min-height:20px; }
2472
2472
  }
2473
+ /* Suite ribbon: tabs lead directly into command groups, with page navigation inside. */
2474
+ .ribbon-tabs { height:40px; }
2475
+ .ribbon-tabs button { min-height:39px; padding:8px 16px; }
2476
+ .ribbon-content { min-height:104px; padding:4px 4px; }
2477
+ .ribbon-primary { height:auto; min-height:92px; width:238px; flex:none; flex-wrap:wrap; justify-content:center; gap:2px; padding:10px 12px 18px; border-right:1px solid var(--_vv-border); position:relative; order:1; }
2478
+ .ribbon-primary .page-picker { flex-direction:column; align-items:start; gap:5px; }
2479
+ .ribbon-primary .page-picker select { width:160px; max-width:100%; }
2480
+ .ribbon-primary .spacer { display:none; }
2481
+ .ribbon-primary .local-label { position:absolute; bottom:4px; left:0; width:100%; text-align:center; }
2482
+ .search-group { order:2; width:320px; }
2483
+ .ribbon-hint { order:3; padding:10px 18px; }
2484
+ .ribbon-command { min-width:82px; }
2485
+ .pane-close { display:none; }
2486
+ @media(max-width:760px) {
2487
+ .ribbon-tabs { height:44px; }
2488
+ .ribbon-tabs button { min-height:44px; }
2489
+ .ribbon-content { min-height:54px; padding:4px 0; }
2490
+ .ribbon-primary { min-height:44px; height:44px; width:100%; padding:0 8px; border:0; flex-wrap:nowrap; gap:4px; order:0; }
2491
+ .ribbon-primary .page-picker { flex-direction:row; flex:1; align-items:center; gap:8px; }
2492
+ .ribbon-primary .page-picker select { flex:1; width:100%; min-width:0; }
2493
+ .search-group { flex:0 0 100%; width:100%; min-height:54px; }
2494
+ .search-feedback,.group-label { display:none; }
2495
+ .ribbon-content { overflow-x:auto; scroll-snap-type:x mandatory; }
2496
+ .ribbon-primary,.search-group { scroll-snap-align:start; }
2497
+ .workspace { display:flex; position:relative; overflow:hidden; }
2498
+ .viewport { flex:1; width:100%; height:100%; min-height:0; padding:16px 4px; }
2499
+ .inspector-pane { position:absolute; inset:0 0 0 auto; width:min(320px,100%); z-index:4; overflow:auto; border-left:1px solid var(--_vv-border); box-shadow:-8px 0 24px #0002; }
2500
+ .pane-close { display:block; width:44px; height:44px; padding:0; font-size:22px; background:transparent; border:0; }
2501
+ .inspector-kind { margin-left:auto; }
2502
+ .page-rail { position:absolute; inset:0 auto 0 0; width:180px; max-height:none; z-index:3; border-right:1px solid var(--_vv-border); background:var(--_vv-secondary); }
2503
+ .page-list { flex-direction:column; }
2504
+ .page-list li { flex:none; }
2505
+ .notes-strip { display:none; }
2506
+ .status { min-height:48px; padding:2px 8px; }
2507
+ .status-message { display:none; }
2508
+ }
2509
+ .toolbar { position:relative; }
2510
+ .ribbon-tools { display:flex; flex:none; order:0; }
2511
+ .tools-content { display:flex; align-items:stretch; }
2512
+ .ribbon-tools>summary { display:none; }
2513
+ .ribbon-command { font-size:12px; min-width:88px; }
2514
+ .ribbon-hint { font-size:12px; line-height:20px; flex:1; }
2515
+ .group-label { font-size:11px; line-height:14px; }
2516
+ .inspector-card,.edit-controls,.layer-controls { font-size:12px; line-height:18px; }
2517
+ .selection-hint,.document-card dl { font-size:12px; }
2518
+ .pane-heading { font-size:12px; }
2519
+ .inspector-pane .pane-heading { position:sticky; top:0; z-index:1; background:var(--_vv-secondary); flex:none; }
2520
+ .status .notes-strip { border:0; padding:0 8px; background:transparent; min-height:28px; }
2521
+ .status .notes-strip>span { display:none; }
2522
+ .status-message { flex:1; }
2523
+ @media(max-width:760px) {
2524
+ #home-panel { overflow:visible; min-height:54px; padding:4px; }
2525
+ .ribbon-primary { width:calc(100% - 92px); min-width:0; flex:1; padding:0 4px; }
2526
+ .ribbon-primary .page-picker { font-size:0; gap:0; }
2527
+ .ribbon-primary .page-picker select { font-size:12px; }
2528
+ .ribbon-tools { display:block; flex:0 0 84px; width:84px; order:1; }
2529
+ .ribbon-tools>summary { display:flex; min-height:44px; align-items:center; justify-content:center; gap:6px; padding:0 10px; border:1px solid var(--_vv-border); background:var(--_vv-surface); border-radius:4px; font-size:12px; cursor:pointer; list-style:none; }
2530
+ .ribbon-tools>summary::-webkit-details-marker { display:none; }
2531
+ .ribbon-tools .tools-content { display:flex; position:absolute; top:100%; left:4px; right:4px; z-index:6; flex-direction:column; padding:12px; gap:12px; border:1px solid var(--_vv-border); border-radius:4px; background:var(--_vv-surface); box-shadow:0 12px 28px #0003; max-height:60vh; overflow:auto; }
2532
+ .ribbon-tools:not([open])>.tools-content { display:none; }
2533
+ .ribbon-tools .ribbon-group { display:flex; width:100%; min-height:64px; border:0; padding:0; }
2534
+ .ribbon-tools .ribbon-actions { justify-content:space-between; }
2535
+ .ribbon-tools .ribbon-command { min-width:88px; font-size:12px; }
2536
+ .ribbon-tools .search-group { order:1; flex:auto; }
2537
+ .ribbon-tools .search-feedback { display:block; }
2538
+ .status { flex-wrap:nowrap; gap:4px; min-height:48px; }
2539
+ .zoom-controls { width:auto; flex:1; gap:0; }
2540
+ .zoom-divider { margin:0; }
2541
+ .status .notes-strip { display:none; }
2542
+ }
2543
+ @media(pointer:coarse) { .ribbon-tabs {height:45px;min-height:45px;} .ribbon-tabs button {min-height:44px;height:44px;} }
2473
2544
  @media(prefers-reduced-motion:reduce) { * { scroll-behavior:auto !important; } }
2474
2545
  `;
2475
2546
  //#endregion
@@ -2783,22 +2854,24 @@ function renderSearchControls(controls, state) {
2783
2854
  /** Only static application markup belongs here. All document labels are inserted as text. */
2784
2855
  var viewerChromeTemplate = `
2785
2856
  <div class="toolbar" role="group" aria-label="Diagram controls">
2786
- <div class="ribbon-primary">
2787
- <label class="page-picker">Page <select aria-label="Page"></select></label>
2788
- <div class="page-stepper"><button type="button" data-chrome="previous-page" aria-label="Previous page">‹</button><button type="button" data-chrome="next-page" aria-label="Next page">›</button></div>
2789
- <span class="spacer"></span><span class="local-label">Local workspace</span>
2790
- </div>
2857
+
2791
2858
  <div class="ribbon-tabs" role="tablist" aria-label="Ribbon">
2792
2859
  <button type="button" id="home-tab" role="tab" aria-selected="true" aria-controls="home-panel" data-tab="home">Home</button>
2793
2860
  <button type="button" id="view-tab" role="tab" aria-selected="false" aria-controls="view-panel" tabindex="-1" data-tab="view">View</button>
2794
2861
  </div>
2795
2862
  <div class="ribbon-content" id="home-panel" role="tabpanel" aria-labelledby="home-tab">
2796
- <div class="ribbon-group search-group">${searchTemplate}<span class="group-label">Find in drawing</span></div>
2863
+ <details class="ribbon-tools" open><summary>Tools <span aria-hidden="true">⌄</span></summary><div class="tools-content"><div class="ribbon-group search-group">${searchTemplate}<span class="group-label">Find in drawing</span></div>
2797
2864
  <div class="ribbon-group"><div class="ribbon-actions">
2798
2865
  <button class="ribbon-command" type="button" data-chrome="selection"><span class="command-icon" data-icon="selection" aria-hidden="true"></span><span>Shape details</span></button>
2799
2866
  <button class="ribbon-command" type="button" data-chrome="edit"><span class="command-icon" data-icon="edit" aria-hidden="true"></span><span>Edit text</span></button>
2800
2867
  <button class="ribbon-command" type="button" data-chrome="layers"><span class="command-icon" data-icon="layers" aria-hidden="true"></span><span>Layers</span></button>
2801
2868
  </div><span class="group-label">Inspect and edit</span></div>
2869
+ </div></details>
2870
+ <div class="ribbon-primary">
2871
+ <label class="page-picker">Page <select aria-label="Page"></select></label>
2872
+ <div class="page-stepper"><button type="button" data-chrome="previous-page" aria-label="Previous page">‹</button><button type="button" data-chrome="next-page" aria-label="Next page">›</button></div>
2873
+ <span class="spacer"></span><span class="local-label">Local workspace</span>
2874
+ </div>
2802
2875
  <p class="ribbon-hint">Select a shape to inspect its details.<br>Text editing is experimental.</p>
2803
2876
  </div>
2804
2877
  <div class="ribbon-content" id="view-panel" role="tabpanel" aria-labelledby="view-tab" hidden>
@@ -2814,7 +2887,7 @@ var viewerChromeTemplate = `
2814
2887
  <nav id="page-rail" class="page-rail" aria-label="Diagram pages"><div class="pane-heading"><span>Pages</span><span data-page-count>0</span></div><ol class="page-list"></ol><p class="page-empty">Open a drawing to see its pages.</p></nav>
2815
2888
  <div class="viewport" tabindex="0" role="region" aria-label="Diagram canvas"></div>
2816
2889
  <aside id="inspector-pane" class="inspector-pane" aria-label="Drawing inspector">
2817
- <div class="pane-heading"><span>Inspector</span><span class="inspector-kind">Drawing</span></div>
2890
+ <div class="pane-heading"><span>Inspector</span><span class="inspector-kind">Drawing</span><button class="pane-close" type="button" data-chrome="inspector" aria-label="Close inspector">×</button></div>
2818
2891
  <div class="inspector-body">
2819
2892
  <section class="inspector-card document-card" aria-label="Current page"><h2>Current page</h2><p class="current-page-name" data-page-name>No diagram open</p><dl><dt>Size</dt><dd data-page-size>No page</dd><dt>Shapes</dt><dd data-page-shapes>No shapes</dd></dl></section>
2820
2893
  <p class="selection-hint">Select a shape on the canvas to see its data and links.</p>
@@ -2824,8 +2897,7 @@ var viewerChromeTemplate = `
2824
2897
  </div>
2825
2898
  </aside>
2826
2899
  </div>
2827
- <div class="notes-strip"><button type="button" data-chrome="notes" aria-controls="inspector-pane" aria-expanded="false">Notes<span class="notes-count" data-note-count></span></button><span>Files stay in your browser</span></div>
2828
- <div class="status"><div class="status-message" role="status"><span data-status></span><span data-diagnostics></span></div><div class="zoom-controls" role="group" aria-label="Canvas zoom"><button type="button" data-action="fit">Fit page</button><button type="button" data-action="actual">100%</button><span class="zoom-divider"></span><button type="button" data-action="out" aria-label="Zoom out">−</button><output class="zoom" aria-label="Zoom level">100%</output><button type="button" data-action="in" aria-label="Zoom in">+</button></div></div>`;
2900
+ <div class="status"><div class="status-message" role="status"><span data-status></span><span data-diagnostics></span></div><div class="notes-strip"><button type="button" data-chrome="notes" aria-controls="inspector-pane" aria-expanded="false">Notes<span class="notes-count" data-note-count></span></button><span>Files stay in your browser</span></div><slot name="workspace-footer"></slot><div class="zoom-controls" role="group" aria-label="Canvas zoom"><button type="button" data-action="fit">Fit page</button><button type="button" data-action="actual">100%</button><span class="zoom-divider"></span><button type="button" data-action="out" aria-label="Zoom out">−</button><output class="zoom" aria-label="Zoom level">100%</output><button type="button" data-action="in" aria-label="Zoom in">+</button></div></div>`;
2829
2901
  /** Presentation state stays local; page navigation uses the same controller as every binding. */
2830
2902
  var ViewerChrome = class {
2831
2903
  #root;
@@ -2836,7 +2908,9 @@ var ViewerChrome = class {
2836
2908
  #inspector;
2837
2909
  #notes;
2838
2910
  #responsive;
2911
+ #compact;
2839
2912
  #pagesManuallyToggled = false;
2913
+ #inspectorManuallyToggled = false;
2840
2914
  constructor(root, controller) {
2841
2915
  this.#root = root;
2842
2916
  this.#controller = controller;
@@ -2849,14 +2923,36 @@ var ViewerChrome = class {
2849
2923
  const view = this.#root.ownerDocument.defaultView;
2850
2924
  const events = new ((view?.AbortController) ?? AbortController)(), options = { signal: events.signal };
2851
2925
  this.#responsive = view?.matchMedia?.("(max-width: 980px)");
2926
+ const compact = view?.matchMedia?.("(max-width: 760px)");
2927
+ this.#compact = compact;
2928
+ const tools = this.#root.querySelector(".ribbon-tools");
2929
+ const toolLayout = () => {
2930
+ tools.open = !compact?.matches;
2931
+ };
2932
+ toolLayout();
2933
+ compact?.addEventListener("change", toolLayout, options);
2934
+ this.#root.addEventListener("keydown", (event) => {
2935
+ if (event.key === "Escape" && compact?.matches && tools.open) {
2936
+ event.preventDefault();
2937
+ event.stopPropagation();
2938
+ tools.open = false;
2939
+ tools.querySelector("summary").focus();
2940
+ }
2941
+ }, {
2942
+ ...options,
2943
+ capture: true
2944
+ });
2852
2945
  const responsive = () => {
2853
2946
  if (!this.#pagesManuallyToggled) this.#setPane("pages", !this.#responsive?.matches);
2947
+ if (!this.#inspectorManuallyToggled) this.#setPane("inspector", !compact?.matches);
2854
2948
  };
2855
2949
  responsive();
2856
2950
  this.#responsive?.addEventListener("change", responsive, options);
2951
+ compact?.addEventListener("change", responsive, options);
2857
2952
  this.#root.addEventListener("click", (event) => {
2858
2953
  const button = event.target?.closest?.("button");
2859
2954
  if (!button || button.disabled) return;
2955
+ if (compact?.matches && button.dataset.chrome) tools.open = false;
2860
2956
  const tab = button.dataset.tab;
2861
2957
  if (tab === "home" || tab === "view") this.#showTab(tab);
2862
2958
  if (button.dataset.pageIndex !== void 0) this.#controller.setPage(Number(button.dataset.pageIndex));
@@ -2867,7 +2963,10 @@ var ViewerChrome = class {
2867
2963
  this.#pagesManuallyToggled = true;
2868
2964
  this.#setPane("pages", this.#rail.hidden);
2869
2965
  }
2870
- if (action === "inspector") this.#setPane("inspector", this.#inspector.hidden);
2966
+ if (action === "inspector") {
2967
+ this.#inspectorManuallyToggled = true;
2968
+ this.#setPane("inspector", this.#inspector.hidden);
2969
+ }
2871
2970
  if (action === "notes" || action === "selection" || action === "edit" || action === "layers") this.#reveal(action);
2872
2971
  }, options);
2873
2972
  this.#root.addEventListener("keydown", (event) => {
@@ -2908,6 +3007,11 @@ var ViewerChrome = class {
2908
3007
  for (const panel of this.#root.querySelectorAll("[role=\"tabpanel\"]")) panel.hidden = panel.id !== `${tab}-panel`;
2909
3008
  }
2910
3009
  #setPane(pane, visible) {
3010
+ if (visible && this.#compact?.matches) {
3011
+ const other = pane === "pages" ? "inspector" : "pages";
3012
+ (other === "pages" ? this.#rail : this.#inspector).hidden = true;
3013
+ this.#root.querySelector(`[data-chrome="${other}"]`).setAttribute("aria-pressed", "false");
3014
+ }
2911
3015
  (pane === "pages" ? this.#rail : this.#inspector).hidden = !visible;
2912
3016
  this.#root.querySelector(`[data-chrome="${pane}"]`).setAttribute("aria-pressed", String(visible));
2913
3017
  this.#syncNotes();
@@ -2916,6 +3020,7 @@ var ViewerChrome = class {
2916
3020
  this.#root.querySelector(".notes-strip button").setAttribute("aria-expanded", String(!this.#inspector.hidden && this.#notes.open));
2917
3021
  }
2918
3022
  #reveal(kind) {
3023
+ this.#inspectorManuallyToggled = true;
2919
3024
  this.#setPane("inspector", true);
2920
3025
  const selector = kind === "notes" ? ".notes" : kind === "edit" ? ".edit-controls" : kind === "layers" ? ".layer-controls" : ".shape-inspector";
2921
3026
  const panel = this.#root.querySelector(selector);
@@ -2462,6 +2462,77 @@ summary::marker { color:var(--_vv-muted); font-size:10px; }
2462
2462
  .zoom-controls [data-action="in"],.zoom-controls [data-action="out"] { min-width:44px; }
2463
2463
  .layer-controls input { min-height:20px; }
2464
2464
  }
2465
+ /* Suite ribbon: tabs lead directly into command groups, with page navigation inside. */
2466
+ .ribbon-tabs { height:40px; }
2467
+ .ribbon-tabs button { min-height:39px; padding:8px 16px; }
2468
+ .ribbon-content { min-height:104px; padding:4px 4px; }
2469
+ .ribbon-primary { height:auto; min-height:92px; width:238px; flex:none; flex-wrap:wrap; justify-content:center; gap:2px; padding:10px 12px 18px; border-right:1px solid var(--_vv-border); position:relative; order:1; }
2470
+ .ribbon-primary .page-picker { flex-direction:column; align-items:start; gap:5px; }
2471
+ .ribbon-primary .page-picker select { width:160px; max-width:100%; }
2472
+ .ribbon-primary .spacer { display:none; }
2473
+ .ribbon-primary .local-label { position:absolute; bottom:4px; left:0; width:100%; text-align:center; }
2474
+ .search-group { order:2; width:320px; }
2475
+ .ribbon-hint { order:3; padding:10px 18px; }
2476
+ .ribbon-command { min-width:82px; }
2477
+ .pane-close { display:none; }
2478
+ @media(max-width:760px) {
2479
+ .ribbon-tabs { height:44px; }
2480
+ .ribbon-tabs button { min-height:44px; }
2481
+ .ribbon-content { min-height:54px; padding:4px 0; }
2482
+ .ribbon-primary { min-height:44px; height:44px; width:100%; padding:0 8px; border:0; flex-wrap:nowrap; gap:4px; order:0; }
2483
+ .ribbon-primary .page-picker { flex-direction:row; flex:1; align-items:center; gap:8px; }
2484
+ .ribbon-primary .page-picker select { flex:1; width:100%; min-width:0; }
2485
+ .search-group { flex:0 0 100%; width:100%; min-height:54px; }
2486
+ .search-feedback,.group-label { display:none; }
2487
+ .ribbon-content { overflow-x:auto; scroll-snap-type:x mandatory; }
2488
+ .ribbon-primary,.search-group { scroll-snap-align:start; }
2489
+ .workspace { display:flex; position:relative; overflow:hidden; }
2490
+ .viewport { flex:1; width:100%; height:100%; min-height:0; padding:16px 4px; }
2491
+ .inspector-pane { position:absolute; inset:0 0 0 auto; width:min(320px,100%); z-index:4; overflow:auto; border-left:1px solid var(--_vv-border); box-shadow:-8px 0 24px #0002; }
2492
+ .pane-close { display:block; width:44px; height:44px; padding:0; font-size:22px; background:transparent; border:0; }
2493
+ .inspector-kind { margin-left:auto; }
2494
+ .page-rail { position:absolute; inset:0 auto 0 0; width:180px; max-height:none; z-index:3; border-right:1px solid var(--_vv-border); background:var(--_vv-secondary); }
2495
+ .page-list { flex-direction:column; }
2496
+ .page-list li { flex:none; }
2497
+ .notes-strip { display:none; }
2498
+ .status { min-height:48px; padding:2px 8px; }
2499
+ .status-message { display:none; }
2500
+ }
2501
+ .toolbar { position:relative; }
2502
+ .ribbon-tools { display:flex; flex:none; order:0; }
2503
+ .tools-content { display:flex; align-items:stretch; }
2504
+ .ribbon-tools>summary { display:none; }
2505
+ .ribbon-command { font-size:12px; min-width:88px; }
2506
+ .ribbon-hint { font-size:12px; line-height:20px; flex:1; }
2507
+ .group-label { font-size:11px; line-height:14px; }
2508
+ .inspector-card,.edit-controls,.layer-controls { font-size:12px; line-height:18px; }
2509
+ .selection-hint,.document-card dl { font-size:12px; }
2510
+ .pane-heading { font-size:12px; }
2511
+ .inspector-pane .pane-heading { position:sticky; top:0; z-index:1; background:var(--_vv-secondary); flex:none; }
2512
+ .status .notes-strip { border:0; padding:0 8px; background:transparent; min-height:28px; }
2513
+ .status .notes-strip>span { display:none; }
2514
+ .status-message { flex:1; }
2515
+ @media(max-width:760px) {
2516
+ #home-panel { overflow:visible; min-height:54px; padding:4px; }
2517
+ .ribbon-primary { width:calc(100% - 92px); min-width:0; flex:1; padding:0 4px; }
2518
+ .ribbon-primary .page-picker { font-size:0; gap:0; }
2519
+ .ribbon-primary .page-picker select { font-size:12px; }
2520
+ .ribbon-tools { display:block; flex:0 0 84px; width:84px; order:1; }
2521
+ .ribbon-tools>summary { display:flex; min-height:44px; align-items:center; justify-content:center; gap:6px; padding:0 10px; border:1px solid var(--_vv-border); background:var(--_vv-surface); border-radius:4px; font-size:12px; cursor:pointer; list-style:none; }
2522
+ .ribbon-tools>summary::-webkit-details-marker { display:none; }
2523
+ .ribbon-tools .tools-content { display:flex; position:absolute; top:100%; left:4px; right:4px; z-index:6; flex-direction:column; padding:12px; gap:12px; border:1px solid var(--_vv-border); border-radius:4px; background:var(--_vv-surface); box-shadow:0 12px 28px #0003; max-height:60vh; overflow:auto; }
2524
+ .ribbon-tools:not([open])>.tools-content { display:none; }
2525
+ .ribbon-tools .ribbon-group { display:flex; width:100%; min-height:64px; border:0; padding:0; }
2526
+ .ribbon-tools .ribbon-actions { justify-content:space-between; }
2527
+ .ribbon-tools .ribbon-command { min-width:88px; font-size:12px; }
2528
+ .ribbon-tools .search-group { order:1; flex:auto; }
2529
+ .ribbon-tools .search-feedback { display:block; }
2530
+ .status { flex-wrap:nowrap; gap:4px; min-height:48px; }
2531
+ .zoom-controls { width:auto; flex:1; gap:0; }
2532
+ .zoom-divider { margin:0; }
2533
+ .status .notes-strip { display:none; }
2534
+ }
2535
+ @media(pointer:coarse) { .ribbon-tabs {height:45px;min-height:45px;} .ribbon-tabs button {min-height:44px;height:44px;} }
2465
2536
  @media(prefers-reduced-motion:reduce) { * { scroll-behavior:auto !important; } }
2466
2537
  `;
2467
2538
  //#endregion
@@ -2775,22 +2846,24 @@ function renderSearchControls(controls, state) {
2775
2846
  /** Only static application markup belongs here. All document labels are inserted as text. */
2776
2847
  var viewerChromeTemplate = `
2777
2848
  <div class="toolbar" role="group" aria-label="Diagram controls">
2778
- <div class="ribbon-primary">
2779
- <label class="page-picker">Page <select aria-label="Page"></select></label>
2780
- <div class="page-stepper"><button type="button" data-chrome="previous-page" aria-label="Previous page">‹</button><button type="button" data-chrome="next-page" aria-label="Next page">›</button></div>
2781
- <span class="spacer"></span><span class="local-label">Local workspace</span>
2782
- </div>
2849
+
2783
2850
  <div class="ribbon-tabs" role="tablist" aria-label="Ribbon">
2784
2851
  <button type="button" id="home-tab" role="tab" aria-selected="true" aria-controls="home-panel" data-tab="home">Home</button>
2785
2852
  <button type="button" id="view-tab" role="tab" aria-selected="false" aria-controls="view-panel" tabindex="-1" data-tab="view">View</button>
2786
2853
  </div>
2787
2854
  <div class="ribbon-content" id="home-panel" role="tabpanel" aria-labelledby="home-tab">
2788
- <div class="ribbon-group search-group">${searchTemplate}<span class="group-label">Find in drawing</span></div>
2855
+ <details class="ribbon-tools" open><summary>Tools <span aria-hidden="true">⌄</span></summary><div class="tools-content"><div class="ribbon-group search-group">${searchTemplate}<span class="group-label">Find in drawing</span></div>
2789
2856
  <div class="ribbon-group"><div class="ribbon-actions">
2790
2857
  <button class="ribbon-command" type="button" data-chrome="selection"><span class="command-icon" data-icon="selection" aria-hidden="true"></span><span>Shape details</span></button>
2791
2858
  <button class="ribbon-command" type="button" data-chrome="edit"><span class="command-icon" data-icon="edit" aria-hidden="true"></span><span>Edit text</span></button>
2792
2859
  <button class="ribbon-command" type="button" data-chrome="layers"><span class="command-icon" data-icon="layers" aria-hidden="true"></span><span>Layers</span></button>
2793
2860
  </div><span class="group-label">Inspect and edit</span></div>
2861
+ </div></details>
2862
+ <div class="ribbon-primary">
2863
+ <label class="page-picker">Page <select aria-label="Page"></select></label>
2864
+ <div class="page-stepper"><button type="button" data-chrome="previous-page" aria-label="Previous page">‹</button><button type="button" data-chrome="next-page" aria-label="Next page">›</button></div>
2865
+ <span class="spacer"></span><span class="local-label">Local workspace</span>
2866
+ </div>
2794
2867
  <p class="ribbon-hint">Select a shape to inspect its details.<br>Text editing is experimental.</p>
2795
2868
  </div>
2796
2869
  <div class="ribbon-content" id="view-panel" role="tabpanel" aria-labelledby="view-tab" hidden>
@@ -2806,7 +2879,7 @@ var viewerChromeTemplate = `
2806
2879
  <nav id="page-rail" class="page-rail" aria-label="Diagram pages"><div class="pane-heading"><span>Pages</span><span data-page-count>0</span></div><ol class="page-list"></ol><p class="page-empty">Open a drawing to see its pages.</p></nav>
2807
2880
  <div class="viewport" tabindex="0" role="region" aria-label="Diagram canvas"></div>
2808
2881
  <aside id="inspector-pane" class="inspector-pane" aria-label="Drawing inspector">
2809
- <div class="pane-heading"><span>Inspector</span><span class="inspector-kind">Drawing</span></div>
2882
+ <div class="pane-heading"><span>Inspector</span><span class="inspector-kind">Drawing</span><button class="pane-close" type="button" data-chrome="inspector" aria-label="Close inspector">×</button></div>
2810
2883
  <div class="inspector-body">
2811
2884
  <section class="inspector-card document-card" aria-label="Current page"><h2>Current page</h2><p class="current-page-name" data-page-name>No diagram open</p><dl><dt>Size</dt><dd data-page-size>No page</dd><dt>Shapes</dt><dd data-page-shapes>No shapes</dd></dl></section>
2812
2885
  <p class="selection-hint">Select a shape on the canvas to see its data and links.</p>
@@ -2816,8 +2889,7 @@ var viewerChromeTemplate = `
2816
2889
  </div>
2817
2890
  </aside>
2818
2891
  </div>
2819
- <div class="notes-strip"><button type="button" data-chrome="notes" aria-controls="inspector-pane" aria-expanded="false">Notes<span class="notes-count" data-note-count></span></button><span>Files stay in your browser</span></div>
2820
- <div class="status"><div class="status-message" role="status"><span data-status></span><span data-diagnostics></span></div><div class="zoom-controls" role="group" aria-label="Canvas zoom"><button type="button" data-action="fit">Fit page</button><button type="button" data-action="actual">100%</button><span class="zoom-divider"></span><button type="button" data-action="out" aria-label="Zoom out">−</button><output class="zoom" aria-label="Zoom level">100%</output><button type="button" data-action="in" aria-label="Zoom in">+</button></div></div>`;
2892
+ <div class="status"><div class="status-message" role="status"><span data-status></span><span data-diagnostics></span></div><div class="notes-strip"><button type="button" data-chrome="notes" aria-controls="inspector-pane" aria-expanded="false">Notes<span class="notes-count" data-note-count></span></button><span>Files stay in your browser</span></div><slot name="workspace-footer"></slot><div class="zoom-controls" role="group" aria-label="Canvas zoom"><button type="button" data-action="fit">Fit page</button><button type="button" data-action="actual">100%</button><span class="zoom-divider"></span><button type="button" data-action="out" aria-label="Zoom out">−</button><output class="zoom" aria-label="Zoom level">100%</output><button type="button" data-action="in" aria-label="Zoom in">+</button></div></div>`;
2821
2893
  /** Presentation state stays local; page navigation uses the same controller as every binding. */
2822
2894
  var ViewerChrome = class {
2823
2895
  #root;
@@ -2828,7 +2900,9 @@ var ViewerChrome = class {
2828
2900
  #inspector;
2829
2901
  #notes;
2830
2902
  #responsive;
2903
+ #compact;
2831
2904
  #pagesManuallyToggled = false;
2905
+ #inspectorManuallyToggled = false;
2832
2906
  constructor(root, controller) {
2833
2907
  this.#root = root;
2834
2908
  this.#controller = controller;
@@ -2841,14 +2915,36 @@ var ViewerChrome = class {
2841
2915
  const view = this.#root.ownerDocument.defaultView;
2842
2916
  const events = new ((view?.AbortController) ?? AbortController)(), options = { signal: events.signal };
2843
2917
  this.#responsive = view?.matchMedia?.("(max-width: 980px)");
2918
+ const compact = view?.matchMedia?.("(max-width: 760px)");
2919
+ this.#compact = compact;
2920
+ const tools = this.#root.querySelector(".ribbon-tools");
2921
+ const toolLayout = () => {
2922
+ tools.open = !compact?.matches;
2923
+ };
2924
+ toolLayout();
2925
+ compact?.addEventListener("change", toolLayout, options);
2926
+ this.#root.addEventListener("keydown", (event) => {
2927
+ if (event.key === "Escape" && compact?.matches && tools.open) {
2928
+ event.preventDefault();
2929
+ event.stopPropagation();
2930
+ tools.open = false;
2931
+ tools.querySelector("summary").focus();
2932
+ }
2933
+ }, {
2934
+ ...options,
2935
+ capture: true
2936
+ });
2844
2937
  const responsive = () => {
2845
2938
  if (!this.#pagesManuallyToggled) this.#setPane("pages", !this.#responsive?.matches);
2939
+ if (!this.#inspectorManuallyToggled) this.#setPane("inspector", !compact?.matches);
2846
2940
  };
2847
2941
  responsive();
2848
2942
  this.#responsive?.addEventListener("change", responsive, options);
2943
+ compact?.addEventListener("change", responsive, options);
2849
2944
  this.#root.addEventListener("click", (event) => {
2850
2945
  const button = event.target?.closest?.("button");
2851
2946
  if (!button || button.disabled) return;
2947
+ if (compact?.matches && button.dataset.chrome) tools.open = false;
2852
2948
  const tab = button.dataset.tab;
2853
2949
  if (tab === "home" || tab === "view") this.#showTab(tab);
2854
2950
  if (button.dataset.pageIndex !== void 0) this.#controller.setPage(Number(button.dataset.pageIndex));
@@ -2859,7 +2955,10 @@ var ViewerChrome = class {
2859
2955
  this.#pagesManuallyToggled = true;
2860
2956
  this.#setPane("pages", this.#rail.hidden);
2861
2957
  }
2862
- if (action === "inspector") this.#setPane("inspector", this.#inspector.hidden);
2958
+ if (action === "inspector") {
2959
+ this.#inspectorManuallyToggled = true;
2960
+ this.#setPane("inspector", this.#inspector.hidden);
2961
+ }
2863
2962
  if (action === "notes" || action === "selection" || action === "edit" || action === "layers") this.#reveal(action);
2864
2963
  }, options);
2865
2964
  this.#root.addEventListener("keydown", (event) => {
@@ -2900,6 +2999,11 @@ var ViewerChrome = class {
2900
2999
  for (const panel of this.#root.querySelectorAll("[role=\"tabpanel\"]")) panel.hidden = panel.id !== `${tab}-panel`;
2901
3000
  }
2902
3001
  #setPane(pane, visible) {
3002
+ if (visible && this.#compact?.matches) {
3003
+ const other = pane === "pages" ? "inspector" : "pages";
3004
+ (other === "pages" ? this.#rail : this.#inspector).hidden = true;
3005
+ this.#root.querySelector(`[data-chrome="${other}"]`).setAttribute("aria-pressed", "false");
3006
+ }
2903
3007
  (pane === "pages" ? this.#rail : this.#inspector).hidden = !visible;
2904
3008
  this.#root.querySelector(`[data-chrome="${pane}"]`).setAttribute("aria-pressed", String(visible));
2905
3009
  this.#syncNotes();
@@ -2908,6 +3012,7 @@ var ViewerChrome = class {
2908
3012
  this.#root.querySelector(".notes-strip button").setAttribute("aria-expanded", String(!this.#inspector.hidden && this.#notes.open));
2909
3013
  }
2910
3014
  #reveal(kind) {
3015
+ this.#inspectorManuallyToggled = true;
2911
3016
  this.#setPane("inspector", true);
2912
3017
  const selector = kind === "notes" ? ".notes" : kind === "edit" ? ".edit-controls" : kind === "layers" ? ".layer-controls" : ".shape-inspector";
2913
3018
  const panel = this.#root.querySelector(selector);
@@ -0,0 +1,92 @@
1
+ Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter)
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ http://scripts.sil.org/OFL
6
+
7
+ -----------------------------------------------------------
8
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
9
+ -----------------------------------------------------------
10
+
11
+ PREAMBLE
12
+ The goals of the Open Font License (OFL) are to stimulate worldwide
13
+ development of collaborative font projects, to support the font creation
14
+ efforts of academic and linguistic communities, and to provide a free and
15
+ open framework in which fonts may be shared and improved in partnership
16
+ with others.
17
+
18
+ The OFL allows the licensed fonts to be used, studied, modified and
19
+ redistributed freely as long as they are not sold by themselves. The
20
+ fonts, including any derivative works, can be bundled, embedded,
21
+ redistributed and/or sold with any software provided that any reserved
22
+ names are not used by derivative works. The fonts and derivatives,
23
+ however, cannot be released under any other type of license. The
24
+ requirement for fonts to remain under this license does not apply
25
+ to any document created using the fonts or their derivatives.
26
+
27
+ DEFINITIONS
28
+ "Font Software" refers to the set of files released by the Copyright
29
+ Holder(s) under this license and clearly marked as such. This may
30
+ include source files, build scripts and documentation.
31
+
32
+ "Reserved Font Name" refers to any names specified as such after the
33
+ copyright statement(s).
34
+
35
+ "Original Version" refers to the collection of Font Software components as
36
+ distributed by the Copyright Holder(s).
37
+
38
+ "Modified Version" refers to any derivative made by adding to, deleting,
39
+ or substituting -- in part or in whole -- any of the components of the
40
+ Original Version, by changing formats or by porting the Font Software to a
41
+ new environment.
42
+
43
+ "Author" refers to any designer, engineer, programmer, technical
44
+ writer or other person who contributed to the Font Software.
45
+
46
+ PERMISSION AND CONDITIONS
47
+ Permission is hereby granted, free of charge, to any person obtaining
48
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
49
+ redistribute, and sell modified and unmodified copies of the Font
50
+ Software, subject to the following conditions:
51
+
52
+ 1) Neither the Font Software nor any of its individual components,
53
+ in Original or Modified Versions, may be sold by itself.
54
+
55
+ 2) Original or Modified Versions of the Font Software may be bundled,
56
+ redistributed and/or sold with any software, provided that each copy
57
+ contains the above copyright notice and this license. These can be
58
+ included either as stand-alone text files, human-readable headers or
59
+ in the appropriate machine-readable metadata fields within text or
60
+ binary files as long as those fields can be easily viewed by the user.
61
+
62
+ 3) No Modified Version of the Font Software may use the Reserved Font
63
+ Name(s) unless explicit written permission is granted by the corresponding
64
+ Copyright Holder. This restriction only applies to the primary font name as
65
+ presented to the users.
66
+
67
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
68
+ Software shall not be used to promote, endorse or advertise any
69
+ Modified Version, except to acknowledge the contribution(s) of the
70
+ Copyright Holder(s) and the Author(s) or with their explicit written
71
+ permission.
72
+
73
+ 5) The Font Software, modified or unmodified, in part or in whole,
74
+ must be distributed entirely under this license, and must not be
75
+ distributed under any other license. The requirement for fonts to
76
+ remain under this license does not apply to any document created
77
+ using the Font Software.
78
+
79
+ TERMINATION
80
+ This license becomes null and void if any of the above conditions are
81
+ not met.
82
+
83
+ DISCLAIMER
84
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
86
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
87
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
88
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
89
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
90
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
91
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
92
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -1,2 +1,2 @@
1
1
  /** Inherited public tokens use local fallback aliases so host themes are never shadowed. */
2
- export declare const viewerStyles = "\n:host {\n --_vv-bg:var(--vv-background,#eceae8); --_vv-surface:var(--vv-surface,#fff);\n --_vv-secondary:var(--vv-secondary,#f3f2f1); --_vv-ink:var(--vv-ink,#1f1f1f);\n --_vv-muted:var(--vv-muted,#605e5c); --_vv-border:var(--vv-border,#e1dfdd);\n --_vv-accent:var(--vv-accent,#3955a3); --_vv-accent-soft:var(--vv-accent-soft,rgba(57,85,163,.10));\n display:flex; flex-direction:column; min-width:0; min-height:320px; height:100%; overflow:hidden;\n color:var(--_vv-ink); background:var(--_vv-bg); font:12px/1.5 \"Segoe UI\",Arial,sans-serif; contain:layout;\n}\n* { box-sizing:border-box; }\n[hidden] { display:none !important; }\nbutton,select,input,textarea { font:inherit; color:inherit; border:1px solid var(--_vv-border); background:var(--_vv-surface); border-radius:4px; min-height:28px; padding:3px 8px; }\nbutton { cursor:pointer; }\nbutton:hover:enabled { background:var(--_vv-accent-soft); border-color:var(--_vv-accent); }\nbutton:disabled { opacity:.4; cursor:default; }\nbutton:focus-visible,select:focus-visible,input:focus-visible,textarea:focus-visible,summary:focus-visible,[tabindex]:focus-visible { outline:2px solid var(--vv-focus,var(--_vv-accent)); outline-offset:2px; }\nbutton[aria-pressed=\"true\"] { color:var(--_vv-accent); background:var(--_vv-accent-soft); }\n.toolbar { flex:none; min-width:0; border-bottom:1px solid var(--_vv-border); background:var(--_vv-surface); }\n.ribbon-primary { height:32px; display:flex; align-items:center; gap:6px; padding:2px 8px; }\n.page-picker { display:flex; min-width:0; align-items:center; gap:8px; color:var(--_vv-muted); font-size:11px; }\n.page-picker select { width:190px; max-width:42vw; height:26px; min-height:26px; padding:2px 6px; font-size:11px; color:var(--_vv-ink); }\n.page-stepper { display:flex; align-items:center; gap:2px; }\n.page-stepper button { width:26px; height:26px; min-height:26px; padding:0; font-size:18px; line-height:22px; background:transparent; border-color:transparent; }\n.spacer { flex:1; }\n.local-label { color:var(--_vv-muted); font-size:10px; white-space:nowrap; }\n.ribbon-tabs { height:35px; display:flex; align-items:stretch; padding:0 4px; border-bottom:1px solid var(--_vv-border); }\n.ribbon-tabs button { position:relative; min-height:34px; padding:7px 14px; border:0; border-radius:0; background:transparent; color:var(--_vv-muted); font-size:12px; font-weight:500; }\n.ribbon-tabs button[aria-selected=\"true\"] { color:var(--_vv-accent); }\n.ribbon-tabs button[aria-selected=\"true\"]::after { content:\"\"; position:absolute; inset:auto 0 -1px; height:2.5px; background:var(--_vv-accent); }\n.ribbon-content { min-height:82px; display:flex; align-items:stretch; gap:0; padding:2px 4px; overflow-x:auto; }\n.ribbon-group { display:flex; flex-direction:column; justify-content:space-between; flex:none; gap:2px; padding:3px 10px 4px; border-right:1px solid var(--_vv-border); }\n.group-label { font-size:10px; line-height:12px; color:var(--_vv-muted); text-align:center; }\n.ribbon-actions { display:flex; align-items:stretch; gap:2px; flex:1; }\n.ribbon-command { display:flex; flex-direction:column; justify-content:center; align-items:center; gap:2px; min-width:70px; padding:2px 6px; border-color:transparent; background:transparent; font-size:11px; white-space:nowrap; }\n.command-icon { display:grid; place-items:center; width:26px; height:26px; color:var(--_vv-accent); }\n.command-icon::before { content:\"\"; width:24px; height:24px; background:currentColor; mask:var(--command-symbol) center / contain no-repeat; }\n[data-icon=\"selection\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22m5%203%2013%209-6%201-3%206z%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"edit\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M4%205h16M12%205v14M8%2019h8%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"layers\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22m3%208%209-5%209%205-9%205zM3%2012l9%205%209-5M3%2016l9%205%209-5%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"pages\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Crect%20x%3D%225%22%20y%3D%223%22%20width%3D%2214%22%20height%3D%2218%22%20rx%3D%221%22%2F%3E%3Cpath%20d%3D%22M8%208h8M8%2012h8M8%2016h5%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"inspector\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Crect%20x%3D%223%22%20y%3D%224%22%20width%3D%2218%22%20height%3D%2216%22%20rx%3D%221%22%2F%3E%3Cpath%20d%3D%22M14%204v16M17%208h1M17%2012h1M17%2016h1%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"notes\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M4%204h16v12H9l-5%204z%22%2F%3E%3Cpath%20d%3D%22M8%208h8M8%2012h5%22%2F%3E%3C%2Fsvg%3E\"); }\n.ribbon-command[data-chrome=\"edit\"] .command-icon { font-family:ui-serif,Georgia,serif; text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:3px; }\n.ribbon-hint { align-self:center; flex:none; margin:0; padding:0 16px; font-size:11px; line-height:18px; color:var(--_vv-muted); }\n.search-group { width:330px; }\n.search-controls { display:flex; align-items:center; gap:4px; flex-wrap:wrap; }\n.search-controls label { display:flex; align-items:center; min-width:0; gap:6px; flex:1; font-size:11px; }\n.search-controls input { width:100%; min-width:0; padding:3px 6px; font-size:11px; }\n.search-controls button { padding:3px 6px; font-size:10px; background:var(--_vv-secondary); }\n.search-controls [role=\"status\"] { display:block; width:100%; min-height:15px; font-size:10px; line-height:15px; color:var(--_vv-muted); overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }\n.workspace { position:relative; display:flex; flex:1; min-width:0; min-height:0; overflow:hidden; }\n.page-rail { flex:0 0 180px; width:180px; min-width:0; overflow:auto; border-right:1px solid var(--_vv-border); background:var(--_vv-secondary); }\n.pane-heading { height:37px; display:flex; align-items:center; justify-content:space-between; gap:8px; padding:8px 10px; border-bottom:1px solid var(--_vv-border); font-size:11px; font-weight:600; }\n.pane-heading [data-page-count],.inspector-kind { color:var(--_vv-muted); font-size:10px; font-weight:400; }\n.page-list { list-style:none; padding:8px 5px; margin:0; display:flex; flex-direction:column; gap:4px; }\n.page-link { display:flex; align-items:center; position:relative; width:100%; min-width:0; gap:4px; padding:4px 5px 4px 2px; border:0; border-radius:0; background:transparent; color:var(--_vv-muted); text-align:left; }\n.page-link[aria-current=\"page\"] { background:var(--_vv-accent-soft); }\n.page-link[aria-current=\"page\"]::before { content:\"\"; position:absolute; left:0; top:4px; bottom:4px; width:3px; border-radius:0 2px 2px 0; background:var(--_vv-accent); }\n.page-number { flex:0 0 20px; width:20px; padding-right:3px; font-size:10px; text-align:right; }\n.page-card { display:flex; flex-direction:column; align-items:flex-start; min-width:0; width:100%; min-height:98px; gap:3px; padding:10px; border:1px solid var(--_vv-border); border-radius:2px; background:var(--_vv-surface); }\n.page-link[aria-current=\"page\"] .page-card { border-color:var(--_vv-accent); }\n.page-link[aria-current=\"page\"] .page-number { color:var(--_vv-accent); font-weight:600; }\n.page-mark { color:var(--_vv-muted); font-size:20px; line-height:23px; }\n.page-name { color:var(--_vv-ink); font-size:11px; font-weight:500; line-height:16px; overflow-wrap:anywhere; }\n.page-meta { color:var(--_vv-muted); font-size:9px; line-height:14px; }\n.page-empty { margin:12px; color:var(--_vv-muted); font-size:11px; }\n.viewport { position:relative; display:flex; flex-direction:column; flex:1; overflow:auto; min-width:0; min-height:0; padding:16px 4px; background:var(--_vv-bg); }\n.paper { display:block; flex:none; background:white; box-shadow:var(--vv-shadow,0 2px 8px rgb(0 0 0 / 14%)); margin:auto; }\n.paper [data-shape-id] { cursor:pointer; }\n.paper [data-selected=\"true\"] > [data-geometry] { stroke:var(--_vv-accent) !important; stroke-width:.025 !important; }\n.inspector-pane { flex:0 0 288px; width:288px; min-width:0; overflow:auto; border-left:1px solid var(--_vv-border); background:var(--_vv-secondary); }\n.inspector-body { display:flex; flex-direction:column; gap:12px; padding:12px 10px; }\n.inspector-card,.edit-controls,.layer-controls { min-width:0; padding:8px; margin:0; border:1px solid var(--_vv-border); border-radius:4px; background:var(--_vv-surface); font-size:11px; line-height:17px; }\n.document-card h2 { margin:0 0 8px; font-size:10px; font-weight:500; letter-spacing:.5px; text-transform:uppercase; color:var(--_vv-muted); }\n.current-page-name { margin:0 0 8px; font-size:12px; font-weight:500; overflow-wrap:anywhere; }\n.document-card dl { display:grid; grid-template-columns:1fr auto; gap:4px 10px; margin:0; font-size:11px; }\n.document-card dt { color:var(--_vv-muted); }\n.document-card dd { margin:0; text-align:right; overflow-wrap:anywhere; }\n.selection-hint { margin:0; padding:0 2px; color:var(--_vv-muted); font-size:11px; }\nsummary { cursor:pointer; min-height:22px; line-height:22px; font-weight:500; }\nsummary::marker { color:var(--_vv-muted); font-size:10px; }\n.shape-inspector div { max-height:260px; overflow:auto; }\n.shape-inspector p { margin:6px 0; overflow-wrap:anywhere; }\n.shape-inspector dl { display:grid; grid-template-columns:minmax(60px,1fr) 1.5fr; gap:6px 10px; }\n.shape-inspector dt { font-weight:500; }\n.shape-inspector dd { margin:0; overflow-wrap:anywhere; white-space:pre-wrap; }\n.shape-inspector h3 { margin:12px 0 5px; font-size:11px; }\n.shape-inspector a { color:var(--_vv-accent); overflow-wrap:anywhere; }\n.edit-controls p,.layer-controls p { margin:6px 0; color:var(--_vv-muted); overflow-wrap:anywhere; }\n.edit-controls textarea { display:block; width:100%; resize:vertical; max-height:180px; margin-top:4px; background:var(--_vv-secondary); }\n.edit-controls label { display:block; margin-top:8px; }\n.edit-actions { display:flex; flex-wrap:wrap; gap:4px; margin-top:8px; }\n.edit-actions button { font-size:11px; padding:3px 7px; }\n.edit-actions [data-edit=\"apply\"]:enabled { background:var(--_vv-accent); border-color:var(--_vv-accent); color:var(--vv-accent-ink,#fff); }\n.edit-controls [data-geometry] { min-width:0; margin:8px 0 0; padding:6px; border:1px solid var(--_vv-border); }\n.edit-controls [data-geometry-field] { display:block; width:100%; min-width:0; margin-top:4px; }\n.edit-controls [data-geometry-error] { color:var(--vv-danger,#b42318); }\n.edit-controls [data-edit-error] { color:var(--vv-danger,#b42318); }\n.edit-controls [data-edit-diagnostics] { max-height:100px; overflow:auto; padding-left:16px; }\n.layer-controls [data-layer-list] { max-height:240px; overflow:auto; }\n.layer-controls fieldset { border:1px solid var(--_vv-border); margin:6px 0; padding:6px; min-width:0; }\n.layer-controls legend { max-width:100%; overflow-wrap:anywhere; }\n.layer-controls fieldset div { display:flex; align-items:center; gap:6px; margin:3px 0; }\n.layer-controls label { display:flex; align-items:center; gap:6px; overflow-wrap:anywhere; }\n.layer-controls input { flex-shrink:0; width:16px; height:16px; min-height:16px; padding:0; accent-color:var(--_vv-accent); }\n.notes ul { max-height:220px; overflow:auto; padding-left:17px; margin:6px 0 0; color:var(--_vv-muted); }\n.notes li { margin:5px 0; overflow-wrap:anywhere; }\n.notes-strip { flex:none; display:flex; align-items:center; justify-content:space-between; min-height:25.5px; padding:0 12px; border-top:1px solid var(--_vv-border); background:var(--_vv-bg); color:var(--_vv-muted); font-size:10px; }\n.notes-strip button { min-height:24.5px; padding:2px 0; border:0; background:transparent; color:var(--_vv-muted); font-size:11px; }\n.notes-strip button::before { content:\"\u25B8\"; margin-right:6px; }\n.notes-strip button[aria-expanded=\"true\"]::before { content:\"\u25BE\"; }\n.status { flex:none; display:flex; align-items:center; justify-content:space-between; gap:12px; min-width:0; min-height:29px; padding:0 8px 0 12px; border-top:1px solid var(--_vv-border); color:var(--_vv-muted); background:var(--_vv-surface); font-size:10px; }\n.status-message { display:flex; gap:16px; min-width:0; }\n.status-message span { overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }\n.zoom-controls { display:flex; flex:none; align-items:center; gap:3px; }\n.zoom-controls button { min-height:24px; height:24px; padding:1px 6px; border-color:transparent; background:transparent; font-size:10px; }\n.zoom-controls [data-action=\"in\"],.zoom-controls [data-action=\"out\"] { min-width:24px; padding:0; font-size:17px; line-height:20px; }\n.zoom-divider { width:1px; height:14px; background:var(--_vv-border); margin:0 3px; }\n.zoom { min-width:40px; font-size:10px; text-align:center; font-variant-numeric:tabular-nums; }\n.empty { max-width:360px; margin:60px auto; padding:16px; text-align:center; color:var(--_vv-muted); font-size:12px; }\n.empty strong { display:block; color:var(--_vv-ink); font-size:18px; font-weight:500; margin-bottom:8px; }\n@media(max-width:1100px) { .ribbon-hint { display:none; } [data-diagnostics] { display:none; } }\n@media(max-width:760px) {\n button,select,input,textarea { min-height:44px; }\n button { min-width:44px; }\n summary { min-height:44px; line-height:44px; }\n .ribbon-primary { height:52px; padding:4px 8px; }\n .page-picker { flex:1; }\n .page-picker select { width:100%; max-width:none; min-height:44px; height:44px; font-size:12px; }\n .page-stepper button { width:44px; min-height:44px; height:44px; }\n .local-label,.ribbon-primary>.spacer { display:none; }\n .ribbon-tabs { height:44px; }\n .ribbon-tabs button { min-height:44px; padding:8px 16px; }\n .ribbon-content { min-height:86px; }\n .ribbon-group { padding:4px 8px; }\n .search-group { width:100%; border-right:0; }\n .search-controls { gap:4px; }\n .search-controls label { font-size:12px; }\n .search-controls input { font-size:12px; }\n .search-controls button { min-width:44px; font-size:0; padding:3px; }\n .search-controls [data-action=\"search-previous\"]::before { content:\"\u2039\"; font-size:22px; }\n .search-controls [data-action=\"search-next\"]::before { content:\"\u203A\"; font-size:22px; }\n #home-panel>.ribbon-group:not(.search-group) { display:none; }\n .ribbon-command { min-width:90px; }\n .workspace { display:block; overflow:auto; }\n .page-rail { width:100%; max-height:190px; border-right:0; border-bottom:1px solid var(--_vv-border); }\n .page-list { flex-direction:row; overflow-x:auto; }\n .page-list li { flex:0 0 155px; }\n .page-card { min-height:86px; }\n .viewport { height:340px; min-height:260px; padding:16px 4px; }\n .inspector-pane { width:100%; overflow:visible; border-left:0; border-top:1px solid var(--_vv-border); }\n .inspector-body { gap:8px; padding:10px; }\n .inspector-card,.edit-controls,.layer-controls { font-size:12px; }\n .layer-controls label { min-height:44px; }\n .layer-controls input { min-width:20px; width:20px; height:20px; min-height:20px; }\n .notes-strip { min-height:44px; padding:0 10px; }\n .notes-strip button { min-height:44px; }\n .status { flex-wrap:wrap; gap:0; padding:4px 8px; }\n .status-message { width:100%; min-height:18px; }\n .zoom-controls { justify-content:flex-end; width:100%; }\n .zoom-controls button { min-height:44px; height:44px; min-width:44px; font-size:11px; }\n .zoom-controls [data-action=\"in\"],.zoom-controls [data-action=\"out\"] { min-width:44px; font-size:20px; }\n .zoom { font-size:11px; }\n}\n@media(pointer:coarse) {\n button,select,input,textarea { min-height:44px; }\n button { min-width:44px; }\n summary,.layer-controls label { min-height:44px; line-height:44px; }\n .ribbon-primary { min-height:52px; height:52px; }\n .page-picker select,.page-stepper button { min-height:44px; height:44px; }\n .page-stepper button { min-width:44px; }\n .ribbon-tabs { min-height:44px; height:44px; }\n .ribbon-tabs button { min-height:44px; }\n .ribbon-content { min-height:96px; }\n .search-group { width:380px; max-width:100%; }\n .zoom-controls button,.notes-strip button { min-height:44px; height:44px; }\n .zoom-controls [data-action=\"in\"],.zoom-controls [data-action=\"out\"] { min-width:44px; }\n .layer-controls input { min-height:20px; }\n}\n@media(prefers-reduced-motion:reduce) { * { scroll-behavior:auto !important; } }\n";
2
+ export declare const viewerStyles = "\n:host {\n --_vv-bg:var(--vv-background,#eceae8); --_vv-surface:var(--vv-surface,#fff);\n --_vv-secondary:var(--vv-secondary,#f3f2f1); --_vv-ink:var(--vv-ink,#1f1f1f);\n --_vv-muted:var(--vv-muted,#605e5c); --_vv-border:var(--vv-border,#e1dfdd);\n --_vv-accent:var(--vv-accent,#3955a3); --_vv-accent-soft:var(--vv-accent-soft,rgba(57,85,163,.10));\n display:flex; flex-direction:column; min-width:0; min-height:320px; height:100%; overflow:hidden;\n color:var(--_vv-ink); background:var(--_vv-bg); font:12px/1.5 \"Segoe UI\",Arial,sans-serif; contain:layout;\n}\n* { box-sizing:border-box; }\n[hidden] { display:none !important; }\nbutton,select,input,textarea { font:inherit; color:inherit; border:1px solid var(--_vv-border); background:var(--_vv-surface); border-radius:4px; min-height:28px; padding:3px 8px; }\nbutton { cursor:pointer; }\nbutton:hover:enabled { background:var(--_vv-accent-soft); border-color:var(--_vv-accent); }\nbutton:disabled { opacity:.4; cursor:default; }\nbutton:focus-visible,select:focus-visible,input:focus-visible,textarea:focus-visible,summary:focus-visible,[tabindex]:focus-visible { outline:2px solid var(--vv-focus,var(--_vv-accent)); outline-offset:2px; }\nbutton[aria-pressed=\"true\"] { color:var(--_vv-accent); background:var(--_vv-accent-soft); }\n.toolbar { flex:none; min-width:0; border-bottom:1px solid var(--_vv-border); background:var(--_vv-surface); }\n.ribbon-primary { height:32px; display:flex; align-items:center; gap:6px; padding:2px 8px; }\n.page-picker { display:flex; min-width:0; align-items:center; gap:8px; color:var(--_vv-muted); font-size:11px; }\n.page-picker select { width:190px; max-width:42vw; height:26px; min-height:26px; padding:2px 6px; font-size:11px; color:var(--_vv-ink); }\n.page-stepper { display:flex; align-items:center; gap:2px; }\n.page-stepper button { width:26px; height:26px; min-height:26px; padding:0; font-size:18px; line-height:22px; background:transparent; border-color:transparent; }\n.spacer { flex:1; }\n.local-label { color:var(--_vv-muted); font-size:10px; white-space:nowrap; }\n.ribbon-tabs { height:35px; display:flex; align-items:stretch; padding:0 4px; border-bottom:1px solid var(--_vv-border); }\n.ribbon-tabs button { position:relative; min-height:34px; padding:7px 14px; border:0; border-radius:0; background:transparent; color:var(--_vv-muted); font-size:12px; font-weight:500; }\n.ribbon-tabs button[aria-selected=\"true\"] { color:var(--_vv-accent); }\n.ribbon-tabs button[aria-selected=\"true\"]::after { content:\"\"; position:absolute; inset:auto 0 -1px; height:2.5px; background:var(--_vv-accent); }\n.ribbon-content { min-height:82px; display:flex; align-items:stretch; gap:0; padding:2px 4px; overflow-x:auto; }\n.ribbon-group { display:flex; flex-direction:column; justify-content:space-between; flex:none; gap:2px; padding:3px 10px 4px; border-right:1px solid var(--_vv-border); }\n.group-label { font-size:10px; line-height:12px; color:var(--_vv-muted); text-align:center; }\n.ribbon-actions { display:flex; align-items:stretch; gap:2px; flex:1; }\n.ribbon-command { display:flex; flex-direction:column; justify-content:center; align-items:center; gap:2px; min-width:70px; padding:2px 6px; border-color:transparent; background:transparent; font-size:11px; white-space:nowrap; }\n.command-icon { display:grid; place-items:center; width:26px; height:26px; color:var(--_vv-accent); }\n.command-icon::before { content:\"\"; width:24px; height:24px; background:currentColor; mask:var(--command-symbol) center / contain no-repeat; }\n[data-icon=\"selection\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22m5%203%2013%209-6%201-3%206z%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"edit\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M4%205h16M12%205v14M8%2019h8%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"layers\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22m3%208%209-5%209%205-9%205zM3%2012l9%205%209-5M3%2016l9%205%209-5%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"pages\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Crect%20x%3D%225%22%20y%3D%223%22%20width%3D%2214%22%20height%3D%2218%22%20rx%3D%221%22%2F%3E%3Cpath%20d%3D%22M8%208h8M8%2012h8M8%2016h5%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"inspector\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Crect%20x%3D%223%22%20y%3D%224%22%20width%3D%2218%22%20height%3D%2216%22%20rx%3D%221%22%2F%3E%3Cpath%20d%3D%22M14%204v16M17%208h1M17%2012h1M17%2016h1%22%2F%3E%3C%2Fsvg%3E\"); }\n[data-icon=\"notes\"] { --command-symbol:url(\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M4%204h16v12H9l-5%204z%22%2F%3E%3Cpath%20d%3D%22M8%208h8M8%2012h5%22%2F%3E%3C%2Fsvg%3E\"); }\n.ribbon-command[data-chrome=\"edit\"] .command-icon { font-family:ui-serif,Georgia,serif; text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:3px; }\n.ribbon-hint { align-self:center; flex:none; margin:0; padding:0 16px; font-size:11px; line-height:18px; color:var(--_vv-muted); }\n.search-group { width:330px; }\n.search-controls { display:flex; align-items:center; gap:4px; flex-wrap:wrap; }\n.search-controls label { display:flex; align-items:center; min-width:0; gap:6px; flex:1; font-size:11px; }\n.search-controls input { width:100%; min-width:0; padding:3px 6px; font-size:11px; }\n.search-controls button { padding:3px 6px; font-size:10px; background:var(--_vv-secondary); }\n.search-controls [role=\"status\"] { display:block; width:100%; min-height:15px; font-size:10px; line-height:15px; color:var(--_vv-muted); overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }\n.workspace { position:relative; display:flex; flex:1; min-width:0; min-height:0; overflow:hidden; }\n.page-rail { flex:0 0 180px; width:180px; min-width:0; overflow:auto; border-right:1px solid var(--_vv-border); background:var(--_vv-secondary); }\n.pane-heading { height:37px; display:flex; align-items:center; justify-content:space-between; gap:8px; padding:8px 10px; border-bottom:1px solid var(--_vv-border); font-size:11px; font-weight:600; }\n.pane-heading [data-page-count],.inspector-kind { color:var(--_vv-muted); font-size:10px; font-weight:400; }\n.page-list { list-style:none; padding:8px 5px; margin:0; display:flex; flex-direction:column; gap:4px; }\n.page-link { display:flex; align-items:center; position:relative; width:100%; min-width:0; gap:4px; padding:4px 5px 4px 2px; border:0; border-radius:0; background:transparent; color:var(--_vv-muted); text-align:left; }\n.page-link[aria-current=\"page\"] { background:var(--_vv-accent-soft); }\n.page-link[aria-current=\"page\"]::before { content:\"\"; position:absolute; left:0; top:4px; bottom:4px; width:3px; border-radius:0 2px 2px 0; background:var(--_vv-accent); }\n.page-number { flex:0 0 20px; width:20px; padding-right:3px; font-size:10px; text-align:right; }\n.page-card { display:flex; flex-direction:column; align-items:flex-start; min-width:0; width:100%; min-height:98px; gap:3px; padding:10px; border:1px solid var(--_vv-border); border-radius:2px; background:var(--_vv-surface); }\n.page-link[aria-current=\"page\"] .page-card { border-color:var(--_vv-accent); }\n.page-link[aria-current=\"page\"] .page-number { color:var(--_vv-accent); font-weight:600; }\n.page-mark { color:var(--_vv-muted); font-size:20px; line-height:23px; }\n.page-name { color:var(--_vv-ink); font-size:11px; font-weight:500; line-height:16px; overflow-wrap:anywhere; }\n.page-meta { color:var(--_vv-muted); font-size:9px; line-height:14px; }\n.page-empty { margin:12px; color:var(--_vv-muted); font-size:11px; }\n.viewport { position:relative; display:flex; flex-direction:column; flex:1; overflow:auto; min-width:0; min-height:0; padding:16px 4px; background:var(--_vv-bg); }\n.paper { display:block; flex:none; background:white; box-shadow:var(--vv-shadow,0 2px 8px rgb(0 0 0 / 14%)); margin:auto; }\n.paper [data-shape-id] { cursor:pointer; }\n.paper [data-selected=\"true\"] > [data-geometry] { stroke:var(--_vv-accent) !important; stroke-width:.025 !important; }\n.inspector-pane { flex:0 0 288px; width:288px; min-width:0; overflow:auto; border-left:1px solid var(--_vv-border); background:var(--_vv-secondary); }\n.inspector-body { display:flex; flex-direction:column; gap:12px; padding:12px 10px; }\n.inspector-card,.edit-controls,.layer-controls { min-width:0; padding:8px; margin:0; border:1px solid var(--_vv-border); border-radius:4px; background:var(--_vv-surface); font-size:11px; line-height:17px; }\n.document-card h2 { margin:0 0 8px; font-size:10px; font-weight:500; letter-spacing:.5px; text-transform:uppercase; color:var(--_vv-muted); }\n.current-page-name { margin:0 0 8px; font-size:12px; font-weight:500; overflow-wrap:anywhere; }\n.document-card dl { display:grid; grid-template-columns:1fr auto; gap:4px 10px; margin:0; font-size:11px; }\n.document-card dt { color:var(--_vv-muted); }\n.document-card dd { margin:0; text-align:right; overflow-wrap:anywhere; }\n.selection-hint { margin:0; padding:0 2px; color:var(--_vv-muted); font-size:11px; }\nsummary { cursor:pointer; min-height:22px; line-height:22px; font-weight:500; }\nsummary::marker { color:var(--_vv-muted); font-size:10px; }\n.shape-inspector div { max-height:260px; overflow:auto; }\n.shape-inspector p { margin:6px 0; overflow-wrap:anywhere; }\n.shape-inspector dl { display:grid; grid-template-columns:minmax(60px,1fr) 1.5fr; gap:6px 10px; }\n.shape-inspector dt { font-weight:500; }\n.shape-inspector dd { margin:0; overflow-wrap:anywhere; white-space:pre-wrap; }\n.shape-inspector h3 { margin:12px 0 5px; font-size:11px; }\n.shape-inspector a { color:var(--_vv-accent); overflow-wrap:anywhere; }\n.edit-controls p,.layer-controls p { margin:6px 0; color:var(--_vv-muted); overflow-wrap:anywhere; }\n.edit-controls textarea { display:block; width:100%; resize:vertical; max-height:180px; margin-top:4px; background:var(--_vv-secondary); }\n.edit-controls label { display:block; margin-top:8px; }\n.edit-actions { display:flex; flex-wrap:wrap; gap:4px; margin-top:8px; }\n.edit-actions button { font-size:11px; padding:3px 7px; }\n.edit-actions [data-edit=\"apply\"]:enabled { background:var(--_vv-accent); border-color:var(--_vv-accent); color:var(--vv-accent-ink,#fff); }\n.edit-controls [data-geometry] { min-width:0; margin:8px 0 0; padding:6px; border:1px solid var(--_vv-border); }\n.edit-controls [data-geometry-field] { display:block; width:100%; min-width:0; margin-top:4px; }\n.edit-controls [data-geometry-error] { color:var(--vv-danger,#b42318); }\n.edit-controls [data-edit-error] { color:var(--vv-danger,#b42318); }\n.edit-controls [data-edit-diagnostics] { max-height:100px; overflow:auto; padding-left:16px; }\n.layer-controls [data-layer-list] { max-height:240px; overflow:auto; }\n.layer-controls fieldset { border:1px solid var(--_vv-border); margin:6px 0; padding:6px; min-width:0; }\n.layer-controls legend { max-width:100%; overflow-wrap:anywhere; }\n.layer-controls fieldset div { display:flex; align-items:center; gap:6px; margin:3px 0; }\n.layer-controls label { display:flex; align-items:center; gap:6px; overflow-wrap:anywhere; }\n.layer-controls input { flex-shrink:0; width:16px; height:16px; min-height:16px; padding:0; accent-color:var(--_vv-accent); }\n.notes ul { max-height:220px; overflow:auto; padding-left:17px; margin:6px 0 0; color:var(--_vv-muted); }\n.notes li { margin:5px 0; overflow-wrap:anywhere; }\n.notes-strip { flex:none; display:flex; align-items:center; justify-content:space-between; min-height:25.5px; padding:0 12px; border-top:1px solid var(--_vv-border); background:var(--_vv-bg); color:var(--_vv-muted); font-size:10px; }\n.notes-strip button { min-height:24.5px; padding:2px 0; border:0; background:transparent; color:var(--_vv-muted); font-size:11px; }\n.notes-strip button::before { content:\"\u25B8\"; margin-right:6px; }\n.notes-strip button[aria-expanded=\"true\"]::before { content:\"\u25BE\"; }\n.status { flex:none; display:flex; align-items:center; justify-content:space-between; gap:12px; min-width:0; min-height:29px; padding:0 8px 0 12px; border-top:1px solid var(--_vv-border); color:var(--_vv-muted); background:var(--_vv-surface); font-size:10px; }\n.status-message { display:flex; gap:16px; min-width:0; }\n.status-message span { overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }\n.zoom-controls { display:flex; flex:none; align-items:center; gap:3px; }\n.zoom-controls button { min-height:24px; height:24px; padding:1px 6px; border-color:transparent; background:transparent; font-size:10px; }\n.zoom-controls [data-action=\"in\"],.zoom-controls [data-action=\"out\"] { min-width:24px; padding:0; font-size:17px; line-height:20px; }\n.zoom-divider { width:1px; height:14px; background:var(--_vv-border); margin:0 3px; }\n.zoom { min-width:40px; font-size:10px; text-align:center; font-variant-numeric:tabular-nums; }\n.empty { max-width:360px; margin:60px auto; padding:16px; text-align:center; color:var(--_vv-muted); font-size:12px; }\n.empty strong { display:block; color:var(--_vv-ink); font-size:18px; font-weight:500; margin-bottom:8px; }\n@media(max-width:1100px) { .ribbon-hint { display:none; } [data-diagnostics] { display:none; } }\n@media(max-width:760px) {\n button,select,input,textarea { min-height:44px; }\n button { min-width:44px; }\n summary { min-height:44px; line-height:44px; }\n .ribbon-primary { height:52px; padding:4px 8px; }\n .page-picker { flex:1; }\n .page-picker select { width:100%; max-width:none; min-height:44px; height:44px; font-size:12px; }\n .page-stepper button { width:44px; min-height:44px; height:44px; }\n .local-label,.ribbon-primary>.spacer { display:none; }\n .ribbon-tabs { height:44px; }\n .ribbon-tabs button { min-height:44px; padding:8px 16px; }\n .ribbon-content { min-height:86px; }\n .ribbon-group { padding:4px 8px; }\n .search-group { width:100%; border-right:0; }\n .search-controls { gap:4px; }\n .search-controls label { font-size:12px; }\n .search-controls input { font-size:12px; }\n .search-controls button { min-width:44px; font-size:0; padding:3px; }\n .search-controls [data-action=\"search-previous\"]::before { content:\"\u2039\"; font-size:22px; }\n .search-controls [data-action=\"search-next\"]::before { content:\"\u203A\"; font-size:22px; }\n #home-panel>.ribbon-group:not(.search-group) { display:none; }\n .ribbon-command { min-width:90px; }\n .workspace { display:block; overflow:auto; }\n .page-rail { width:100%; max-height:190px; border-right:0; border-bottom:1px solid var(--_vv-border); }\n .page-list { flex-direction:row; overflow-x:auto; }\n .page-list li { flex:0 0 155px; }\n .page-card { min-height:86px; }\n .viewport { height:340px; min-height:260px; padding:16px 4px; }\n .inspector-pane { width:100%; overflow:visible; border-left:0; border-top:1px solid var(--_vv-border); }\n .inspector-body { gap:8px; padding:10px; }\n .inspector-card,.edit-controls,.layer-controls { font-size:12px; }\n .layer-controls label { min-height:44px; }\n .layer-controls input { min-width:20px; width:20px; height:20px; min-height:20px; }\n .notes-strip { min-height:44px; padding:0 10px; }\n .notes-strip button { min-height:44px; }\n .status { flex-wrap:wrap; gap:0; padding:4px 8px; }\n .status-message { width:100%; min-height:18px; }\n .zoom-controls { justify-content:flex-end; width:100%; }\n .zoom-controls button { min-height:44px; height:44px; min-width:44px; font-size:11px; }\n .zoom-controls [data-action=\"in\"],.zoom-controls [data-action=\"out\"] { min-width:44px; font-size:20px; }\n .zoom { font-size:11px; }\n}\n@media(pointer:coarse) {\n button,select,input,textarea { min-height:44px; }\n button { min-width:44px; }\n summary,.layer-controls label { min-height:44px; line-height:44px; }\n .ribbon-primary { min-height:52px; height:52px; }\n .page-picker select,.page-stepper button { min-height:44px; height:44px; }\n .page-stepper button { min-width:44px; }\n .ribbon-tabs { min-height:44px; height:44px; }\n .ribbon-tabs button { min-height:44px; }\n .ribbon-content { min-height:96px; }\n .search-group { width:380px; max-width:100%; }\n .zoom-controls button,.notes-strip button { min-height:44px; height:44px; }\n .zoom-controls [data-action=\"in\"],.zoom-controls [data-action=\"out\"] { min-width:44px; }\n .layer-controls input { min-height:20px; }\n}\n/* Suite ribbon: tabs lead directly into command groups, with page navigation inside. */\n.ribbon-tabs { height:40px; }\n.ribbon-tabs button { min-height:39px; padding:8px 16px; }\n.ribbon-content { min-height:104px; padding:4px 4px; }\n.ribbon-primary { height:auto; min-height:92px; width:238px; flex:none; flex-wrap:wrap; justify-content:center; gap:2px; padding:10px 12px 18px; border-right:1px solid var(--_vv-border); position:relative; order:1; }\n.ribbon-primary .page-picker { flex-direction:column; align-items:start; gap:5px; }\n.ribbon-primary .page-picker select { width:160px; max-width:100%; }\n.ribbon-primary .spacer { display:none; }\n.ribbon-primary .local-label { position:absolute; bottom:4px; left:0; width:100%; text-align:center; }\n.search-group { order:2; width:320px; }\n.ribbon-hint { order:3; padding:10px 18px; }\n.ribbon-command { min-width:82px; }\n.pane-close { display:none; }\n@media(max-width:760px) {\n .ribbon-tabs { height:44px; }\n .ribbon-tabs button { min-height:44px; }\n .ribbon-content { min-height:54px; padding:4px 0; }\n .ribbon-primary { min-height:44px; height:44px; width:100%; padding:0 8px; border:0; flex-wrap:nowrap; gap:4px; order:0; }\n .ribbon-primary .page-picker { flex-direction:row; flex:1; align-items:center; gap:8px; }\n .ribbon-primary .page-picker select { flex:1; width:100%; min-width:0; }\n .search-group { flex:0 0 100%; width:100%; min-height:54px; }\n .search-feedback,.group-label { display:none; }\n .ribbon-content { overflow-x:auto; scroll-snap-type:x mandatory; }\n .ribbon-primary,.search-group { scroll-snap-align:start; }\n .workspace { display:flex; position:relative; overflow:hidden; }\n .viewport { flex:1; width:100%; height:100%; min-height:0; padding:16px 4px; }\n .inspector-pane { position:absolute; inset:0 0 0 auto; width:min(320px,100%); z-index:4; overflow:auto; border-left:1px solid var(--_vv-border); box-shadow:-8px 0 24px #0002; }\n .pane-close { display:block; width:44px; height:44px; padding:0; font-size:22px; background:transparent; border:0; }\n .inspector-kind { margin-left:auto; }\n .page-rail { position:absolute; inset:0 auto 0 0; width:180px; max-height:none; z-index:3; border-right:1px solid var(--_vv-border); background:var(--_vv-secondary); }\n .page-list { flex-direction:column; }\n .page-list li { flex:none; }\n .notes-strip { display:none; }\n .status { min-height:48px; padding:2px 8px; }\n .status-message { display:none; }\n}\n.toolbar { position:relative; }\n.ribbon-tools { display:flex; flex:none; order:0; }\n.tools-content { display:flex; align-items:stretch; }\n.ribbon-tools>summary { display:none; }\n.ribbon-command { font-size:12px; min-width:88px; }\n.ribbon-hint { font-size:12px; line-height:20px; flex:1; }\n.group-label { font-size:11px; line-height:14px; }\n.inspector-card,.edit-controls,.layer-controls { font-size:12px; line-height:18px; }\n.selection-hint,.document-card dl { font-size:12px; }\n.pane-heading { font-size:12px; }\n.inspector-pane .pane-heading { position:sticky; top:0; z-index:1; background:var(--_vv-secondary); flex:none; }\n.status .notes-strip { border:0; padding:0 8px; background:transparent; min-height:28px; }\n.status .notes-strip>span { display:none; }\n.status-message { flex:1; }\n@media(max-width:760px) {\n #home-panel { overflow:visible; min-height:54px; padding:4px; }\n .ribbon-primary { width:calc(100% - 92px); min-width:0; flex:1; padding:0 4px; }\n .ribbon-primary .page-picker { font-size:0; gap:0; }\n .ribbon-primary .page-picker select { font-size:12px; }\n .ribbon-tools { display:block; flex:0 0 84px; width:84px; order:1; }\n .ribbon-tools>summary { display:flex; min-height:44px; align-items:center; justify-content:center; gap:6px; padding:0 10px; border:1px solid var(--_vv-border); background:var(--_vv-surface); border-radius:4px; font-size:12px; cursor:pointer; list-style:none; }\n .ribbon-tools>summary::-webkit-details-marker { display:none; }\n .ribbon-tools .tools-content { display:flex; position:absolute; top:100%; left:4px; right:4px; z-index:6; flex-direction:column; padding:12px; gap:12px; border:1px solid var(--_vv-border); border-radius:4px; background:var(--_vv-surface); box-shadow:0 12px 28px #0003; max-height:60vh; overflow:auto; }\n .ribbon-tools:not([open])>.tools-content { display:none; }\n .ribbon-tools .ribbon-group { display:flex; width:100%; min-height:64px; border:0; padding:0; }\n .ribbon-tools .ribbon-actions { justify-content:space-between; }\n .ribbon-tools .ribbon-command { min-width:88px; font-size:12px; }\n .ribbon-tools .search-group { order:1; flex:auto; }\n .ribbon-tools .search-feedback { display:block; }\n .status { flex-wrap:nowrap; gap:4px; min-height:48px; }\n .zoom-controls { width:auto; flex:1; gap:0; }\n .zoom-divider { margin:0; }\n .status .notes-strip { display:none; }\n}\n@media(pointer:coarse) { .ribbon-tabs {height:45px;min-height:45px;} .ribbon-tabs button {min-height:44px;height:44px;} }\n@media(prefers-reduced-motion:reduce) { * { scroll-behavior:auto !important; } }\n";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "visio-solid-viewer",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Local-first Visio viewer for solid",
5
5
  "homepage": "https://christophervr.github.io/visio-viewer/",
6
6
  "license": "Apache-2.0",
@@ -30,7 +30,7 @@
30
30
  "dependencies": {
31
31
  "emf-converter": "4.8.9",
32
32
  "ooxml-core": "^0.10.0",
33
- "visio-core": "^0.1.0"
33
+ "visio-core": "^0.1.1"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "solid-js": "^1.9.0"