triiiceratops 0.9.1 → 0.9.3

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.
@@ -12,7 +12,7 @@ function getAnnotationId(anno) {
12
12
  function parseXywh(targetStr) {
13
13
  if (!targetStr)
14
14
  return null;
15
- var match = targetStr.match(/xywh=(\d+),(\d+),(\d+),(\d+)/);
15
+ const match = targetStr.match(/xywh=(\d+),(\d+),(\d+),(\d+)/);
16
16
  if (match) {
17
17
  return {
18
18
  x: parseInt(match[1], 10),
@@ -28,12 +28,12 @@ function parseXywh(targetStr) {
28
28
  */
29
29
  function extractGeometry(annotation) {
30
30
  // Try to find SVG selector first
31
- var svgSelector = findSvgSelector(annotation);
31
+ const svgSelector = findSvgSelector(annotation);
32
32
  if (svgSelector) {
33
33
  return convertSvgToPolygon(svgSelector);
34
34
  }
35
35
  // Extract xywh from target
36
- var xywh = extractXywhFromTarget(annotation);
36
+ const xywh = extractXywhFromTarget(annotation);
37
37
  if (xywh) {
38
38
  return {
39
39
  type: 'RECTANGLE',
@@ -49,17 +49,16 @@ function extractGeometry(annotation) {
49
49
  * Find SVG selector in annotation target
50
50
  */
51
51
  function findSvgSelector(annotation) {
52
- var _a, _b;
53
52
  // Try Manifesto method
54
53
  if (typeof annotation.getTarget === 'function') {
55
54
  // For Manifesto, check raw JSON for SVG
56
- var rawOn = ((_a = annotation.__jsonld) === null || _a === void 0 ? void 0 : _a.on) || ((_b = annotation.__jsonld) === null || _b === void 0 ? void 0 : _b.target);
55
+ const rawOn = annotation.__jsonld?.on || annotation.__jsonld?.target;
57
56
  if (rawOn) {
58
57
  return extractSvgFromTarget(rawOn);
59
58
  }
60
59
  }
61
60
  // Check common locations in raw JSON
62
- var target = annotation.target || annotation.on;
61
+ const target = annotation.target || annotation.on;
63
62
  if (target) {
64
63
  return extractSvgFromTarget(target);
65
64
  }
@@ -73,9 +72,8 @@ function extractSvgFromTarget(target) {
73
72
  return null;
74
73
  // Handle array of targets
75
74
  if (Array.isArray(target)) {
76
- for (var _i = 0, target_1 = target; _i < target_1.length; _i++) {
77
- var t = target_1[_i];
78
- var svg = extractSvgValue(t);
75
+ for (const t of target) {
76
+ const svg = extractSvgValue(t);
79
77
  if (svg)
80
78
  return svg;
81
79
  }
@@ -89,16 +87,15 @@ function extractSvgFromTarget(target) {
89
87
  * Extract SVG value from single target object
90
88
  */
91
89
  function extractSvgValue(target) {
92
- var _a;
93
90
  if (!target)
94
91
  return null;
95
92
  // Check for SvgSelector
96
- var selector = target.selector || target;
97
- if ((selector === null || selector === void 0 ? void 0 : selector.type) === 'SvgSelector' && selector.value) {
93
+ const selector = target.selector || target;
94
+ if (selector?.type === 'SvgSelector' && selector.value) {
98
95
  return selector.value;
99
96
  }
100
97
  // Check item (sometimes nested)
101
- if (((_a = selector === null || selector === void 0 ? void 0 : selector.item) === null || _a === void 0 ? void 0 : _a.type) === 'SvgSelector' && selector.item.value) {
98
+ if (selector?.item?.type === 'SvgSelector' && selector.item.value) {
102
99
  return selector.item.value;
103
100
  }
104
101
  return null;
@@ -109,49 +106,46 @@ function extractSvgValue(target) {
109
106
  */
110
107
  function convertSvgToPolygon(svgString) {
111
108
  try {
112
- var parser = new DOMParser();
113
- var doc = parser.parseFromString(svgString, 'image/svg+xml');
109
+ const parser = new DOMParser();
110
+ const doc = parser.parseFromString(svgString, 'image/svg+xml');
114
111
  if (doc.documentElement.nodeName === 'parsererror') {
115
112
  console.warn('Failed to parse SVG selector:', svgString);
116
113
  return null;
117
114
  }
118
- var points = [];
115
+ const points = [];
119
116
  // Extract points from polygon elements
120
- var polygons = doc.querySelectorAll('polygon');
121
- for (var _i = 0, polygons_1 = polygons; _i < polygons_1.length; _i++) {
122
- var poly = polygons_1[_i];
123
- var pointsAttr = poly.getAttribute('points');
117
+ const polygons = doc.querySelectorAll('polygon');
118
+ for (const poly of polygons) {
119
+ const pointsAttr = poly.getAttribute('points');
124
120
  if (pointsAttr) {
125
- var polyPoints = parsePolygonPoints(pointsAttr);
126
- points.push.apply(points, polyPoints);
121
+ const polyPoints = parsePolygonPoints(pointsAttr);
122
+ points.push(...polyPoints);
127
123
  }
128
124
  }
129
125
  // Extract points from path elements (simple conversion, doesn't handle curves)
130
- var paths = doc.querySelectorAll('path');
131
- for (var _a = 0, paths_1 = paths; _a < paths_1.length; _a++) {
132
- var path = paths_1[_a];
133
- var d = path.getAttribute('d');
126
+ const paths = doc.querySelectorAll('path');
127
+ for (const path of paths) {
128
+ const d = path.getAttribute('d');
134
129
  if (d) {
135
- var pathPoints = parsePathData(d);
136
- points.push.apply(points, pathPoints);
130
+ const pathPoints = parsePathData(d);
131
+ points.push(...pathPoints);
137
132
  }
138
133
  }
139
134
  // Extract points from circle/ellipse (approximate as polygon)
140
- var circles = doc.querySelectorAll('circle');
141
- for (var _b = 0, circles_1 = circles; _b < circles_1.length; _b++) {
142
- var circle = circles_1[_b];
143
- var cx = parseFloat(circle.getAttribute('cx') || '0');
144
- var cy = parseFloat(circle.getAttribute('cy') || '0');
145
- var r = parseFloat(circle.getAttribute('r') || '0');
146
- var circlePoints = generateCirclePoints(cx, cy, r);
147
- points.push.apply(points, circlePoints);
135
+ const circles = doc.querySelectorAll('circle');
136
+ for (const circle of circles) {
137
+ const cx = parseFloat(circle.getAttribute('cx') || '0');
138
+ const cy = parseFloat(circle.getAttribute('cy') || '0');
139
+ const r = parseFloat(circle.getAttribute('r') || '0');
140
+ const circlePoints = generateCirclePoints(cx, cy, r);
141
+ points.push(...circlePoints);
148
142
  }
149
143
  if (points.length === 0) {
150
144
  return null;
151
145
  }
152
146
  return {
153
147
  type: 'POLYGON',
154
- points: points,
148
+ points,
155
149
  };
156
150
  }
157
151
  catch (e) {
@@ -164,11 +158,10 @@ function convertSvgToPolygon(svgString) {
164
158
  * Format: "x1,y1 x2,y2 x3,y3"
165
159
  */
166
160
  function parsePolygonPoints(pointsStr) {
167
- var points = [];
168
- var pairs = pointsStr.trim().split(/\s+/);
169
- for (var _i = 0, pairs_1 = pairs; _i < pairs_1.length; _i++) {
170
- var pair = pairs_1[_i];
171
- var _a = pair.split(',').map(function (v) { return parseFloat(v); }), x = _a[0], y = _a[1];
161
+ const points = [];
162
+ const pairs = pointsStr.trim().split(/\s+/);
163
+ for (const pair of pairs) {
164
+ const [x, y] = pair.split(',').map((v) => parseFloat(v));
172
165
  if (!isNaN(x) && !isNaN(y)) {
173
166
  points.push([x, y]);
174
167
  }
@@ -180,13 +173,13 @@ function parsePolygonPoints(pointsStr) {
180
173
  * Extracts M (moveto) and L (lineto) commands
181
174
  */
182
175
  function parsePathData(d) {
183
- var points = [];
176
+ const points = [];
184
177
  // Simple regex: match M and L commands followed by coordinates
185
- var commandRegex = /[ML]\s*([\d.]+)[,\s]+([\d.]+)/g;
186
- var match;
178
+ const commandRegex = /[ML]\s*([\d.]+)[,\s]+([\d.]+)/g;
179
+ let match;
187
180
  while ((match = commandRegex.exec(d)) !== null) {
188
- var x = parseFloat(match[1]);
189
- var y = parseFloat(match[2]);
181
+ const x = parseFloat(match[1]);
182
+ const y = parseFloat(match[2]);
190
183
  if (!isNaN(x) && !isNaN(y)) {
191
184
  points.push([x, y]);
192
185
  }
@@ -196,13 +189,12 @@ function parsePathData(d) {
196
189
  /**
197
190
  * Generate polygon points approximating a circle
198
191
  */
199
- function generateCirclePoints(cx, cy, r, numPoints) {
200
- if (numPoints === void 0) { numPoints = 8; }
201
- var points = [];
202
- for (var i = 0; i < numPoints; i++) {
203
- var angle = (i / numPoints) * Math.PI * 2;
204
- var x = cx + r * Math.cos(angle);
205
- var y = cy + r * Math.sin(angle);
192
+ function generateCirclePoints(cx, cy, r, numPoints = 8) {
193
+ const points = [];
194
+ for (let i = 0; i < numPoints; i++) {
195
+ const angle = (i / numPoints) * Math.PI * 2;
196
+ const x = cx + r * Math.cos(angle);
197
+ const y = cy + r * Math.sin(angle);
206
198
  points.push([x, y]);
207
199
  }
208
200
  return points;
@@ -211,23 +203,22 @@ function generateCirclePoints(cx, cy, r, numPoints) {
211
203
  * Extract xywh from annotation target (multiple formats)
212
204
  */
213
205
  function extractXywhFromTarget(annotation) {
214
- var _a;
215
206
  // Try Manifesto getTarget method
216
207
  if (typeof annotation.getTarget === 'function') {
217
- var target_2 = annotation.getTarget();
218
- if (typeof target_2 === 'string' && target_2.includes('xywh=')) {
219
- return parseXywh(target_2);
208
+ const target = annotation.getTarget();
209
+ if (typeof target === 'string' && target.includes('xywh=')) {
210
+ return parseXywh(target);
220
211
  }
221
212
  // Check raw JSON as fallback
222
- var rawOn = (_a = annotation.__jsonld) === null || _a === void 0 ? void 0 : _a.on;
213
+ const rawOn = annotation.__jsonld?.on;
223
214
  if (rawOn) {
224
- var xywh = extractXywhFromRawTarget(rawOn);
215
+ const xywh = extractXywhFromRawTarget(rawOn);
225
216
  if (xywh)
226
217
  return xywh;
227
218
  }
228
219
  }
229
220
  // Check raw annotation formats (v2 and v3)
230
- var target = annotation.target || annotation.on;
221
+ const target = annotation.target || annotation.on;
231
222
  if (target) {
232
223
  return extractXywhFromRawTarget(target);
233
224
  }
@@ -241,9 +232,8 @@ function extractXywhFromRawTarget(target) {
241
232
  return null;
242
233
  // Handle arrays
243
234
  if (Array.isArray(target)) {
244
- for (var _i = 0, target_3 = target; _i < target_3.length; _i++) {
245
- var t = target_3[_i];
246
- var xywh = extractXywhFromRawTarget(t);
235
+ for (const t of target) {
236
+ const xywh = extractXywhFromRawTarget(t);
247
237
  if (xywh)
248
238
  return xywh;
249
239
  }
@@ -254,8 +244,8 @@ function extractXywhFromRawTarget(target) {
254
244
  }
255
245
  // Handle object with selector
256
246
  if (target.selector) {
257
- var sel = target.selector;
258
- var item = sel.item || sel;
247
+ const sel = target.selector;
248
+ const item = sel.item || sel;
259
249
  if (item.value && typeof item.value === 'string' && item.value.includes('xywh=')) {
260
250
  return parseXywh(item.value);
261
251
  }
@@ -266,19 +256,18 @@ function extractXywhFromRawTarget(target) {
266
256
  * Extract annotation body content (text, label, etc)
267
257
  */
268
258
  function extractBody(annotation) {
269
- var value = '';
270
- var isHtml = false;
259
+ let value = '';
260
+ let isHtml = false;
271
261
  // Try Manifesto getBody method
272
262
  if (typeof annotation.getBody === 'function') {
273
- var body = annotation.getBody();
263
+ const body = annotation.getBody();
274
264
  if (body && Array.isArray(body)) {
275
- var values = [];
276
- for (var _i = 0, body_1 = body; _i < body_1.length; _i++) {
277
- var b = body_1[_i];
278
- var val = b.getValue ? b.getValue() : '';
265
+ const values = [];
266
+ for (const b of body) {
267
+ const val = b.getValue ? b.getValue() : '';
279
268
  if (val) {
280
269
  values.push(val);
281
- var format = b.getFormat ? b.getFormat() : '';
270
+ const format = b.getFormat ? b.getFormat() : '';
282
271
  if (format === 'text/html' || format === 'application/html') {
283
272
  isHtml = true;
284
273
  }
@@ -289,23 +278,23 @@ function extractBody(annotation) {
289
278
  }
290
279
  else {
291
280
  // Handle raw JSON body/resource
292
- var getText = function (r) {
281
+ const getText = (r) => {
293
282
  if (!r)
294
283
  return '';
295
284
  return r.chars || r.value || r['cnt:chars'] || '';
296
285
  };
297
- var checkHtml = function (r) {
286
+ const checkHtml = (r) => {
298
287
  if (!r)
299
288
  return false;
300
289
  return r.format === 'text/html' || r.type === 'TextualBody';
301
290
  };
302
291
  if (annotation.resource) {
303
- var resources = Array.isArray(annotation.resource) ? annotation.resource : [annotation.resource];
292
+ const resources = Array.isArray(annotation.resource) ? annotation.resource : [annotation.resource];
304
293
  value = resources.map(getText).filter(Boolean).join(' ');
305
294
  isHtml = resources.some(checkHtml);
306
295
  }
307
296
  else if (annotation.body) {
308
- var bodyArr = Array.isArray(annotation.body) ? annotation.body : [annotation.body];
297
+ const bodyArr = Array.isArray(annotation.body) ? annotation.body : [annotation.body];
309
298
  value = bodyArr.map(getText).filter(Boolean).join(' ');
310
299
  isHtml = bodyArr.some(checkHtml);
311
300
  }
@@ -319,36 +308,34 @@ function extractBody(annotation) {
319
308
  value = Array.isArray(annotation.label) ? annotation.label.join(' ') : annotation.label;
320
309
  }
321
310
  }
322
- return { value: value || 'Annotation', isHtml: isHtml };
311
+ return { value: value || 'Annotation', isHtml };
323
312
  }
324
313
  /**
325
314
  * Parse Manifesto/IIIF annotation to internal format
326
315
  */
327
- export function parseAnnotation(annotation, index, isSearchHit) {
328
- if (isSearchHit === void 0) { isSearchHit = false; }
329
- var id = getAnnotationId(annotation) || "anno-".concat(index);
330
- var geometry = extractGeometry(annotation);
316
+ export function parseAnnotation(annotation, index, isSearchHit = false) {
317
+ const id = getAnnotationId(annotation) || `anno-${index}`;
318
+ const geometry = extractGeometry(annotation);
331
319
  // Skip annotations without geometry
332
320
  if (!geometry) {
333
321
  return null;
334
322
  }
335
- var body = extractBody(annotation);
323
+ const body = extractBody(annotation);
336
324
  return {
337
- id: id,
338
- geometry: geometry,
339
- body: body,
340
- isSearchHit: isSearchHit,
325
+ id,
326
+ geometry,
327
+ body,
328
+ isSearchHit,
341
329
  };
342
330
  }
343
331
  /**
344
332
  * Batch parse annotations
345
333
  */
346
- export function parseAnnotations(annotations, searchHitIds) {
347
- if (searchHitIds === void 0) { searchHitIds = new Set(); }
334
+ export function parseAnnotations(annotations, searchHitIds = new Set()) {
348
335
  return annotations
349
- .map(function (anno, idx) {
350
- var isSearchHit = searchHitIds.has(getAnnotationId(anno));
336
+ .map((anno, idx) => {
337
+ const isSearchHit = searchHitIds.has(getAnnotationId(anno));
351
338
  return parseAnnotation(anno, idx, isSearchHit);
352
339
  })
353
- .filter(function (anno) { return anno !== null; });
340
+ .filter((anno) => anno !== null);
354
341
  }
@@ -1,19 +1,19 @@
1
1
  import { describe, it, expect } from "vitest";
2
2
  import { parseAnnotation } from "./annotationAdapter";
3
- describe("annotationAdapter", function () {
4
- describe("parseAnnotation", function () {
5
- it("should correctly parse a simple xywh string target", function () {
6
- var annotation = {
3
+ describe("annotationAdapter", () => {
4
+ describe("parseAnnotation", () => {
5
+ it("should correctly parse a simple xywh string target", () => {
6
+ const annotation = {
7
7
  "@id": "http://example.org/anno1",
8
8
  on: "http://example.org/image1#xywh=10,20,100,200",
9
9
  label: "Test Annotation",
10
10
  };
11
- var result = parseAnnotation(annotation, 0);
11
+ const result = parseAnnotation(annotation, 0);
12
12
  expect(result).not.toBeNull();
13
13
  if (!result)
14
14
  return;
15
15
  expect(result.geometry.type).toBe("RECTANGLE");
16
- var geometry = result.geometry;
16
+ const geometry = result.geometry;
17
17
  if ("x" in geometry) {
18
18
  expect(geometry).toEqual({
19
19
  type: "RECTANGLE",
@@ -27,8 +27,8 @@ describe("annotationAdapter", function () {
27
27
  throw new Error("Geometry should be RECTANGLE type with x, y, w, h");
28
28
  }
29
29
  });
30
- it("should extract SVG selector geometry", function () {
31
- var annotation = {
30
+ it("should extract SVG selector geometry", () => {
31
+ const annotation = {
32
32
  "@id": "http://example.org/anno2",
33
33
  on: {
34
34
  selector: {
@@ -37,12 +37,12 @@ describe("annotationAdapter", function () {
37
37
  },
38
38
  },
39
39
  };
40
- var result = parseAnnotation(annotation, 1);
40
+ const result = parseAnnotation(annotation, 1);
41
41
  expect(result).not.toBeNull();
42
42
  if (!result)
43
43
  return;
44
44
  expect(result.geometry.type).toBe("POLYGON");
45
- var geometry = result.geometry;
45
+ const geometry = result.geometry;
46
46
  if ("points" in geometry) {
47
47
  expect(geometry.points).toHaveLength(4);
48
48
  expect(geometry.points).toEqual([
@@ -56,18 +56,18 @@ describe("annotationAdapter", function () {
56
56
  throw new Error("Geometry should be POLYGON type with points");
57
57
  }
58
58
  });
59
- it("should handle Manifesto-style getTarget and getId methods", function () {
60
- var mockManifestoAnno = {
61
- getId: function () { return "http://example.org/manifesto-anno"; },
62
- getTarget: function () { return "http://example.org/canvas1#xywh=5,5,50,50"; },
63
- getBody: function () { return [
64
- { getValue: function () { return "Manifesto Body"; }, getFormat: function () { return "text/plain"; } },
65
- ]; },
59
+ it("should handle Manifesto-style getTarget and getId methods", () => {
60
+ const mockManifestoAnno = {
61
+ getId: () => "http://example.org/manifesto-anno",
62
+ getTarget: () => "http://example.org/canvas1#xywh=5,5,50,50",
63
+ getBody: () => [
64
+ { getValue: () => "Manifesto Body", getFormat: () => "text/plain" },
65
+ ],
66
66
  };
67
67
  // @ts-ignore - mocking complex object
68
- var result = parseAnnotation(mockManifestoAnno, 2);
69
- expect(result === null || result === void 0 ? void 0 : result.id).toBe("http://example.org/manifesto-anno");
70
- var geometry = result === null || result === void 0 ? void 0 : result.geometry;
68
+ const result = parseAnnotation(mockManifestoAnno, 2);
69
+ expect(result?.id).toBe("http://example.org/manifesto-anno");
70
+ const geometry = result?.geometry;
71
71
  if (geometry && "x" in geometry) {
72
72
  expect(geometry).toMatchObject({
73
73
  type: "RECTANGLE",
@@ -77,14 +77,14 @@ describe("annotationAdapter", function () {
77
77
  h: 50,
78
78
  });
79
79
  }
80
- expect(result === null || result === void 0 ? void 0 : result.body.value).toBe("Manifesto Body");
80
+ expect(result?.body.value).toBe("Manifesto Body");
81
81
  });
82
- it("should return null for invalid annotations with no geometry", function () {
83
- var invalidAnno = {
82
+ it("should return null for invalid annotations with no geometry", () => {
83
+ const invalidAnno = {
84
84
  "@id": "bad-anno",
85
85
  on: "http://example.org/canvas1", // No media fragment or selector
86
86
  };
87
- var result = parseAnnotation(invalidAnno, 3);
87
+ const result = parseAnnotation(invalidAnno, 3);
88
88
  expect(result).toBeNull();
89
89
  });
90
90
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "triiiceratops",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -59,7 +59,6 @@
59
59
  "@types/openseadragon": "^5.0.1",
60
60
  "happy-dom": "^20.0.11",
61
61
  "jsdom": "^27.3.0",
62
- "phosphor-svelte": "^3.0.1",
63
62
  "prettier": "^3.7.4",
64
63
  "prettier-plugin-svelte": "^3.4.0",
65
64
  "svelte": "^5.43.8",
@@ -74,12 +73,13 @@
74
73
  "daisyui": "^5.5.8",
75
74
  "manifesto.js": "^4.3.0",
76
75
  "openseadragon": "^5.0.1",
76
+ "phosphor-svelte": "^3.0.1",
77
77
  "tailwindcss": "^4.1.17"
78
78
  },
79
79
  "scripts": {
80
80
  "dev": "vite",
81
81
  "build": "vite build",
82
- "build:lib": "svelte-package && vite build --config vite.config.lib.ts",
82
+ "build:lib": "svelte-package --tsconfig ./tsconfig.app.json && vite build --config vite.config.lib.ts",
83
83
  "build:element": "vite build --config vite.config.element.ts",
84
84
  "build:demo": "vite build --config vite.config.demo.ts",
85
85
  "build:consumer": "vite build --config vite.config.demo-consumer.ts",