triiiceratops 0.9.12 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/dist/ArrowCounterClockwise-aFffCOKw.js +136 -0
  2. package/dist/X-DZEgXrJ8.js +877 -0
  3. package/dist/annotation_tool_point-CZKsj4Nk.js +290 -0
  4. package/dist/components/AnnotationOverlay.svelte +179 -86
  5. package/dist/components/DemoHeader.svelte +12 -0
  6. package/dist/components/LeftFab.svelte +21 -9
  7. package/dist/components/OSDViewer.svelte +24 -4
  8. package/dist/components/SearchPanel.svelte +4 -1
  9. package/dist/components/TriiiceratopsViewer.svelte +114 -47
  10. package/dist/components/TriiiceratopsViewer.svelte.d.ts +5 -5
  11. package/dist/components/TriiiceratopsViewerElement.svelte +2 -2
  12. package/dist/components/TriiiceratopsViewerElement.svelte.d.ts +2 -2
  13. package/dist/custom-element.d.ts +10 -0
  14. package/dist/custom-element.js +13 -0
  15. package/dist/image_filters_reset-BEIf-_QA.js +108 -0
  16. package/dist/index.d.ts +1 -2
  17. package/dist/index.js +0 -1
  18. package/dist/paraglide/messages/_index.d.ts +31 -0
  19. package/dist/paraglide/messages/_index.js +32 -1
  20. package/dist/paraglide/messages/annotation_editor_add_content.d.ts +4 -0
  21. package/dist/paraglide/messages/annotation_editor_add_content.js +34 -0
  22. package/dist/paraglide/messages/annotation_editor_cancel.d.ts +4 -0
  23. package/dist/paraglide/messages/annotation_editor_cancel.js +34 -0
  24. package/dist/paraglide/messages/annotation_editor_create_mode.d.ts +4 -0
  25. package/dist/paraglide/messages/annotation_editor_create_mode.js +34 -0
  26. package/dist/paraglide/messages/annotation_editor_delete.d.ts +4 -0
  27. package/dist/paraglide/messages/annotation_editor_delete.js +34 -0
  28. package/dist/paraglide/messages/annotation_editor_delete_message.d.ts +4 -0
  29. package/dist/paraglide/messages/annotation_editor_delete_message.js +34 -0
  30. package/dist/paraglide/messages/annotation_editor_delete_title.d.ts +4 -0
  31. package/dist/paraglide/messages/annotation_editor_delete_title.js +34 -0
  32. package/dist/paraglide/messages/annotation_editor_delete_tooltip.d.ts +4 -0
  33. package/dist/paraglide/messages/annotation_editor_delete_tooltip.js +34 -0
  34. package/dist/paraglide/messages/annotation_editor_edit_mode.d.ts +4 -0
  35. package/dist/paraglide/messages/annotation_editor_edit_mode.js +34 -0
  36. package/dist/paraglide/messages/annotation_editor_edit_section.d.ts +4 -0
  37. package/dist/paraglide/messages/annotation_editor_edit_section.js +34 -0
  38. package/dist/paraglide/messages/annotation_editor_instruction_create.d.ts +4 -0
  39. package/dist/paraglide/messages/annotation_editor_instruction_create.js +34 -0
  40. package/dist/paraglide/messages/annotation_editor_instruction_edit.d.ts +4 -0
  41. package/dist/paraglide/messages/annotation_editor_instruction_edit.js +34 -0
  42. package/dist/paraglide/messages/annotation_editor_link_placeholder.d.ts +4 -0
  43. package/dist/paraglide/messages/annotation_editor_link_placeholder.js +34 -0
  44. package/dist/paraglide/messages/annotation_editor_redo.d.ts +4 -0
  45. package/dist/paraglide/messages/annotation_editor_redo.js +34 -0
  46. package/dist/paraglide/messages/annotation_editor_save.d.ts +4 -0
  47. package/dist/paraglide/messages/annotation_editor_save.js +34 -0
  48. package/dist/paraglide/messages/annotation_editor_tag_placeholder.d.ts +4 -0
  49. package/dist/paraglide/messages/annotation_editor_tag_placeholder.js +34 -0
  50. package/dist/paraglide/messages/annotation_editor_text_placeholder.d.ts +4 -0
  51. package/dist/paraglide/messages/annotation_editor_text_placeholder.js +34 -0
  52. package/dist/paraglide/messages/annotation_editor_title.d.ts +4 -0
  53. package/dist/paraglide/messages/annotation_editor_title.js +34 -0
  54. package/dist/paraglide/messages/annotation_editor_tool_label.d.ts +4 -0
  55. package/dist/paraglide/messages/annotation_editor_tool_label.js +34 -0
  56. package/dist/paraglide/messages/annotation_editor_undo.d.ts +4 -0
  57. package/dist/paraglide/messages/annotation_editor_undo.js +34 -0
  58. package/dist/paraglide/messages/annotation_tool_point.d.ts +4 -0
  59. package/dist/paraglide/messages/annotation_tool_point.js +34 -0
  60. package/dist/paraglide/messages/annotation_tool_polygon.d.ts +4 -0
  61. package/dist/paraglide/messages/annotation_tool_polygon.js +34 -0
  62. package/dist/paraglide/messages/annotation_tool_rectangle.d.ts +4 -0
  63. package/dist/paraglide/messages/annotation_tool_rectangle.js +34 -0
  64. package/dist/paraglide/messages/image_adjustments_title.d.ts +4 -0
  65. package/dist/paraglide/messages/image_adjustments_title.js +34 -0
  66. package/dist/paraglide/messages/image_filters_brightness.d.ts +4 -0
  67. package/dist/paraglide/messages/image_filters_brightness.js +34 -0
  68. package/dist/paraglide/messages/image_filters_contrast.d.ts +4 -0
  69. package/dist/paraglide/messages/image_filters_contrast.js +34 -0
  70. package/dist/paraglide/messages/image_filters_effects.d.ts +4 -0
  71. package/dist/paraglide/messages/image_filters_effects.js +34 -0
  72. package/dist/paraglide/messages/image_filters_grayscale.d.ts +4 -0
  73. package/dist/paraglide/messages/image_filters_grayscale.js +34 -0
  74. package/dist/paraglide/messages/image_filters_invert.d.ts +4 -0
  75. package/dist/paraglide/messages/image_filters_invert.js +34 -0
  76. package/dist/paraglide/messages/image_filters_reset.d.ts +4 -0
  77. package/dist/paraglide/messages/image_filters_reset.js +34 -0
  78. package/dist/paraglide/messages/image_filters_saturation.d.ts +4 -0
  79. package/dist/paraglide/messages/image_filters_saturation.js +34 -0
  80. package/dist/paraglide/messages/plugins_tooltip.js +1 -1
  81. package/dist/paraglide/messages/settings_transparent_background.d.ts +4 -0
  82. package/dist/paraglide/messages/settings_transparent_background.js +34 -0
  83. package/dist/plugins/annotation-editor/AnnotationEditorController.svelte +166 -0
  84. package/dist/plugins/annotation-editor/AnnotationEditorController.svelte.d.ts +9 -0
  85. package/dist/plugins/annotation-editor/AnnotationEditorPanel.svelte +315 -0
  86. package/dist/plugins/annotation-editor/AnnotationEditorPanel.svelte.d.ts +24 -0
  87. package/dist/plugins/annotation-editor/AnnotationManager.svelte.d.ts +39 -0
  88. package/dist/plugins/annotation-editor/AnnotationManager.svelte.js +433 -0
  89. package/dist/plugins/annotation-editor/adapters/LocalStorageAdapter.d.ts +20 -0
  90. package/dist/plugins/annotation-editor/adapters/LocalStorageAdapter.js +67 -0
  91. package/dist/plugins/annotation-editor/adapters/index.d.ts +2 -0
  92. package/dist/plugins/annotation-editor/adapters/index.js +1 -0
  93. package/dist/plugins/annotation-editor/adapters/types.d.ts +23 -0
  94. package/dist/plugins/annotation-editor/adapters/types.js +1 -0
  95. package/dist/plugins/annotation-editor/iife-entry.d.ts +15 -0
  96. package/dist/plugins/annotation-editor/iife-entry.js +35 -0
  97. package/dist/plugins/annotation-editor/index.d.ts +41 -0
  98. package/dist/plugins/annotation-editor/index.js +57 -0
  99. package/dist/plugins/annotation-editor/loader.svelte.d.ts +7 -0
  100. package/dist/plugins/annotation-editor/loader.svelte.js +32 -0
  101. package/dist/plugins/annotation-editor/types.d.ts +41 -0
  102. package/dist/plugins/annotation-editor/types.js +13 -0
  103. package/dist/plugins/annotation-editor.js +32824 -0
  104. package/dist/plugins/image-manipulation/ImageManipulationController.svelte +54 -0
  105. package/dist/plugins/image-manipulation/ImageManipulationController.svelte.d.ts +6 -0
  106. package/dist/plugins/image-manipulation/ImageManipulationPanel.svelte +19 -9
  107. package/dist/plugins/image-manipulation/ImageManipulationPanel.svelte.d.ts +1 -0
  108. package/dist/plugins/image-manipulation/iife-entry.d.ts +13 -0
  109. package/dist/plugins/image-manipulation/iife-entry.js +17 -0
  110. package/dist/plugins/image-manipulation/index.d.ts +15 -1
  111. package/dist/plugins/image-manipulation/index.js +21 -1
  112. package/dist/plugins/image-manipulation.js +265 -0
  113. package/dist/state/i18n.svelte.js +4 -2
  114. package/dist/state/manifests.svelte.d.ts +5 -0
  115. package/dist/state/manifests.svelte.js +42 -13
  116. package/dist/state/viewer.svelte.d.ts +14 -13
  117. package/dist/state/viewer.svelte.js +63 -74
  118. package/dist/triiiceratops-bundle.js +3208 -3124
  119. package/dist/triiiceratops-element.iife.js +99 -0
  120. package/dist/triiiceratops.css +1 -1
  121. package/dist/types/config.d.ts +5 -0
  122. package/dist/types/plugin.d.ts +21 -62
  123. package/dist/types/plugin.js +1 -23
  124. package/dist/utils/annotationAdapter.d.ts +12 -1
  125. package/dist/utils/annotationAdapter.js +98 -39
  126. package/package.json +13 -6
  127. package/dist/chunks/TriiiceratopsViewer-DpZQA17w.js +0 -10435
  128. package/dist/chunks/openseadragon-5MHeYuQz.js +0 -12427
  129. package/dist/components/TriiiceratopsViewerElementImage.svelte +0 -143
  130. package/dist/components/TriiiceratopsViewerElementImage.svelte.d.ts +0 -27
  131. package/dist/custom-element-image.d.ts +0 -1
  132. package/dist/custom-element-image.js +0 -2
  133. package/dist/plugins/image-manipulation/ImageManipulationPlugin.svelte.d.ts +0 -19
  134. package/dist/plugins/image-manipulation/ImageManipulationPlugin.svelte.js +0 -87
  135. package/dist/triiiceratops-element-image.js +0 -555
  136. package/dist/triiiceratops-element.js +0 -114
