triiiceratops 0.10.5 → 0.11.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.
Files changed (40) hide show
  1. package/dist/{ArrowCounterClockwise-C2bPi1fL.js → ArrowCounterClockwise-CN8KGaI0.js} +1 -1
  2. package/dist/{X-Hy7z8RKI.js → X-i_EmjXwW.js} +376 -359
  3. package/dist/actions/tooltip.d.ts +10 -0
  4. package/dist/actions/tooltip.js +107 -0
  5. package/dist/{annotation_tool_point-CVRtOCN5.js → annotation_tool_point-BpZXtX5D.js} +1 -1
  6. package/dist/components/CanvasNavigation.svelte +57 -21
  7. package/dist/components/DemoHeader.svelte +81 -40
  8. package/dist/components/OSDViewer.svelte +2 -1
  9. package/dist/components/Toolbar.svelte +295 -0
  10. package/dist/components/Toolbar.svelte.d.ts +3 -0
  11. package/dist/components/TriiiceratopsViewer.svelte +7 -13
  12. package/dist/{image_filters_reset-BOxhPxhP.js → image_filters_reset-CyWg622b.js} +1 -1
  13. package/dist/paraglide/messages/_index.d.ts +6 -3
  14. package/dist/paraglide/messages/_index.js +6 -3
  15. package/dist/paraglide/messages/{settings_toggle_right_menu.d.ts → open_menu.d.ts} +1 -1
  16. package/dist/paraglide/messages/open_menu.js +33 -0
  17. package/dist/paraglide/messages/{settings_submenu_right_menu_items.d.ts → settings_submenu_toolbar.d.ts} +1 -1
  18. package/dist/paraglide/messages/{settings_toggle_right_menu.js → settings_submenu_toolbar.js} +9 -9
  19. package/dist/paraglide/messages/settings_toggle_show_toggle.d.ts +4 -0
  20. package/dist/paraglide/messages/{settings_submenu_right_menu_items.js → settings_toggle_show_toggle.js} +9 -9
  21. package/dist/paraglide/messages/settings_toggle_zoom_controls.d.ts +4 -0
  22. package/dist/paraglide/messages/settings_toggle_zoom_controls.js +34 -0
  23. package/dist/paraglide/messages/settings_toolbar_open.d.ts +4 -0
  24. package/dist/paraglide/messages/settings_toolbar_open.js +34 -0
  25. package/dist/paraglide/messages/{settings_toggle_left_menu.d.ts → settings_toolbar_position.d.ts} +1 -1
  26. package/dist/paraglide/messages/{settings_toggle_left_menu.js → settings_toolbar_position.js} +9 -9
  27. package/dist/plugins/annotation-editor.js +3 -3
  28. package/dist/plugins/image-manipulation.js +3 -3
  29. package/dist/state/viewer.svelte.d.ts +7 -2
  30. package/dist/state/viewer.svelte.js +26 -5
  31. package/dist/triiiceratops-bundle.js +2768 -2533
  32. package/dist/triiiceratops-element.iife.js +17 -17
  33. package/dist/triiiceratops.css +1 -1
  34. package/dist/types/config.d.ts +24 -18
  35. package/dist/utils/annotationAdapter.test.js +32 -29
  36. package/package.json +1 -1
  37. package/dist/components/FloatingMenu.svelte +0 -208
  38. package/dist/components/FloatingMenu.svelte.d.ts +0 -3
  39. package/dist/components/LeftFab.svelte +0 -81
  40. package/dist/components/LeftFab.svelte.d.ts +0 -3