@@ -3,18 +3,25 @@
3
3
  import PuzzlePiece from 'phosphor-svelte/lib/PuzzlePiece';
4
4
  import X from 'phosphor-svelte/lib/X';
5
5
  import { VIEWER_STATE_KEY, type ViewerState } from '../state/viewer.svelte';
6
- import { m } from '../state/i18n.svelte';
6
+ import { m, language } from '../state/i18n.svelte';
7
7
 
8
8
  const viewerState = getContext<ViewerState>(VIEWER_STATE_KEY);
9
9
 
10
- let sortedPluginButtons = $derived(
11
- [...viewerState.pluginMenuButtons].sort(
10
+ let sortedPluginButtons = $derived.by(() => {
11
+ // Read language to trigger re-evaluation
12
+ language.current;
13
+ return [...viewerState.pluginMenuButtons].sort(
12
14
  (a, b) => (a.order ?? 100) - (b.order ?? 100),
13
- ),
14
- );
15
+ );
16
+ });
15
17
 
16
18
  let isOpen = $state(false);
17
19
 
20
+ let pluginsTooltip = $derived.by(() => {
21
+ language.current;
22
+ return m.plugins_tooltip();
23
+ });
24
+
18
25
  function toggleOpen() {
19
26
  isOpen = !isOpen;
20
27
  }
@@ -32,7 +39,13 @@
32
39
  >
33
40
  {#each sortedPluginButtons as button (button.id)}
34
41
  {@const Icon = button.icon}
35
- <div class="tooltip tooltip-right" data-tip={button.tooltip}>
42
+ {@const tooltip =
43
+ // @ts-ignore - access message dynamically
44
+ typeof m[button.tooltip] === 'function'
45
+ ? // @ts-ignore
46
+ m[button.tooltip]()
47
+ : button.tooltip}
48
+ <div class="tooltip tooltip-right" data-tip={tooltip}>
36
49
  <button
37
50
  aria-label={button.tooltip}
38
51
  class="btn btn-lg btn-circle shadow-lg {button.isActive?.()
@@ -49,13 +62,12 @@
49
62
  {/each}
50
63
  </div>
51
64
 
52
- <!-- Main Toggle Button -->
53
- <div class="tooltip tooltip-right" data-tip={m.plugins_tooltip()}>
65
+ <div class="tooltip tooltip-right" data-tip={pluginsTooltip}>
54
66
  <button
55
67
  class="btn btn-lg btn-secondary btn-circle shadow-xl transition-transform duration-300 {isOpen
56
68
  ? 'rotate-90'
57
69
  : ''}"
58
- aria-label={m.plugins_tooltip()}
70
+ aria-label={pluginsTooltip}
59
71
  onclick={toggleOpen}
60
72
  >
61
73
  {#if isOpen}
@@ -11,7 +11,7 @@
11
11
  $props();
12
12
 
13
13
  let container: HTMLElement | undefined = $state();
14
- let viewer: any | undefined = $state();
14
+ let viewer: any | undefined = $state.raw();
15
15
  let OSD: any | undefined = $state();
16
16
 
17
17
  // Track OSD state changes for reactivity
@@ -61,6 +61,12 @@
61
61
 
62
62
  const results: any[] = [];
63
63
 
64
+ // Check if annotation editor is open to prevent double rendering
65
+ const editorPanel = viewerState.pluginPanels.find(
66
+ (p) => p.id === 'annotation-editor:panel',
67
+ );
68
+ const isEditorOpen = editorPanel ? editorPanel.isVisible() : false;
69
+
64
70
  for (const anno of parsedAnnotations) {
65
71
  // Filter based on visibility
66
72
  if (anno.isSearchHit) {
@@ -96,7 +102,9 @@
96
102
  height: pixelRect.height,
97
103
  },
98
104
  isSearchHit: anno.isSearchHit,
99
- tooltip: anno.body.value,
105
+ tooltip: anno.body.map((b) => b.value).join(' '),
106
+ // Disable pointer events if editor is open so blue annotations can be selected
107
+ pointerEvents: isEditorOpen ? 'none' : 'auto',
100
108
  });