@@ -0,0 +1,10 @@
1
+ export declare function tooltip(node: HTMLElement, params: {
2
+ content: string;
3
+ position?: 'top' | 'bottom' | 'left' | 'right';
4
+ }): {
5
+ update(newParams: {
6
+ content: string;
7
+ position?: "top" | "bottom" | "left" | "right";
8
+ }): void;
9
+ destroy(): void;
10
+ };
@@ -0,0 +1,107 @@
1
+ export function tooltip(node, params) {
2
+ let tip = null;
3
+ function create() {
4
+ if (tip)
5
+ return;
6
+ tip = document.createElement('div');
7
+ // Mimic DaisyUI tooltip style
8
+ // tooltip: --tooltip-color: #e5e7eb; --tooltip-text-color: #000000; ...
9
+ // We'll use standard utility classes that match the theme roughly
10
+ // bg-neutral text-neutral-content is usually closest to daisyui tooltip default
11
+ tip.className =
12
+ 'fixed z-[9999] px-2 py-1 text-xs rounded bg-neutral text-neutral-content shadow-sm pointer-events-none opacity-0 transition-opacity duration-150 whitespace-nowrap max-w-xs';
13
+ tip.textContent = params.content;
14
+ document.body.appendChild(tip);
15
+ updatePosition();
16
+ // Trigger reflow/paint for transition
17
+ requestAnimationFrame(() => {
18
+ if (tip)
19
+ tip.style.opacity = '1';
20
+ });
21
+ }
22
+ function destroy() {
23
+ if (tip) {
24
+ tip.style.opacity = '0';
25
+ // Allow transition to finish
26
+ setTimeout(() => {
27
+ if (tip && tip.parentNode) {
28
+ tip.remove();
29
+ }
30
+ }, 150);
31
+ tip = null;
32
+ }
33
+ }
34
+ function updatePosition() {
35
+ if (!tip)
36
+ return;
37
+ const rect = node.getBoundingClientRect();
38
+ const tipRect = tip.getBoundingClientRect();
39
+ const pos = params.position || 'top';
40
+ const gap = 6; // slightly smaller gap
41
+ let top = 0;
42
+ let left = 0;
43
+ switch (pos) {
44
+ case 'top':
45
+ top = rect.top - tipRect.height - gap;
46
+ left = rect.left + (rect.width - tipRect.width) / 2;
47
+ break;
48
+ case 'bottom':
49
+ top = rect.bottom + gap;
50
+ left = rect.left + (rect.width - tipRect.width) / 2;
51
+ break;
52
+ case 'left':
53
+ top = rect.top + (rect.height - tipRect.height) / 2;
54
+ left = rect.left - tipRect.width - gap;
55
+ break;
56
+ case 'right':
57
+ top = rect.top + (rect.height - tipRect.height) / 2;
58
+ left = rect.right + gap;
59
+ break;
60
+ }
61
+ // Keep within viewport logic (basic)
62
+ if (left < 0)
63
+ left = 0;
64
+ if (top < 0)
65
+ top = 0;
66
+ if (left + tipRect.width > window.innerWidth)
67
+ left = window.innerWidth - tipRect.width;
68
+ if (top + tipRect.height > window.innerHeight)
69
+ top = window.innerHeight - tipRect.height;
70
+ tip.style.top = `${top}px`;
71
+ tip.style.left = `${left}px`;
72
+ }
73
+ function onMouseEnter() {
74
+ create();
75
+ }
76
+ function onMouseLeave() {
77
+ destroy();
78
+ }
79
+ // Also update on scroll?
80
+ // For now, let's just destroy on scroll to avoid detached tooltips
81
+ function onScroll() {
82
+ if (tip)
83
+ destroy();
84
+ }
85
+ node.addEventListener('mouseenter', onMouseEnter);
86
+ node.addEventListener('mouseleave', onMouseLeave);
87
+ node.addEventListener('focus', onMouseEnter);
88
+ node.addEventListener('blur', onMouseLeave);
89
+ window.addEventListener('scroll', onScroll, true); // Capture to detect any scroll
90
+ return {
91
+ update(newParams) {
92
+ params = newParams;
93
+ if (tip) {
94
+ tip.textContent = params.content;
95
+ updatePosition();
96
+ }
97
+ },
98
+ destroy() {
99
+ destroy();
100
+ node.removeEventListener('mouseenter', onMouseEnter);
101
+ node.removeEventListener('mouseleave', onMouseLeave);
102
+ node.removeEventListener('focus', onMouseEnter);
103
+ node.removeEventListener('blur', onMouseLeave);
104
+ window.removeEventListener('scroll', onScroll, true);
105
+ },
106
+ };
107
+ }
@@ -1,4 +1,4 @@
1
- import { a as t } from "./X-Hy7z8RKI.js";
1
+ import { a as t } from "./X-i_EmjXwW.js";
2
2
  const a = (
3
3
  /** @type {(inputs: {}) => LocalizedString} */
4
4
  () => (
@@ -1,32 +1,68 @@
1
1
  <script>
2
2
  import CaretLeft from 'phosphor-svelte/lib/CaretLeft';
3
3
  import CaretRight from 'phosphor-svelte/lib/CaretRight';
4
+ import MagnifyingGlassPlus from 'phosphor-svelte/lib/MagnifyingGlassPlus';
5
+ import MagnifyingGlassMinus from 'phosphor-svelte/lib/MagnifyingGlassMinus';
4
6
  import { m } from '../state/i18n.svelte';
5
7
  let { viewerState } = $props();
8
+
9
+ let showNav = $derived(
10
+ viewerState.showCanvasNav && viewerState.canvases.length > 1,
11
+ );
6
12
  </script>
7
13
 
8
14
  <div
9
15
  class="select-none absolute left-1/2 -translate-x-1/2 bg-base-200/90 backdrop-blur rounded-full shadow-lg flex items-center gap-4 z-10 border border-base-300 transition-all duration-200 bottom-4"
10
16
  >
11
- <button
12
- class="btn btn-circle btn-sm btn-ghost"
13
- disabled={!viewerState.hasPrevious}
14
- onclick={() => viewerState.previousCanvas()}
15
- aria-label={m.previous_canvas()}
16
- >
17
- <CaretLeft size={20} weight="bold" />
18
- </button>
19
-
20
- <span class="text-sm font-mono tabular-nums text-nowrap">
21
- {viewerState.currentCanvasIndex + 1} / {viewerState.canvases.length}
22
- </span>
23
-
24
- <button
25
- class="btn btn-circle btn-sm btn-ghost"
26
- disabled={!viewerState.hasNext}
27
- onclick={() => viewerState.nextCanvas()}
28
- aria-label={m.next_canvas()}
29
- >
30
- <CaretRight size={20} weight="bold" />
31
- </button>
17
+ {#if showNav}
18
+ <button
19
+ class="btn btn-circle btn-sm btn-ghost"
20
+ disabled={!viewerState.hasPrevious}
21
+ onclick={() => viewerState.previousCanvas()}
22
+ aria-label={m.previous_canvas()}
23
+ >
24
+ <CaretLeft size={20} weight="bold" />
25
+ </button>
26
+ {/if}
27
+
28
+ {#if viewerState.showZoomControls}
29
+ {#if showNav}
30
+ <div class="h-4 w-px bg-base-content/20 mx-1"></div>
31
+ {/if}
32
+
33
+ <button
34
+ class="btn btn-circle btn-sm btn-ghost"
35
+ onclick={() => viewerState.zoomOut()}
36
+ aria-label="Zoom Out"
37
+ >
38
+ <MagnifyingGlassMinus size={20} weight="bold" />
39
+ </button>
40
+
41
+ <button
42
+ class="btn btn-circle btn-sm btn-ghost"
43
+ onclick={() => viewerState.zoomIn()}
44
+ aria-label="Zoom In"
45
+ >
46
+ <MagnifyingGlassPlus size={20} weight="bold" />
47
+ </button>
48
+
49
+ {#if showNav}
50
+ <div class="h-4 w-px bg-base-content/20 mx-1"></div>
51
+ {/if}
52
+ {/if}
53
+
54
+ {#if showNav}
55
+ <span class="text-sm font-mono tabular-nums text-nowrap">
56
+ {viewerState.currentCanvasIndex + 1} / {viewerState.canvases.length}
57
+ </span>
58
+
59
+ <button
60
+ class="btn btn-circle btn-sm btn-ghost"
61
+ disabled={!viewerState.hasNext}
62
+ onclick={() => viewerState.nextCanvas()}
63
+ aria-label={m.next_canvas()}
64
+ >
65
+ <CaretRight size={20} weight="bold" />
66
+ </button>
67
+ {/if}
32
68
  </div>
@@ -253,36 +253,24 @@
253
253
  <li>
254
254
  <label class="label cursor-pointer py-1">
255
255
  <span class="label-text"
256
- >{m.settings_toggle_left_menu()}</span
257
- >
258
- <input
259
- type="checkbox"
260
- class="toggle toggle-sm"
261
- bind:checked={config.showLeftMenu}
262
- />
263
- </label>
264
- </li>
265
- <li>
266
- <label class="label cursor-pointer py-1">
267
- <span class="label-text"
268
- >{m.settings_toggle_right_menu()}</span
256
+ >{m.settings_toggle_canvas_nav()}</span
269
257
  >
270
258
  <input
271
259
  type="checkbox"
272
260
  class="toggle toggle-sm"
273
- bind:checked={config.showRightMenu}
261
+ bind:checked={config.showCanvasNav}
274
262
  />
275
263
  </label>
276
264
  </li>
277
265
  <li>
278
266
  <label class="label cursor-pointer py-1">
279
267
  <span class="label-text"
280
- >{m.settings_toggle_canvas_nav()}</span
268
+ >{m.settings_toggle_zoom_controls()}</span
281
269
  >
282
270
  <input
283
271
  type="checkbox"
284
272
  class="toggle toggle-sm"
285
- bind:checked={config.showCanvasNav}
273
+ bind:checked={config.showZoomControls}
286
274
  />
287
275
  </label>
288
276
  </li>
@@ -295,10 +283,63 @@
295
283
 
296
284
  <li>
297
285
  <details>
298
- <summary
299
- >{m.settings_submenu_right_menu_items()}</summary
300
- >
286
+ <summary>{m.settings_submenu_toolbar()}</summary>
301
287
  <ul>
288
+ <li>
289
+ <label class="label cursor-pointer py-1">
290
+ <span class="label-text"
291
+ >{m.settings_toggle_show_toggle()}</span
292
+ >
293
+ <input
294
+ type="checkbox"
295
+ class="toggle toggle-sm"
296
+ checked={config.showToggle !== false}
297
+ onchange={(e) => {
298
+ config.showToggle =
299
+ e.currentTarget.checked;
300
+ }}
301
+ />
302
+ </label>
303
+ </li>
304
+ <li>
305
+ <label class="label cursor-pointer py-1">
306
+ <span class="label-text"
307
+ >{m.settings_toolbar_open()}</span
308
+ >
309
+ <input
310
+ type="checkbox"
311
+ class="toggle toggle-sm"
312
+ bind:checked={config.toolbarOpen}
313
+ />
314
+ </label>
315
+ </li>
316
+ <li>
317
+ <label class="label cursor-pointer py-1">
318
+ <span class="label-text"
319
+ >{m.settings_toolbar_position()}</span
320
+ >
321
+ <select
322
+ class="select select-bordered select-xs w-24"
323
+ value={config.toolbarPosition ?? 'left'}
324
+ onchange={(e) => {
325
+ config.toolbarPosition = (
326
+ e.currentTarget as HTMLSelectElement
327
+ ).value as 'left' | 'right' | 'top';
328
+ }}
329
+ >
330
+ <option value="left"
331
+ >{m.settings_position_left()}</option
332
+ >
333
+ <option value="right"
334
+ >{m.settings_position_right()}</option
335
+ >
336
+ <option value="top"
337
+ >{m.settings_position_top()}</option
338
+ >
339
+ </select>
340
+ </label>
341
+ </li>
342
+ <div class="divider my-1"></div>
302
343
  <li>
303
344
  <label class="label cursor-pointer py-1">
304
345
  <span class="label-text"
@@ -307,12 +348,12 @@
307
348
  <input
308
349
  type="checkbox"
309
350
  class="checkbox checkbox-xs"
310
- checked={config.rightMenu?.showSearch ??
351
+ checked={config.toolbar?.showSearch ??
311
352
  true}
312
353
  onchange={(e) => {
313
- if (!config.rightMenu)
314
- config.rightMenu = {};
315
- config.rightMenu.showSearch =
354
+ if (!config.toolbar)
355
+ config.toolbar = {};
356
+ config.toolbar.showSearch =
316
357
  e.currentTarget.checked;
317
358
  }}
318
359
  />
@@ -326,12 +367,12 @@
326
367
  <input
327
368
  type="checkbox"
328
369
  class="checkbox checkbox-xs"
329
- checked={config.rightMenu
330
- ?.showGallery ?? true}
370
+ checked={config.toolbar?.showGallery ??
371
+ true}
331
372
  onchange={(e) => {
332
- if (!config.rightMenu)
333
- config.rightMenu = {};
334
- config.rightMenu.showGallery =
373
+ if (!config.toolbar)
374
+ config.toolbar = {};
375
+ config.toolbar.showGallery =
335
376
  e.currentTarget.checked;
336
377
  }}
337
378
  />
@@ -345,12 +386,12 @@
345
386
  <input
346
387
  type="checkbox"
347
388
  class="checkbox checkbox-xs"
348
- checked={config.rightMenu
389
+ checked={config.toolbar
349
390
  ?.showAnnotations ?? true}
350
391
  onchange={(e) => {
351
- if (!config.rightMenu)
352
- config.rightMenu = {};
353
- config.rightMenu.showAnnotations =
392
+ if (!config.toolbar)
393
+ config.toolbar = {};
394
+ config.toolbar.showAnnotations =
354
395
  e.currentTarget.checked;
355
396
  }}
356
397
  />
@@ -364,12 +405,12 @@
364
405
  <input
365
406
  type="checkbox"
366
407
  class="checkbox checkbox-xs"
367
- checked={config.rightMenu
408
+ checked={config.toolbar
368
409
  ?.showFullscreen ?? true}
369
410
  onchange={(e) => {
370
- if (!config.rightMenu)
371
- config.rightMenu = {};
372
- config.rightMenu.showFullscreen =
411
+ if (!config.toolbar)
412
+ config.toolbar = {};
413
+ config.toolbar.showFullscreen =
373
414
  e.currentTarget.checked;
374
415
  }}
375
416
  />
@@ -383,12 +424,12 @@
383
424
  <input
384
425
  type="checkbox"
385
426
  class="checkbox checkbox-xs"
386
- checked={config.rightMenu?.showInfo ??
427
+ checked={config.toolbar?.showInfo ??
387
428
  true}
388
429
  onchange={(e) => {
389
- if (!config.rightMenu)
390
- config.rightMenu = {};
391
- config.rightMenu.showInfo =
430
+ if (!config.toolbar)
431
+ config.toolbar = {};
432
+ config.toolbar.showInfo =
392
433
  e.currentTarget.checked;
393
434
  }}
394
435
  />
@@ -179,9 +179,10 @@
179
179
  animationTime: 0.5,
180
180
  springStiffness: 7.0,
181
181
  zoomPerClick: 2.0,
182
- // Disable click-to-zoom to allow Annotorious click drawing
182
+ // Enable double-click to zoom, but keep clickToZoom disabled for Annotorious
183
183
  gestureSettingsMouse: {
184
184
  clickToZoom: false,
185
+ dblClickToZoom: true,
185
186
  },
186
187
  });
187
188