101
109
  } else if (anno.geometry.type === 'POLYGON') {
102
110
  // Convert each point from image to viewport to pixel
@@ -140,7 +148,8 @@
140
148
  },
141
149
  points: relativePoints,
142
150
  isSearchHit: anno.isSearchHit,
143
- tooltip: anno.body.value,
151
+ tooltip: anno.body.map((b) => b.value).join(' '),
152
+ pointerEvents: isEditorOpen ? 'none' : 'auto',
144
153
  });
145
154
  }
146
155
  }
@@ -170,6 +179,10 @@
170
179
  animationTime: 0.5,
171
180
  springStiffness: 7.0,
172
181
  zoomPerClick: 2.0,
182
+ // Disable click-to-zoom to allow Annotorious click drawing
183
+ gestureSettingsMouse: {
184
+ clickToZoom: false,
185
+ },
173
186
  });
174
187
 
175
188
  // Notify plugins that OSD is ready
@@ -218,13 +231,17 @@
218
231
  <div class="w-full h-full relative">
219
232
  <div
220
233
  bind:this={container}
221
- class="w-full h-full osd-background bg-base-100"
234
+ class="w-full h-full osd-background {viewerState.config
235
+ .transparentBackground
236
+ ? ''
237
+ : 'bg-base-100'}"
222
238
  ></div>
223
239
 
224
240
  <!-- Render annotations -->
225
241
  {#each renderedAnnotations as anno (anno.id)}
226
242
  {#if anno.type === 'RECTANGLE'}
227
243
  <div
244
+ id="annotation-visual-{anno.id}"
228
245
  class="absolute border-2 transition-colors cursor-pointer pointer-events-auto {anno.isSearchHit
229
246
  ? 'border-yellow-400 bg-yellow-400/40 hover:bg-yellow-400/60'
230
247
  : 'border-red-500 bg-red-500/20 hover:bg-red-500/40'}"
@@ -233,6 +250,7 @@
233
250
  top: {anno.rect.y}px;
234
251
  width: {anno.rect.width}px;
235
252
  height: {anno.rect.height}px;
253
+ pointer-events: {anno.pointerEvents};
236
254
  "
237
255
  title={anno.tooltip}
238
256
  ></div>
@@ -244,10 +262,12 @@
244
262
  top: {anno.bounds.y}px;
245
263
  width: {anno.bounds.width}px;
246
264
  height: {anno.bounds.height}px;
265
+ pointer-events: {anno.pointerEvents};
247
266
  "
248
267
  >
249
268
  <title>{anno.tooltip}</title>
250
269
  <polygon
270
+ id="annotation-visual-{anno.id}"
251
271
  points={anno.points.map((p: any) => p.join(',')).join(' ')}
252
272
  class="cursor-pointer transition-colors {anno.isSearchHit
253
273
  ? 'fill-yellow-400/40 stroke-yellow-400 hover:fill-yellow-400/60'
@@ -45,7 +45,10 @@
45
45
  <!-- Drawer / Panel -->
46
46
  {#if viewerState.showSearchPanel}
47
47
  <div
48
- class="h-full bg-base-200 shadow-2xl z-100 flex flex-col border-l border-base-300 transition-[width] duration-200"
48
+ class="h-full bg-base-200 shadow-2xl z-100 flex flex-col transition-[width] duration-200 {viewerState
49
+ .config.transparentBackground
50
+ ? ''
51
+ : 'border-l border-base-300'}"
49
52
  style="width: {width}"
50
53
  role="dialog"
51
54
  aria-label={m.search_panel_title()}
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
- import { setContext, onDestroy } from 'svelte';
2
+ import { setContext, onDestroy, untrack } from 'svelte';
3
3
  import { ViewerState, VIEWER_STATE_KEY } from '../state/viewer.svelte';
4
- import type { TriiiceratopsPlugin } from '../types/plugin';
4
+ import type { PluginDef } from '../types/plugin';
5
5
  import type { DaisyUITheme, ThemeConfig } from '../theme/types';
6
6
  import type { ViewerConfig } from '../types/config';
7
7
  import { applyTheme } from '../theme/themeManager';
@@ -13,23 +13,15 @@
13
13
  import LeftFab from './LeftFab.svelte';
14
14
  import MetadataDialog from './MetadataDialog.svelte';
15
15
  import SearchPanel from './SearchPanel.svelte';
16
- import { m } from '../state/i18n.svelte';
16
+ import { m, language } from '../state/i18n.svelte';
17
17
 
18
18
  // SSR-safe browser detection for library consumers
19
19
  const browser = typeof window !== 'undefined';
20
20
 
21
- let {
22
- manifestId,
23
- canvasId,
24
- plugins = [],
25
- theme,
26
- themeConfig,
27
- config = {},
28
- viewerState = $bindable(),
29
- }: {
21
+ interface Props {
30
22
  manifestId?: string;
31
23
  canvasId?: string;
32
- plugins?: TriiiceratopsPlugin[];
24
+ plugins?: PluginDef[];
33
25
  /** Built-in DaisyUI theme name. Defaults to 'light' or 'dark' based on prefers-color-scheme. */
34
26
  theme?: DaisyUITheme;
35
27
  /** Custom theme configuration to override the base theme's values. */
@@ -38,7 +30,17 @@
38
30
  config?: ViewerConfig;
39
31
  /** Bindable viewer state instance for external access (Svelte consumers) */
40
32
  viewerState?: ViewerState;
41
- } = $props();
33
+ }
34
+
35
+ let {
36
+ manifestId,
37
+ canvasId,
38
+ plugins = [],
39
+ theme,
40
+ themeConfig,
41
+ config = {},
42
+ viewerState = $bindable(),
43
+ }: Props = $props();
42
44
 
43
45
  // Reference to root element for applying theme
44
46
  let rootElement: HTMLElement | undefined = $state();
@@ -101,11 +103,45 @@
101
103
  }
102
104
  });
103
105
 
104
- // Register plugins reactively
106
+ // Register plugins reactively with cleanup
107
+ let registeredPluginIds: string[] = [];
108
+
105
109
  $effect(() => {
106
- for (const plugin of plugins) {
107
- internalViewerState.registerPlugin(plugin);
108
- }
110
+ // Create dependency on plugins prop by accessing it
111
+ const currentPlugins = plugins;
112
+
113
+ // Use untrack so that operations inside (like registerPlugin accessing/writing state)
114
+ // do NOT become dependencies of this effect. This prevents infinite loops.
115
+ untrack(() => {
116
+ // Cleanup previous plugins first
117
+ for (const id of registeredPluginIds) {
118
+ internalViewerState.unregisterPlugin(id);
119
+ }
120
+ registeredPluginIds = [];
121
+
122
+ // Register new plugins
123
+ for (const plugin of currentPlugins) {
124
+ const id =
125
+ plugin.id ||
126
+ `plugin-${Math.random().toString(36).substr(2, 9)}`;
127
+ // Create a copy with the ID to ensure stability for THIS registration
128
+ const defWithId = { ...plugin, id };
129
+ internalViewerState.registerPlugin(defWithId);
130
+ registeredPluginIds.push(id);
131
+ }
132
+ });
133
+
134
+ // Cleanup on effect re-run
135
+ return () => {
136
+ for (const id of registeredPluginIds) {
137
+ internalViewerState.unregisterPlugin(id);
138
+ }
139
+ registeredPluginIds = [];
140
+ };
141
+ });
142
+
143
+ onDestroy(() => {
144
+ internalViewerState.destroyAllPlugins();
109
145
  });
110
146
 
111
147
  $effect(() => {
@@ -187,13 +223,19 @@
187
223
  else if (body) resource = body;
188
224
  }
189
225
 
190
- // Check if resource is valid (Manifesto sometimes returns empty objects for v3 bodies)
191
- if (
226
+ // Check if resource is valid (Manifesto sometimes returns empty wrapper objects for v3 bodies)
227
+ // The wrapper may have getServices() that returns manifest-level services, so we can't rely on that.
228
+ // Instead, check if the resource has actual content (id, __jsonld, or a service property)
229
+ const resourceJson = resource?.__jsonld || resource;
230
+ const hasContent =
192
231
  resource &&
193
- !resource.id &&
194
- !resource.__jsonld &&
195
- (!resource.getServices || resource.getServices().length === 0)
196
- ) {
232
+ (resource.id ||
233
+ resource['@id'] ||
234
+ (resourceJson &&
235
+ (resourceJson.service ||
236
+ resourceJson.id ||
237
+ resourceJson['@id'])));
238
+ if (resource && !hasContent) {
197
239
  resource = null;
198
240
  }
199
241
 
@@ -214,28 +256,27 @@
214
256
  const getId = (thing: any) => thing.id || thing['@id'];
215
257
 
216
258
  // Start of service detection logic
217
- let services = [];
218
- if (resource.getServices) {
219
- services = resource.getServices();
259
+ // Check raw json service FIRST - Manifesto's getServices() often returns
260
+ // manifest-level services instead of the image body's services
261
+ let services: any[] = [];
262
+ const rJson = resource.__jsonld || resource;
263
+ if (rJson.service) {
264
+ services = Array.isArray(rJson.service)
265
+ ? rJson.service
266
+ : [rJson.service];
220
267
  }
221
268
 
222
- // Fallback: check raw json service
223
- if (!services.length) {
224
- const rJson = resource.__jsonld || resource;
225
- // console.log('Checking raw resource for services:', rJson);
226
- if (rJson.service) {
227
- services = Array.isArray(rJson.service)
228
- ? rJson.service
229
- : [rJson.service];
230
- }
269
+ // Fallback to getServices() only if raw json didn't have services
270
+ if (!services.length && resource.getServices) {
271
+ services = resource.getServices();
231
272
  }
232
273
 
233
- // console.log('Found services:', services);
234
-
235
274
  if (services.length > 0) {
236
275
  // Find a valid image service
237
276
  const service = services.find((s: any) => {
238
- const type = s.getType ? s.getType() : s.type || '';
277
+ const type = s.getType
278
+ ? s.getType()
279
+ : s.type || s['@type'] || '';
239
280
  const profile = s.getProfile ? s.getProfile() : s.profile || '';
240
281
  return (
241
282
  type === 'ImageService1' ||
@@ -284,12 +325,18 @@
284
325
  <div
285
326
  bind:this={rootElement}
286
327
  id="triiiceratops-viewer"
287
- class="flex w-full h-full relative bg-base-100 overflow-hidden"
328
+ class="flex w-full h-full relative overflow-hidden {internalViewerState
329
+ .config.transparentBackground
330
+ ? ''
331
+ : 'bg-base-100'}"
288
332
  >
289
333
  <!-- Left Column -->
290
334
  {#if isLeftSidebarVisible}
291
335
  <div
292
- class="flex-none flex flex-row z-20 bg-base-200 border-r border-base-300 transition-all"
336
+ class="flex-none flex flex-row z-20 transition-all {internalViewerState
337
+ .config.transparentBackground
338
+ ? ''
339
+ : 'bg-base-200 border-r border-base-300'}"
293
340
  >
294
341
  <!-- Gallery (when docked left) -->
295
342
  {#if internalViewerState.showThumbnailGallery && internalViewerState.dockSide === 'left'}
@@ -301,7 +348,10 @@
301
348
  {#each internalViewerState.pluginPanels as panel (panel.id)}
302
349
  {#if panel.isVisible() && panel.position === 'left'}
303
350
  <div class="h-full relative pointer-events-auto">
304
- <panel.component {...panel.props ?? {}} />
351
+ <panel.component
352
+ {...panel.props ?? {}}
353
+ locale={language.current}
354
+ />
305
355
  </div>
306
356
  {/if}
307
357
  {/each}
@@ -323,7 +373,12 @@
323
373
  {/if}
324
374
 
325
375
  <!-- Main Viewer Area -->
326
- <div class="flex-1 relative min-h-0 w-full h-full bg-base-100">
376
+ <div
377
+ class="flex-1 relative min-h-0 w-full h-full {internalViewerState
378
+ .config.transparentBackground
379
+ ? ''
380
+ : 'bg-base-100'}"
381
+ >
327
382
  {#if manifestData?.isFetching}
328
383
  <div class="w-full h-full flex items-center justify-center">
329
384
  <span
@@ -367,7 +422,10 @@
367
422
  {#each internalViewerState.pluginPanels as panel (panel.id)}
368
423
  {#if panel.isVisible() && panel.position === 'overlay'}
369
424
  <div class="absolute inset-0 z-40 pointer-events-none">
370
- <panel.component {...panel.props ?? {}} />
425
+ <panel.component
426
+ {...panel.props ?? {}}
427
+ locale={language.current}
428
+ />
371
429
  </div>
372
430
  {/if}
373
431
  {/each}
@@ -396,7 +454,10 @@
396
454
  {#each internalViewerState.pluginPanels as panel (panel.id)}
397
455
  {#if panel.isVisible() && panel.position === 'bottom'}
398
456
  <div class="relative w-full z-40 pointer-events-auto">
399
- <panel.component {...panel.props ?? {}} />
457
+ <panel.component
458
+ {...panel.props ?? {}}
459
+ locale={language.current}
460
+ />
400
461
  </div>
401
462
  {/if}
402
463
  {/each}
@@ -405,7 +466,10 @@
405
466
  <!-- Right Column -->
406
467
  {#if isRightSidebarVisible}
407
468
  <div
408
- class="flex-none flex flex-row z-20 bg-base-200 border-l border-base-300 transition-all"
469
+ class="flex-none flex flex-row z-20 transition-all {internalViewerState
470
+ .config.transparentBackground
471
+ ? ''
472
+ : 'bg-base-200 border-l border-base-300'}"
409
473
  >
410
474
  <!-- Search Panel -->
411
475
  {#if internalViewerState.showSearchPanel}
@@ -425,7 +489,10 @@
425
489
  {#each internalViewerState.pluginPanels as panel (panel.id)}
426
490
  {#if panel.isVisible() && panel.position === 'right'}
427
491
  <div class="h-full relative pointer-events-auto">
428
- <panel.component {...panel.props ?? {}} />
492
+ <panel.component
493
+ {...panel.props ?? {}}
494
+ locale={language.current}
495
+ />
429
496
  </div>
430
497
  {/if}
431
498
  {/each}
@@ -1,11 +1,11 @@
1
1
  import { ViewerState } from '../state/viewer.svelte';
2
- import type { TriiiceratopsPlugin } from '../types/plugin';
2
+ import type { PluginDef } from '../types/plugin';
3
3
  import type { DaisyUITheme, ThemeConfig } from '../theme/types';
4
4
  import type { ViewerConfig } from '../types/config';
5
- type $$ComponentProps = {
5
+ interface Props {
6
6
  manifestId?: string;
7
7
  canvasId?: string;
8
- plugins?: TriiiceratopsPlugin[];
8
+ plugins?: PluginDef[];
9
9
  /** Built-in DaisyUI theme name. Defaults to 'light' or 'dark' based on prefers-color-scheme. */
10
10
  theme?: DaisyUITheme;
11
11
  /** Custom theme configuration to override the base theme's values. */
@@ -14,7 +14,7 @@ type $$ComponentProps = {
14
14
  config?: ViewerConfig;
15
15
  /** Bindable viewer state instance for external access (Svelte consumers) */
16
16
  viewerState?: ViewerState;
17
- };
18
- declare const TriiiceratopsViewer: import("svelte").Component<$$ComponentProps, {}, "viewerState">;
17
+ }
18
+ declare const TriiiceratopsViewer: import("svelte").Component<Props, {}, "viewerState">;
19
19
  type TriiiceratopsViewer = ReturnType<typeof TriiiceratopsViewer>;
20
20
  export default TriiiceratopsViewer;
@@ -35,7 +35,7 @@
35
35
  <script lang="ts">
36
36
  import styles from '../../app.css?inline';
37
37
  import TriiiceratopsViewer from './TriiiceratopsViewer.svelte';
38
- import type { TriiiceratopsPlugin } from '../types/plugin';
38
+ import type { PluginDef } from '../types/plugin';
39
39
  import type { DaisyUITheme, ThemeConfig } from '../theme/types';
40
40
  import type { ViewerConfig } from '../types/config';
41
41
  import { isBuiltInTheme, parseThemeConfig } from '../theme/themeManager';
@@ -51,7 +51,7 @@
51
51
  }: {
52
52
  manifestId?: string;
53
53
  canvasId?: string;
54
- plugins?: TriiiceratopsPlugin[];
54
+ plugins?: PluginDef[];
55
55
  /**
56
56
  * Built-in DaisyUI theme name (e.g., 'light', 'dark', 'cupcake').
57
57
  * When not specified, inherits the theme from the parent context.
@@ -1,10 +1,10 @@
1
- import type { TriiiceratopsPlugin } from '../types/plugin';
1
+ import type { PluginDef } from '../types/plugin';
2
2
  import type { ThemeConfig } from '../theme/types';
3
3
  import type { ViewerConfig } from '../types/config';
4
4
  type $$ComponentProps = {
5
5
  manifestId?: string;
6
6
  canvasId?: string;
7
- plugins?: TriiiceratopsPlugin[];
7
+ plugins?: PluginDef[];
8
8
  /**
9
9
  * Built-in DaisyUI theme name (e.g., 'light', 'dark', 'cupcake').
10
10
  * When not specified, inherits the theme from the parent context.
@@ -1 +1,11 @@
1
+ import * as svelte from 'svelte';
2
+ declare global {
3
+ interface Window {
4
+ __TriiiceratopsSvelteRuntime: {
5
+ svelte: typeof svelte;
6
+ internal: unknown;
7
+ };
8
+ TriiiceratopsPlugins?: Record<string, unknown>;
9
+ }
10
+ }
1
11
  import './components/TriiiceratopsViewerElement.svelte';
@@ -1,3 +1,16 @@
1
1
  // Entry point for custom element build
2
2
  // Importing this module registers the <triiiceratops-viewer> custom element
3
+ // Expose Svelte internals for IIFE plugin builds
4
+ // Plugins built as IIFE need to share the same Svelte runtime instance
5
+ // so that getContext/setContext work correctly across bundle boundaries
6
+ // @ts-expect-error - svelte/internal/client is not typed but exists at runtime
7
+ import * as svelteInternal from 'svelte/internal/client';
8
+ import * as svelte from 'svelte';
9
+ window.__TriiiceratopsSvelteRuntime = {
10
+ svelte,
11
+ internal: svelteInternal,
12
+ };
13
+ // Initialize the plugins namespace
14
+ window.TriiiceratopsPlugins = window.TriiiceratopsPlugins || {};
15
+ // Register the custom element
3
16
  import './components/TriiiceratopsViewerElement.svelte';
@@ -0,0 +1,108 @@
1
+ import { a as t } from "./X-DZEgXrJ8.js";
2
+ const s = (
3
+ /** @type {(inputs: {}) => LocalizedString} */
4
+ () => (
5
+ /** @type {LocalizedString} */
6
+ "Image Adjustments"
7
+ )
8
+ ), a = (
9
+ /** @type {(inputs: {}) => LocalizedString} */
10
+ () => (
11
+ /** @type {LocalizedString} */
12
+ "Bildanpassungen"
13
+ )
14
+ ), v = /* @__NO_SIDE_EFFECTS__ */ (n = {}, e = {}) => (e.locale ?? t()) === "en" ? s() : a(), l = (
15
+ /** @type {(inputs: {}) => LocalizedString} */
16
+ () => (
17
+ /** @type {LocalizedString} */
18
+ "Brightness"
19
+ )
20
+ ), i = (
21
+ /** @type {(inputs: {}) => LocalizedString} */
22
+ () => (
23
+ /** @type {LocalizedString} */
24
+ "Helligkeit"
25
+ )
26
+ ), y = /* @__NO_SIDE_EFFECTS__ */ (n = {}, e = {}) => (e.locale ?? t()) === "en" ? l() : i(), o = (
27
+ /** @type {(inputs: {}) => LocalizedString} */
28
+ () => (
29
+ /** @type {LocalizedString} */
30
+ "Contrast"
31
+ )
32
+ ), c = (
33
+ /** @type {(inputs: {}) => LocalizedString} */
34
+ () => (
35
+ /** @type {LocalizedString} */
36
+ "Kontrast"
37
+ )
38
+ ), B = /* @__NO_SIDE_EFFECTS__ */ (n = {}, e = {}) => (e.locale ?? t()) === "en" ? o() : c(), _ = (
39
+ /** @type {(inputs: {}) => LocalizedString} */
40
+ () => (
41
+ /** @type {LocalizedString} */
42
+ "Saturation"
43
+ )
44
+ ), u = (
45
+ /** @type {(inputs: {}) => LocalizedString} */
46
+ () => (
47
+ /** @type {LocalizedString} */
48
+ "Sättigung"
49
+ )
50
+ ), C = /* @__NO_SIDE_EFFECTS__ */ (n = {}, e = {}) => (e.locale ?? t()) === "en" ? _() : u(), f = (
51
+ /** @type {(inputs: {}) => LocalizedString} */
52
+ () => (
53
+ /** @type {LocalizedString} */
54
+ "Effects"
55
+ )
56
+ ), g = (
57
+ /** @type {(inputs: {}) => LocalizedString} */
58
+ () => (
59
+ /** @type {LocalizedString} */
60
+ "Effekte"
61
+ )
62
+ ), E = /* @__NO_SIDE_EFFECTS__ */ (n = {}, e = {}) => (e.locale ?? t()) === "en" ? f() : g(), m = (
63
+ /** @type {(inputs: {}) => LocalizedString} */
64
+ () => (
65
+ /** @type {LocalizedString} */
66
+ "Invert Colors"
67
+ )
68
+ ), d = (
69
+ /** @type {(inputs: {}) => LocalizedString} */
70
+ () => (
71
+ /** @type {LocalizedString} */
72
+ "Farben umkehren"
73
+ )
74
+ ), G = /* @__NO_SIDE_EFFECTS__ */ (n = {}, e = {}) => (e.locale ?? t()) === "en" ? m() : d(), p = (
75
+ /** @type {(inputs: {}) => LocalizedString} */
76
+ () => (
77
+ /** @type {LocalizedString} */
78
+ "Grayscale"
79
+ )
80
+ ), b = (
81
+ /** @type {(inputs: {}) => LocalizedString} */
82
+ () => (
83
+ /** @type {LocalizedString} */
84
+ "Graustufen"
85
+ )
86
+ ), I = /* @__NO_SIDE_EFFECTS__ */ (n = {}, e = {}) => (e.locale ?? t()) === "en" ? p() : b(), h = (
87
+ /** @type {(inputs: {}) => LocalizedString} */
88
+ () => (
89
+ /** @type {LocalizedString} */
90
+ "Reset to Default"
91
+ )
92
+ ), j = (
93
+ /** @type {(inputs: {}) => LocalizedString} */
94
+ () => (
95
+ /** @type {LocalizedString} */
96
+ "Zurücksetzen"
97
+ )
98
+ ), S = /* @__NO_SIDE_EFFECTS__ */ (n = {}, e = {}) => (e.locale ?? t()) === "en" ? h() : j();
99
+ export {
100
+ y as a,
101
+ B as b,
102
+ E as c,
103
+ I as d,
104
+ G as e,
105
+ S as f,
106
+ C as g,
107
+ v as i
108
+ };
package/dist/index.d.ts CHANGED
@@ -2,8 +2,7 @@ export { default as TriiiceratopsViewer } from './components/TriiiceratopsViewer
2
2
  export { ViewerState, VIEWER_STATE_KEY } from './state/viewer.svelte';
3
3
  export type { ViewerStateSnapshot } from './state/viewer.svelte';
4
4
  export { ManifestsState } from './state/manifests.svelte';
5
- export type { TriiiceratopsPlugin, PluginContext, PluginMenuButton, PluginPanel, } from './types/plugin';
6
- export { BasePlugin } from './types/plugin';
5
+ export type { PluginDef, PluginMenuButton, PluginPanel } from './types/plugin';
7
6
  export type { ThemeConfig, DaisyUITheme } from './theme/types';
8
7
  export { DAISYUI_THEMES } from './theme/types';
9
8
  export { applyTheme, applyBuiltInTheme, applyThemeConfig, clearThemeConfig, isBuiltInTheme, parseThemeConfig, } from './theme/themeManager';
package/dist/index.js CHANGED
@@ -3,7 +3,6 @@ export { default as TriiiceratopsViewer } from './components/TriiiceratopsViewer
3
3
  // Type exports for TypeScript users
4
4
  export { ViewerState, VIEWER_STATE_KEY } from './state/viewer.svelte';
5
5
  export { ManifestsState } from './state/manifests.svelte';
6
- export { BasePlugin } from './types/plugin';
7
6
  export { DAISYUI_THEMES } from './theme/types';
8
7
  export { applyTheme, applyBuiltInTheme, applyThemeConfig, clearThemeConfig, isBuiltInTheme, parseThemeConfig, } from './theme/themeManager';
9
8
  export { hexToOklch, normalizeColor } from './theme/colorUtils';