@semiont/react-ui 0.2.34 → 0.2.35-build.101

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/dist/index.mjs CHANGED
@@ -17131,11 +17131,10 @@ var jsonLightHighlightStyle = HighlightStyle.define([
17131
17131
  // src/lib/codemirror-widgets.ts
17132
17132
  import { isResolvedReference, getBodySource } from "@semiont/api-client";
17133
17133
  var ReferenceResolutionWidget = class extends WidgetType {
17134
- constructor(annotation, targetDocumentName, eventBus, isGenerating) {
17134
+ constructor(annotation, targetDocumentName, isGenerating) {
17135
17135
  super();
17136
17136
  this.annotation = annotation;
17137
17137
  this.targetDocumentName = targetDocumentName;
17138
- this.eventBus = eventBus;
17139
17138
  this.isGenerating = isGenerating;
17140
17139
  }
17141
17140
  eq(other) {
@@ -17152,10 +17151,17 @@ var ReferenceResolutionWidget = class extends WidgetType {
17152
17151
  margin-left: 4px;
17153
17152
  position: relative;
17154
17153
  `;
17154
+ const isResolved = isResolvedReference(this.annotation);
17155
+ const bodySource = getBodySource(this.annotation.body);
17156
+ container.dataset.widgetAnnotationId = this.annotation.id;
17157
+ container.dataset.widgetMotivation = this.annotation.motivation;
17158
+ container.dataset.widgetResolved = isResolved ? "true" : "false";
17159
+ if (bodySource) container.dataset.widgetBodySource = bodySource;
17160
+ if (this.targetDocumentName) container.dataset.widgetTargetName = this.targetDocumentName;
17161
+ if (this.isGenerating) container.dataset.widgetGenerating = "true";
17155
17162
  const indicator = document.createElement("button");
17156
17163
  indicator.className = "reference-indicator";
17157
17164
  indicator.type = "button";
17158
- const isResolved = isResolvedReference(this.annotation);
17159
17165
  if (isResolved) {
17160
17166
  indicator.innerHTML = '<span aria-hidden="true">\u{1F517}</span>';
17161
17167
  indicator.setAttribute("aria-label", this.targetDocumentName ? `Reference link to ${this.targetDocumentName}` : "Reference link to document");
@@ -17171,13 +17177,6 @@ var ReferenceResolutionWidget = class extends WidgetType {
17171
17177
  margin: 0;
17172
17178
  vertical-align: baseline;
17173
17179
  `;
17174
- indicator.style.cssText += `
17175
- &:focus {
17176
- outline: 2px solid #3b82f6;
17177
- outline-offset: 2px;
17178
- opacity: 1;
17179
- }
17180
- `;
17181
17180
  } else if (this.isGenerating) {
17182
17181
  indicator.innerHTML = `
17183
17182
  <span style="position: relative; display: inline-flex; align-items: center; justify-content: center;" aria-hidden="true">
@@ -17226,82 +17225,40 @@ var ReferenceResolutionWidget = class extends WidgetType {
17226
17225
  margin: 0;
17227
17226
  vertical-align: baseline;
17228
17227
  `;
17229
- indicator.style.cssText += `
17230
- &:focus {
17231
- outline: 2px solid #3b82f6;
17232
- outline-offset: 2px;
17233
- opacity: 1;
17234
- }
17235
- `;
17236
- }
17237
- if (!this.isGenerating) {
17238
- indicator.addEventListener("mouseenter", () => {
17239
- indicator.style.opacity = "1";
17240
- if (isResolved && this.targetDocumentName && this.targetDocumentName.trim() !== "") {
17241
- this.showPreview(container, this.targetDocumentName);
17242
- }
17243
- });
17244
- indicator.addEventListener("mouseleave", () => {
17245
- indicator.style.opacity = "0.6";
17246
- if (isResolved) {
17247
- this.hidePreview(container);
17248
- }
17249
- });
17250
- const bodySource = getBodySource(this.annotation.body);
17251
- if (isResolved && bodySource && this.eventBus) {
17252
- const eventBus = this.eventBus;
17253
- indicator.addEventListener("click", (e6) => {
17254
- e6.preventDefault();
17255
- e6.stopPropagation();
17256
- eventBus.get("navigation:reference-navigate").next({ documentId: bodySource });
17257
- });
17258
- } else if (!isResolved && this.eventBus) {
17259
- const eventBus = this.eventBus;
17260
- const annotation = this.annotation;
17261
- indicator.addEventListener("click", (e6) => {
17262
- e6.preventDefault();
17263
- e6.stopPropagation();
17264
- eventBus.get("attend:click").next({ annotationId: annotation.id, motivation: annotation.motivation });
17265
- });
17266
- }
17267
17228
  }
17268
17229
  container.appendChild(indicator);
17269
17230
  return container;
17270
17231
  }
17271
- showPreview(container, documentName) {
17272
- if (!documentName || documentName.trim() === "") {
17273
- return;
17274
- }
17275
- const tooltip = document.createElement("div");
17276
- tooltip.className = "reference-tooltip";
17277
- tooltip.textContent = `\u2192 ${documentName}`;
17278
- tooltip.style.cssText = `
17279
- position: absolute;
17280
- bottom: 100%;
17281
- left: 50%;
17282
- transform: translateX(-50%) translateY(-4px);
17283
- padding: 4px 8px;
17284
- background: rgba(0, 0, 0, 0.8);
17285
- color: white;
17286
- border-radius: 4px;
17287
- font-size: 11px;
17288
- white-space: nowrap;
17289
- pointer-events: none;
17290
- z-index: 1000;
17291
- animation: fadeIn 0.2s ease;
17292
- `;
17293
- container.appendChild(tooltip);
17294
- }
17295
- hidePreview(container) {
17296
- const tooltip = container.querySelector(".reference-tooltip");
17297
- if (tooltip) {
17298
- tooltip.remove();
17299
- }
17300
- }
17301
17232
  ignoreEvent(event) {
17302
17233
  return event.type === "click";
17303
17234
  }
17304
17235
  };
17236
+ function showWidgetPreview(container, documentName) {
17237
+ if (!documentName || documentName.trim() === "") return;
17238
+ const tooltip = document.createElement("div");
17239
+ tooltip.className = "reference-tooltip";
17240
+ tooltip.textContent = `\u2192 ${documentName}`;
17241
+ tooltip.style.cssText = `
17242
+ position: absolute;
17243
+ bottom: 100%;
17244
+ left: 50%;
17245
+ transform: translateX(-50%) translateY(-4px);
17246
+ padding: 4px 8px;
17247
+ background: rgba(0, 0, 0, 0.8);
17248
+ color: white;
17249
+ border-radius: 4px;
17250
+ font-size: 11px;
17251
+ white-space: nowrap;
17252
+ pointer-events: none;
17253
+ z-index: 1000;
17254
+ animation: fadeIn 0.2s ease;
17255
+ `;
17256
+ container.appendChild(tooltip);
17257
+ }
17258
+ function hideWidgetPreview(container) {
17259
+ const tooltip = container.querySelector(".reference-tooltip");
17260
+ if (tooltip) tooltip.remove();
17261
+ }
17305
17262
 
17306
17263
  // src/lib/media-shapes.ts
17307
17264
  import { isPdfMimeType } from "@semiont/api-client";
@@ -17353,402 +17310,154 @@ function saveSelectedShapeForSelectorType(selectorType, shape) {
17353
17310
  }
17354
17311
  }
17355
17312
 
17356
- // ../../node_modules/unist-util-is/lib/index.js
17357
- var convert = (
17358
- // Note: overloads in JSDoc can’t yet use different `@template`s.
17359
- /**
17360
- * @type {(
17361
- * (<Condition extends string>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & {type: Condition}) &
17362
- * (<Condition extends Props>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & Condition) &
17363
- * (<Condition extends TestFunction>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & Predicate<Condition, Node>) &
17364
- * ((test?: null | undefined) => (node?: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node) &
17365
- * ((test?: Test) => Check)
17366
- * )}
17367
- */
17368
- /**
17369
- * @param {Test} [test]
17370
- * @returns {Check}
17371
- */
17372
- (function(test) {
17373
- if (test === null || test === void 0) {
17374
- return ok;
17375
- }
17376
- if (typeof test === "function") {
17377
- return castFactory(test);
17378
- }
17379
- if (typeof test === "object") {
17380
- return Array.isArray(test) ? anyFactory(test) : (
17381
- // Cast because `ReadonlyArray` goes into the above but `isArray`
17382
- // narrows to `Array`.
17383
- propertiesFactory(
17384
- /** @type {Props} */
17385
- test
17386
- )
17387
- );
17388
- }
17389
- if (typeof test === "string") {
17390
- return typeFactory(test);
17391
- }
17392
- throw new Error("Expected function, string, or object as test");
17393
- })
17394
- );
17395
- function anyFactory(tests) {
17396
- const checks2 = [];
17397
- let index2 = -1;
17398
- while (++index2 < tests.length) {
17399
- checks2[index2] = convert(tests[index2]);
17313
+ // src/lib/annotation-overlay.ts
17314
+ import { getTextPositionSelector, getTargetSelector, getExactText, getBodySource as getBodySource2 } from "@semiont/api-client";
17315
+ function buildSourceToRenderedMap(markdownSource, container) {
17316
+ const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT);
17317
+ let renderedText = "";
17318
+ while (walker.nextNode()) {
17319
+ renderedText += walker.currentNode.textContent ?? "";
17400
17320
  }
17401
- return castFactory(any);
17402
- function any(...parameters) {
17403
- let index3 = -1;
17404
- while (++index3 < checks2.length) {
17405
- if (checks2[index3].apply(this, parameters)) return true;
17406
- }
17407
- return false;
17408
- }
17409
- }
17410
- function propertiesFactory(check) {
17411
- const checkAsRecord = (
17412
- /** @type {Record<string, unknown>} */
17413
- check
17414
- );
17415
- return castFactory(all2);
17416
- function all2(node2) {
17417
- const nodeAsRecord = (
17418
- /** @type {Record<string, unknown>} */
17419
- /** @type {unknown} */
17420
- node2
17421
- );
17422
- let key;
17423
- for (key in check) {
17424
- if (nodeAsRecord[key] !== checkAsRecord[key]) return false;
17321
+ const map3 = /* @__PURE__ */ new Map();
17322
+ let renderedPos = 0;
17323
+ let sourcePos = 0;
17324
+ while (sourcePos < markdownSource.length && renderedPos < renderedText.length) {
17325
+ if (markdownSource[sourcePos] === renderedText[renderedPos]) {
17326
+ map3.set(sourcePos, renderedPos);
17327
+ renderedPos++;
17328
+ sourcePos++;
17329
+ } else {
17330
+ sourcePos++;
17425
17331
  }
17426
- return true;
17427
- }
17428
- }
17429
- function typeFactory(check) {
17430
- return castFactory(type);
17431
- function type(node2) {
17432
- return node2 && node2.type === check;
17433
17332
  }
17434
- }
17435
- function castFactory(testFunction) {
17436
- return check;
17437
- function check(value, index2, parent) {
17438
- return Boolean(
17439
- looksLikeANode(value) && testFunction.call(
17440
- this,
17441
- value,
17442
- typeof index2 === "number" ? index2 : void 0,
17443
- parent || void 0
17444
- )
17445
- );
17333
+ while (sourcePos < markdownSource.length) {
17334
+ map3.set(sourcePos, renderedPos);
17335
+ sourcePos++;
17446
17336
  }
17337
+ return map3;
17447
17338
  }
17448
- function ok() {
17449
- return true;
17450
- }
17451
- function looksLikeANode(value) {
17452
- return value !== null && typeof value === "object" && "type" in value;
17453
- }
17454
-
17455
- // ../../node_modules/unist-util-visit-parents/lib/color.node.js
17456
- function color(d8) {
17457
- return "\x1B[33m" + d8 + "\x1B[39m";
17458
- }
17459
-
17460
- // ../../node_modules/unist-util-visit-parents/lib/index.js
17461
- var empty = [];
17462
- var CONTINUE = true;
17463
- var EXIT = false;
17464
- var SKIP = "skip";
17465
- function visitParents(tree, test, visitor, reverse) {
17466
- let check;
17467
- if (typeof test === "function" && typeof visitor !== "function") {
17468
- reverse = visitor;
17469
- visitor = test;
17470
- } else {
17471
- check = test;
17472
- }
17473
- const is2 = convert(check);
17474
- const step = reverse ? -1 : 1;
17475
- factory(tree, void 0, [])();
17476
- function factory(node2, index2, parents) {
17477
- const value = (
17478
- /** @type {Record<string, unknown>} */
17479
- node2 && typeof node2 === "object" ? node2 : {}
17480
- );
17481
- if (typeof value.type === "string") {
17482
- const name3 = (
17483
- // `hast`
17484
- typeof value.tagName === "string" ? value.tagName : (
17485
- // `xast`
17486
- typeof value.name === "string" ? value.name : void 0
17487
- )
17488
- );
17489
- Object.defineProperty(visit2, "name", {
17490
- value: "node (" + color(node2.type + (name3 ? "<" + name3 + ">" : "")) + ")"
17491
- });
17492
- }
17493
- return visit2;
17494
- function visit2() {
17495
- let result = empty;
17496
- let subresult;
17497
- let offset;
17498
- let grandparents;
17499
- if (!test || is2(node2, index2, parents[parents.length - 1] || void 0)) {
17500
- result = toResult(visitor(node2, parents));
17501
- if (result[0] === EXIT) {
17502
- return result;
17503
- }
17504
- }
17505
- if ("children" in node2 && node2.children) {
17506
- const nodeAsParent = (
17507
- /** @type {UnistParent} */
17508
- node2
17509
- );
17510
- if (nodeAsParent.children && result[0] !== SKIP) {
17511
- offset = (reverse ? nodeAsParent.children.length : -1) + step;
17512
- grandparents = parents.concat(nodeAsParent);
17513
- while (offset > -1 && offset < nodeAsParent.children.length) {
17514
- const child = nodeAsParent.children[offset];
17515
- subresult = factory(child, offset, grandparents)();
17516
- if (subresult[0] === EXIT) {
17517
- return subresult;
17518
- }
17519
- offset = typeof subresult[1] === "number" ? subresult[1] : offset + step;
17520
- }
17521
- }
17522
- }
17523
- return result;
17339
+ function buildTextNodeIndex(container) {
17340
+ const entries = [];
17341
+ const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT);
17342
+ let offset = 0;
17343
+ while (walker.nextNode()) {
17344
+ const node2 = walker.currentNode;
17345
+ const length = node2.textContent?.length ?? 0;
17346
+ entries.push({ node: node2, start: offset, end: offset + length });
17347
+ offset += length;
17348
+ }
17349
+ return entries;
17350
+ }
17351
+ function findTextNode(entries, renderedOffset) {
17352
+ let lo = 0;
17353
+ let hi = entries.length - 1;
17354
+ while (lo <= hi) {
17355
+ const mid = lo + hi >>> 1;
17356
+ const entry = entries[mid];
17357
+ if (renderedOffset < entry.start) {
17358
+ hi = mid - 1;
17359
+ } else if (renderedOffset >= entry.end) {
17360
+ lo = mid + 1;
17361
+ } else {
17362
+ return { node: entry.node, localOffset: renderedOffset - entry.start };
17524
17363
  }
17525
17364
  }
17365
+ return null;
17526
17366
  }
17527
- function toResult(value) {
17528
- if (Array.isArray(value)) {
17529
- return value;
17530
- }
17531
- if (typeof value === "number") {
17532
- return [CONTINUE, value];
17533
- }
17534
- return value === null || value === void 0 ? empty : [value];
17535
- }
17536
-
17537
- // ../../node_modules/unist-util-visit/lib/index.js
17538
- function visit(tree, testOrVisitor, visitorOrReverse, maybeReverse) {
17539
- let reverse;
17540
- let test;
17541
- let visitor;
17542
- if (typeof testOrVisitor === "function" && typeof visitorOrReverse !== "function") {
17543
- test = void 0;
17544
- visitor = testOrVisitor;
17545
- reverse = visitorOrReverse;
17546
- } else {
17547
- test = testOrVisitor;
17548
- visitor = visitorOrReverse;
17549
- reverse = maybeReverse;
17550
- }
17551
- visitParents(tree, test, overload, reverse);
17552
- function overload(node2, parents) {
17553
- const parent = parents[parents.length - 1];
17554
- const index2 = parent ? parent.children.indexOf(node2) : void 0;
17555
- return visitor(node2, index2, parent);
17556
- }
17557
- }
17558
-
17559
- // src/lib/rehype-render-annotations.ts
17560
- function buildAnnotationSpan(annotation, children) {
17561
- let className;
17562
- const annotationType = annotation.type;
17563
- if (annotation.type === "highlight") {
17564
- className = "annotation-highlight";
17565
- } else if (annotation.type === "assessment") {
17566
- className = "annotation-assessment";
17567
- } else if (annotation.type === "comment") {
17568
- className = "annotation-comment";
17569
- } else if (annotation.type === "tag") {
17570
- className = "annotation-tag";
17571
- } else if (annotation.type === "reference") {
17572
- className = "annotation-reference";
17573
- } else {
17574
- className = "annotation-reference";
17575
- }
17576
- return {
17577
- type: "element",
17578
- tagName: "span",
17579
- properties: {
17580
- className,
17581
- "data-annotation-id": annotation.id,
17582
- "data-annotation-type": annotationType
17583
- },
17584
- children
17585
- };
17586
- }
17587
- function rehypeRenderAnnotations() {
17588
- return (tree, file) => {
17589
- const originalSource = String(file);
17590
- visit(tree, "element", (element2) => {
17591
- const annotationsJson = element2.properties?.["data-annotations"];
17592
- if (!annotationsJson || typeof annotationsJson !== "string") {
17593
- return;
17594
- }
17595
- const annotations = JSON.parse(annotationsJson);
17596
- wrapCrossElementAnnotations(element2, annotations);
17597
- applyWithinTextNodeAnnotations(element2, annotations, originalSource);
17598
- delete element2.properties["data-annotations"];
17599
- });
17600
- };
17601
- }
17602
- function wrapCrossElementAnnotations(element2, annotations) {
17603
- const spans = analyzeChildSpans(element2, annotations);
17604
- if (spans.length === 0) return;
17605
- const sortedSpans = spans.sort((a15, b8) => {
17606
- const aLength = a15.endChildIndex - a15.startChildIndex;
17607
- const bLength = b8.endChildIndex - b8.startChildIndex;
17608
- return bLength - aLength;
17609
- });
17610
- for (const span of sortedSpans) {
17611
- wrapChildRange(element2, span);
17367
+ function resolveAnnotationRanges(annotations, offsetMap, textNodeIndex) {
17368
+ const ranges = /* @__PURE__ */ new Map();
17369
+ for (const ann of annotations) {
17370
+ const renderedStart = offsetMap.get(ann.offset);
17371
+ const renderedEnd = offsetMap.get(ann.offset + ann.length - 1);
17372
+ if (renderedStart === void 0 || renderedEnd === void 0) continue;
17373
+ const startInfo = findTextNode(textNodeIndex, renderedStart);
17374
+ const endInfo = findTextNode(textNodeIndex, renderedEnd + 1);
17375
+ if (!startInfo || !endInfo) continue;
17376
+ const range = document.createRange();
17377
+ range.setStart(startInfo.node, startInfo.localOffset);
17378
+ range.setEnd(endInfo.node, endInfo.localOffset);
17379
+ ranges.set(ann.id, { range, annotation: ann });
17612
17380
  }
17381
+ return ranges;
17613
17382
  }
17614
- function analyzeChildSpans(element2, annotations) {
17615
- const spans = [];
17616
- for (const ann of annotations) {
17617
- const annStart = ann.offset;
17618
- const annEnd = ann.offset + ann.length;
17619
- let startChildIndex = -1;
17620
- let endChildIndex = -1;
17621
- for (let i12 = 0; i12 < element2.children.length; i12++) {
17622
- const child = element2.children[i12];
17623
- const childRange = getNodeOffsetRange(child);
17624
- if (!childRange) continue;
17625
- const [childStart, childEnd] = childRange;
17626
- if (annStart < childEnd && annEnd > childStart) {
17627
- if (startChildIndex === -1) {
17628
- startChildIndex = i12;
17629
- }
17630
- endChildIndex = i12 + 1;
17383
+ function applyHighlights(ranges) {
17384
+ for (const [id2, { range, annotation }] of ranges) {
17385
+ const className = `annotation-${annotation.type}`;
17386
+ if (range.startContainer === range.endContainer) {
17387
+ const span = document.createElement("span");
17388
+ span.className = className;
17389
+ span.dataset.annotationId = id2;
17390
+ span.dataset.annotationType = annotation.type;
17391
+ try {
17392
+ range.surroundContents(span);
17393
+ } catch {
17394
+ wrapRangeTextNodes(range, id2, annotation);
17631
17395
  }
17396
+ continue;
17632
17397
  }
17633
- if (startChildIndex !== -1 && endChildIndex - startChildIndex > 1) {
17634
- spans.push({ annotation: ann, startChildIndex, endChildIndex });
17635
- }
17398
+ wrapRangeTextNodes(range, id2, annotation);
17636
17399
  }
17637
- return spans;
17638
17400
  }
17639
- function getNodeOffsetRange(node2) {
17640
- if (!node2) return null;
17641
- if ("position" in node2 && node2.position?.start.offset !== void 0 && node2.position?.end.offset !== void 0) {
17642
- return [node2.position.start.offset, node2.position.end.offset];
17643
- }
17644
- return null;
17645
- }
17646
- function wrapChildRange(element2, span) {
17647
- const { annotation, startChildIndex, endChildIndex } = span;
17648
- const childrenToWrap = element2.children.slice(startChildIndex, endChildIndex);
17649
- const wrapper = buildAnnotationSpan(annotation, childrenToWrap);
17650
- element2.children.splice(startChildIndex, endChildIndex - startChildIndex, wrapper);
17651
- }
17652
- function applyWithinTextNodeAnnotations(element2, annotations, originalSource) {
17653
- visit(element2, "text", (textNode, index2, parent) => {
17654
- if (index2 === void 0 || !parent || parent.type !== "element") {
17655
- return SKIP;
17656
- }
17657
- if (parent.properties?.["data-annotation-id"]) {
17658
- return SKIP;
17659
- }
17660
- const position3 = textNode.position || parent.position;
17661
- if (!position3) return SKIP;
17662
- const textStart = position3.start.offset;
17663
- const textEnd = position3.end.offset;
17664
- if (textStart === void 0 || textEnd === void 0) return SKIP;
17665
- const textContent = textNode.value;
17666
- const applicable = annotations.filter((ann) => {
17667
- const annStart = ann.offset;
17668
- const annEnd = ann.offset + ann.length;
17669
- return annStart < textEnd && annEnd > textStart;
17670
- });
17671
- if (applicable.length === 0) return SKIP;
17672
- const sourceTextInNode = originalSource.substring(textStart, textEnd);
17673
- const sourceToRendered = buildPositionMap(sourceTextInNode, textContent, textStart);
17674
- const segments = [];
17675
- let lastPos = 0;
17676
- for (const ann of applicable.sort((a15, b8) => a15.offset - b8.offset)) {
17677
- let relStart = sourceToRendered.get(ann.offset);
17678
- let relEnd = sourceToRendered.get(ann.offset + ann.length - 1);
17679
- if (relStart === void 0 || relEnd === void 0) continue;
17680
- relEnd = relEnd + 1;
17681
- relStart = Math.max(0, Math.min(relStart, textContent.length));
17682
- relEnd = Math.max(0, Math.min(relEnd, textContent.length));
17683
- if (relStart >= relEnd || relStart < lastPos) continue;
17684
- if (relStart > lastPos) {
17685
- segments.push({ type: "text", value: textContent.substring(lastPos, relStart) });
17686
- }
17687
- const annotationSpan = buildAnnotationSpan(ann, [
17688
- { type: "text", value: textContent.substring(relStart, relEnd) }
17689
- ]);
17690
- segments.push(annotationSpan);
17691
- lastPos = relEnd;
17692
- }
17693
- if (lastPos < textContent.length) {
17694
- segments.push({ type: "text", value: textContent.substring(lastPos) });
17695
- }
17696
- if (segments.length === 0) {
17697
- return SKIP;
17698
- } else if (segments.length === 1 && segments[0]) {
17699
- parent.children[index2] = segments[0];
17700
- } else {
17701
- parent.children[index2] = {
17702
- type: "element",
17703
- tagName: "span",
17704
- properties: {},
17705
- children: segments
17706
- };
17401
+ function wrapRangeTextNodes(range, id2, annotation) {
17402
+ const className = `annotation-${annotation.type}`;
17403
+ const walker = document.createTreeWalker(
17404
+ range.commonAncestorContainer,
17405
+ NodeFilter.SHOW_TEXT
17406
+ );
17407
+ const textNodes = [];
17408
+ while (walker.nextNode()) {
17409
+ const node2 = walker.currentNode;
17410
+ if (range.intersectsNode(node2)) {
17411
+ textNodes.push(node2);
17412
+ }
17413
+ }
17414
+ for (const textNode of textNodes) {
17415
+ const nodeRange = document.createRange();
17416
+ nodeRange.selectNodeContents(textNode);
17417
+ if (textNode === range.startContainer) {
17418
+ nodeRange.setStart(textNode, range.startOffset);
17419
+ }
17420
+ if (textNode === range.endContainer) {
17421
+ nodeRange.setEnd(textNode, range.endOffset);
17422
+ }
17423
+ const span = document.createElement("span");
17424
+ span.className = className;
17425
+ span.dataset.annotationId = id2;
17426
+ span.dataset.annotationType = annotation.type;
17427
+ try {
17428
+ nodeRange.surroundContents(span);
17429
+ } catch {
17707
17430
  }
17708
- return SKIP;
17709
- });
17431
+ }
17710
17432
  }
17711
- function buildPositionMap(sourceText, renderedText, baseOffset) {
17712
- const map3 = /* @__PURE__ */ new Map();
17713
- let renderedPos = 0;
17714
- let sourcePos = 0;
17715
- while (sourcePos < sourceText.length && renderedPos < renderedText.length) {
17716
- if (sourceText[sourcePos] === renderedText[renderedPos]) {
17717
- map3.set(baseOffset + sourcePos, renderedPos);
17718
- renderedPos++;
17719
- sourcePos++;
17720
- } else {
17721
- sourcePos++;
17433
+ function clearHighlights(container) {
17434
+ const spans = container.querySelectorAll("[data-annotation-id]");
17435
+ for (const span of spans) {
17436
+ const parent = span.parentNode;
17437
+ if (!parent) continue;
17438
+ while (span.firstChild) {
17439
+ parent.insertBefore(span.firstChild, span);
17722
17440
  }
17441
+ parent.removeChild(span);
17442
+ parent.normalize();
17723
17443
  }
17724
- while (sourcePos < sourceText.length) {
17725
- map3.set(baseOffset + sourcePos, renderedPos);
17726
- sourcePos++;
17727
- }
17728
- return map3;
17729
17444
  }
17730
-
17731
- // src/lib/remark-annotations.ts
17732
- function remarkAnnotations(options) {
17733
- const { annotations } = options;
17734
- return (tree, _file) => {
17735
- visit(tree, (node2) => {
17736
- if (!node2.position) return;
17737
- const nodeStart = node2.position.start.offset;
17738
- const nodeEnd = node2.position.end.offset;
17739
- if (nodeStart === void 0 || nodeEnd === void 0) return;
17740
- const overlapping = annotations.filter((ann) => {
17741
- const annStart = ann.offset;
17742
- const annEnd = ann.offset + ann.length;
17743
- return annStart < nodeEnd && annEnd > nodeStart;
17744
- });
17745
- if (overlapping.length > 0) {
17746
- if (!node2.data) node2.data = {};
17747
- if (!node2.data.hProperties) node2.data.hProperties = {};
17748
- node2.data.hProperties["data-annotations"] = JSON.stringify(overlapping);
17749
- }
17750
- });
17751
- };
17445
+ function toOverlayAnnotations(annotations) {
17446
+ return annotations.map((ann) => {
17447
+ const targetSelector = getTargetSelector(ann.target);
17448
+ const posSelector = getTextPositionSelector(targetSelector);
17449
+ const start2 = posSelector?.start ?? 0;
17450
+ const end = posSelector?.end ?? 0;
17451
+ const type = Object.values(ANNOTATORS).find((a15) => a15.matchesAnnotation(ann))?.internalType || "highlight";
17452
+ return {
17453
+ id: ann.id,
17454
+ exact: getExactText(targetSelector),
17455
+ offset: start2,
17456
+ length: end - start2,
17457
+ type,
17458
+ source: getBodySource2(ann.body)
17459
+ };
17460
+ });
17752
17461
  }
17753
17462
 
17754
17463
  // src/lib/resource-utils.ts
@@ -26432,7 +26141,7 @@ function scrollAnnotationIntoView(annotationId, rootElement, options = {}) {
26432
26141
  }
26433
26142
 
26434
26143
  // src/components/CodeMirrorRenderer.tsx
26435
- import { isHighlight as isHighlight2, isReference as isReference2, isResolvedReference as isResolvedReference2, isComment as isComment2, isAssessment, isTag as isTag3, getBodySource as getBodySource2 } from "@semiont/api-client";
26144
+ import { isHighlight as isHighlight2, isReference as isReference2, isResolvedReference as isResolvedReference2, isComment as isComment2, isAssessment, isTag as isTag3, getBodySource as getBodySource3 } from "@semiont/api-client";
26436
26145
  import { jsx as jsx8 } from "react/jsx-runtime";
26437
26146
  var updateAnnotationsEffect = StateEffect.define();
26438
26147
  var updateWidgetsEffect = StateEffect.define();
@@ -26447,8 +26156,14 @@ function convertSegmentPositions(segments, content4) {
26447
26156
  }
26448
26157
  }
26449
26158
  const convertPosition = (pos) => {
26450
- const crlfsBefore = crlfPositions.filter((crlfPos) => crlfPos < pos).length;
26451
- return pos - crlfsBefore;
26159
+ let lo = 0;
26160
+ let hi = crlfPositions.length;
26161
+ while (lo < hi) {
26162
+ const mid = lo + hi >>> 1;
26163
+ if (crlfPositions[mid] < pos) lo = mid + 1;
26164
+ else hi = mid;
26165
+ }
26166
+ return pos - lo;
26452
26167
  };
26453
26168
  return segments.map((seg) => ({
26454
26169
  ...seg,
@@ -26526,20 +26241,19 @@ function createAnnotationDecorationsField() {
26526
26241
  provide: (field) => EditorView.decorations.from(field)
26527
26242
  });
26528
26243
  }
26529
- function buildWidgetDecorations(_content, segments, generatingReferenceId, eventBus, getTargetDocumentName) {
26244
+ function buildWidgetDecorations(_content, segments, generatingReferenceId, getTargetDocumentName) {
26530
26245
  const builder = new RangeSetBuilder();
26531
26246
  const allAnnotatedSegments = segments.filter((s11) => s11.annotation).sort((a15, b8) => a15.end - b8.end);
26532
26247
  for (const segment of allAnnotatedSegments) {
26533
26248
  if (!segment.annotation) continue;
26534
26249
  const annotation = segment.annotation;
26535
26250
  if (isReference2(annotation)) {
26536
- const bodySource = getBodySource2(annotation.body);
26251
+ const bodySource = getBodySource3(annotation.body);
26537
26252
  const targetName = bodySource ? getTargetDocumentName?.(bodySource) : void 0;
26538
26253
  const isGenerating = generatingReferenceId ? annotation.id === generatingReferenceId : false;
26539
26254
  const widget = new ReferenceResolutionWidget(
26540
26255
  annotation,
26541
26256
  targetName,
26542
- eventBus,
26543
26257
  isGenerating
26544
26258
  );
26545
26259
  builder.add(
@@ -26563,7 +26277,6 @@ var widgetDecorationsField = StateField.define({
26563
26277
  effect.value.content,
26564
26278
  effect.value.segments,
26565
26279
  effect.value.generatingReferenceId,
26566
- effect.value.eventBus,
26567
26280
  effect.value.getTargetDocumentName
26568
26281
  );
26569
26282
  }
@@ -26579,7 +26292,6 @@ function CodeMirrorRenderer({
26579
26292
  editable: editable2 = false,
26580
26293
  newAnnotationIds,
26581
26294
  hoveredAnnotationId,
26582
- hoveredCommentId,
26583
26295
  scrollToAnnotationId,
26584
26296
  sourceView = false,
26585
26297
  showLineNumbers = false,
@@ -26594,10 +26306,16 @@ function CodeMirrorRenderer({
26594
26306
  const contentRef = useRef7(content4);
26595
26307
  const convertedSegments = convertSegmentPositions(segments, content4);
26596
26308
  const segmentsRef = useRef7(convertedSegments);
26309
+ const segmentsByIdRef = useRef7(/* @__PURE__ */ new Map());
26597
26310
  const lineNumbersCompartment = useRef7(new Compartment());
26598
26311
  const eventBusRef = useRef7(eventBus);
26599
26312
  const getTargetDocumentNameRef = useRef7(getTargetDocumentName);
26600
26313
  segmentsRef.current = segments;
26314
+ const segmentsById = /* @__PURE__ */ new Map();
26315
+ for (const s11 of segments) {
26316
+ if (s11.annotation) segmentsById.set(s11.annotation.id, s11);
26317
+ }
26318
+ segmentsByIdRef.current = segmentsById;
26601
26319
  eventBusRef.current = eventBus;
26602
26320
  getTargetDocumentNameRef.current = getTargetDocumentName;
26603
26321
  useEffect10(() => {
@@ -26627,7 +26345,7 @@ function CodeMirrorRenderer({
26627
26345
  const annotationElement = target.closest("[data-annotation-id]");
26628
26346
  const annotationId = annotationElement?.getAttribute("data-annotation-id");
26629
26347
  if (annotationId && eventBusRef.current) {
26630
- const segment = segmentsRef.current.find((s11) => s11.annotation?.id === annotationId);
26348
+ const segment = segmentsByIdRef.current.get(annotationId);
26631
26349
  if (segment?.annotation) {
26632
26350
  event.preventDefault();
26633
26351
  eventBusRef.current.get("attend:click").next({
@@ -26705,11 +26423,54 @@ function CodeMirrorRenderer({
26705
26423
  const annotationElement = target.closest("[data-annotation-id]");
26706
26424
  if (annotationElement) handleMouseLeave();
26707
26425
  };
26426
+ const handleWidgetClick = (e6) => {
26427
+ const target = e6.target;
26428
+ const widget = target.closest(".reference-preview-widget");
26429
+ if (!widget || widget.dataset.widgetGenerating === "true") return;
26430
+ e6.preventDefault();
26431
+ e6.stopPropagation();
26432
+ const annotationId = widget.dataset.widgetAnnotationId;
26433
+ const bodySource = widget.dataset.widgetBodySource;
26434
+ const isResolved = widget.dataset.widgetResolved === "true";
26435
+ if (!annotationId || !eventBusRef.current) return;
26436
+ if (isResolved && bodySource) {
26437
+ eventBusRef.current.get("navigation:reference-navigate").next({ documentId: bodySource });
26438
+ } else {
26439
+ const motivation = widget.dataset.widgetMotivation || "linking";
26440
+ eventBusRef.current.get("attend:click").next({ annotationId, motivation });
26441
+ }
26442
+ };
26443
+ const handleWidgetMouseEnter = (e6) => {
26444
+ const target = e6.target;
26445
+ const widget = target.closest(".reference-preview-widget");
26446
+ if (!widget || widget.dataset.widgetGenerating === "true") return;
26447
+ const indicator = widget.querySelector(".reference-indicator");
26448
+ if (indicator) indicator.style.opacity = "1";
26449
+ if (widget.dataset.widgetResolved === "true" && widget.dataset.widgetTargetName) {
26450
+ showWidgetPreview(widget, widget.dataset.widgetTargetName);
26451
+ }
26452
+ };
26453
+ const handleWidgetMouseLeave = (e6) => {
26454
+ const target = e6.target;
26455
+ const widget = target.closest(".reference-preview-widget");
26456
+ if (!widget) return;
26457
+ const indicator = widget.querySelector(".reference-indicator");
26458
+ if (indicator) indicator.style.opacity = "0.6";
26459
+ if (widget.dataset.widgetResolved === "true") {
26460
+ hideWidgetPreview(widget);
26461
+ }
26462
+ };
26708
26463
  container.addEventListener("mouseover", handleMouseOver);
26709
26464
  container.addEventListener("mouseout", handleMouseOut);
26465
+ container.addEventListener("click", handleWidgetClick);
26466
+ container.addEventListener("mouseenter", handleWidgetMouseEnter, true);
26467
+ container.addEventListener("mouseleave", handleWidgetMouseLeave, true);
26710
26468
  return () => {
26711
26469
  container.removeEventListener("mouseover", handleMouseOver);
26712
26470
  container.removeEventListener("mouseout", handleMouseOut);
26471
+ container.removeEventListener("click", handleWidgetClick);
26472
+ container.removeEventListener("mouseenter", handleWidgetMouseEnter, true);
26473
+ container.removeEventListener("mouseleave", handleWidgetMouseLeave, true);
26713
26474
  cleanupHover();
26714
26475
  view.destroy();
26715
26476
  viewRef.current = null;
@@ -26750,7 +26511,6 @@ function CodeMirrorRenderer({
26750
26511
  content: content4,
26751
26512
  segments: convertedSegments,
26752
26513
  generatingReferenceId,
26753
- eventBus: eventBusRef.current,
26754
26514
  getTargetDocumentName: getTargetDocumentNameRef.current
26755
26515
  })
26756
26516
  });
@@ -26783,34 +26543,6 @@ function CodeMirrorRenderer({
26783
26543
  element2.classList.remove("annotation-pulse");
26784
26544
  };
26785
26545
  }, [hoveredAnnotationId]);
26786
- useEffect10(() => {
26787
- if (!viewRef.current || !hoveredCommentId) return void 0;
26788
- const view = viewRef.current;
26789
- const element2 = view.contentDOM.querySelector(
26790
- `[data-annotation-id="${CSS.escape(hoveredCommentId)}"]`
26791
- );
26792
- if (!element2) return void 0;
26793
- const scrollContainer = element2.closest(".semiont-annotate-view__content") || element2.closest(".semiont-document-viewer__scrollable-body");
26794
- if (scrollContainer) {
26795
- const elementRect = element2.getBoundingClientRect();
26796
- const containerRect = scrollContainer.getBoundingClientRect();
26797
- const isVisible = elementRect.top >= containerRect.top && elementRect.bottom <= containerRect.bottom;
26798
- if (!isVisible) {
26799
- const elementTop = element2.offsetTop;
26800
- const containerHeight = scrollContainer.clientHeight;
26801
- const elementHeight = element2.offsetHeight;
26802
- const scrollTo = elementTop - containerHeight / 2 + elementHeight / 2;
26803
- scrollContainer.scrollTo({ top: scrollTo, behavior: "smooth" });
26804
- }
26805
- }
26806
- const timeoutId = setTimeout(() => {
26807
- element2.classList.add("annotation-pulse");
26808
- }, 100);
26809
- return () => {
26810
- clearTimeout(timeoutId);
26811
- element2.classList.remove("annotation-pulse");
26812
- };
26813
- }, [hoveredCommentId]);
26814
26546
  useEffect10(() => {
26815
26547
  if (!viewRef.current || !scrollToAnnotationId) return;
26816
26548
  scrollAnnotationIntoView(scrollToAnnotationId, viewRef.current.contentDOM);
@@ -30370,16 +30102,17 @@ function ProposeEntitiesModal({
30370
30102
  // src/components/resource/AnnotateView.tsx
30371
30103
  import { useRef as useRef12, useEffect as useEffect18, useCallback as useCallback13, lazy, Suspense } from "react";
30372
30104
  import { resourceUri as toResourceUri } from "@semiont/core";
30373
- import { getTextPositionSelector, getTextQuoteSelector, getTargetSelector, getMimeCategory, isPdfMimeType as isPdfMimeType2, extractContext, findTextWithContext } from "@semiont/api-client";
30105
+ import { getTextPositionSelector as getTextPositionSelector2, getTextQuoteSelector, getTargetSelector as getTargetSelector2, getMimeCategory, isPdfMimeType as isPdfMimeType2, extractContext, findTextWithContext, buildContentCache } from "@semiont/api-client";
30374
30106
  import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
30375
30107
  var PdfAnnotationCanvas = lazy(() => import("./PdfAnnotationCanvas.client-HNYRKFDS.mjs").then((mod) => ({ default: mod.PdfAnnotationCanvas })));
30376
30108
  function segmentTextWithAnnotations(content4, annotations) {
30377
30109
  if (!content4) {
30378
30110
  return [{ exact: "", start: 0, end: 0 }];
30379
30111
  }
30112
+ const cache2 = buildContentCache(content4);
30380
30113
  const normalizedAnnotations = annotations.map((ann) => {
30381
- const targetSelector = getTargetSelector(ann.target);
30382
- const posSelector = getTextPositionSelector(targetSelector);
30114
+ const targetSelector = getTargetSelector2(ann.target);
30115
+ const posSelector = getTextPositionSelector2(targetSelector);
30383
30116
  const quoteSelector = targetSelector ? getTextQuoteSelector(targetSelector) : null;
30384
30117
  let position4;
30385
30118
  if (quoteSelector) {
@@ -30388,8 +30121,8 @@ function segmentTextWithAnnotations(content4, annotations) {
30388
30121
  quoteSelector.exact,
30389
30122
  quoteSelector.prefix,
30390
30123
  quoteSelector.suffix,
30391
- posSelector?.start
30392
- // Position hint for fuzzy matching
30124
+ posSelector?.start,
30125
+ cache2
30393
30126
  );
30394
30127
  }
30395
30128
  const start2 = position4?.start ?? posSelector?.start ?? 0;
@@ -30452,7 +30185,7 @@ function AnnotateView({
30452
30185
  const { highlights, references, assessments, comments, tags: tags3 } = annotations;
30453
30186
  const allAnnotations = [...highlights, ...references, ...assessments, ...comments, ...tags3];
30454
30187
  const segments = segmentTextWithAnnotations(content4, allAnnotations);
30455
- const { selectedMotivation, selectedClick, selectedShape, hoveredAnnotationId, hoveredCommentId, scrollToAnnotationId } = uiState;
30188
+ const { selectedMotivation, selectedClick, selectedShape, hoveredAnnotationId, scrollToAnnotationId } = uiState;
30456
30189
  const onUIStateChangeRef = useRef12(onUIStateChange);
30457
30190
  onUIStateChangeRef.current = onUIStateChange;
30458
30191
  const handleToolbarSelectionChanged = useCallback13(({ motivation }) => {
@@ -30585,7 +30318,6 @@ function AnnotateView({
30585
30318
  editable: false,
30586
30319
  newAnnotationIds,
30587
30320
  ...hoveredAnnotationId !== void 0 && { hoveredAnnotationId },
30588
- ...hoveredCommentId !== void 0 && { hoveredCommentId },
30589
30321
  ...scrollToAnnotationId !== void 0 && { scrollToAnnotationId },
30590
30322
  sourceView: true,
30591
30323
  showLineNumbers,
@@ -30620,7 +30352,7 @@ function AnnotateView({
30620
30352
  drawingMode: selectedMotivation ? selectedShape : null,
30621
30353
  selectedMotivation,
30622
30354
  eventBus,
30623
- hoveredAnnotationId: hoveredCommentId || hoveredAnnotationId || null,
30355
+ hoveredAnnotationId: hoveredAnnotationId || null,
30624
30356
  hoverDelayMs
30625
30357
  }
30626
30358
  ) }) })
@@ -30647,7 +30379,7 @@ function AnnotateView({
30647
30379
  drawingMode: selectedMotivation ? selectedShape : null,
30648
30380
  selectedMotivation,
30649
30381
  eventBus,
30650
- hoveredAnnotationId: hoveredCommentId || hoveredAnnotationId || null,
30382
+ hoveredAnnotationId: hoveredAnnotationId || null,
30651
30383
  hoverDelayMs
30652
30384
  }
30653
30385
  ) })
@@ -30681,7 +30413,7 @@ import { useRef as useRef13, useCallback as useCallback14, useEffect as useEffec
30681
30413
  import { getAnnotationUriFromEvent } from "@semiont/core";
30682
30414
 
30683
30415
  // src/components/resource/event-formatting.ts
30684
- import { getExactText, getTargetSelector as getTargetSelector2 } from "@semiont/api-client";
30416
+ import { getExactText as getExactText2, getTargetSelector as getTargetSelector3 } from "@semiont/api-client";
30685
30417
  function formatEventType(type, t12, payload) {
30686
30418
  switch (type) {
30687
30419
  case "resource.created":
@@ -30792,8 +30524,8 @@ function getEventDisplayContent(event, annotations, allEvents) {
30792
30524
  );
30793
30525
  if (annotation?.target) {
30794
30526
  try {
30795
- const targetSelector = getTargetSelector2(annotation.target);
30796
- const exact = getExactText(targetSelector);
30527
+ const targetSelector = getTargetSelector3(annotation.target);
30528
+ const exact = getExactText2(targetSelector);
30797
30529
  if (exact) {
30798
30530
  return { exact: truncateText(exact), isQuoted: true, isTag: false };
30799
30531
  }
@@ -30810,7 +30542,7 @@ function getEventDisplayContent(event, annotations, allEvents) {
30810
30542
  try {
30811
30543
  const target = addedEvent.event.payload.annotation.target;
30812
30544
  if (typeof target !== "string" && target.selector) {
30813
- const exact = getExactText(target.selector);
30545
+ const exact = getExactText2(target.selector);
30814
30546
  if (exact) {
30815
30547
  return { exact: truncateText(exact), isQuoted: true, isTag: false };
30816
30548
  }
@@ -30824,7 +30556,7 @@ function getEventDisplayContent(event, annotations, allEvents) {
30824
30556
  try {
30825
30557
  const target = eventData.payload.annotation.target;
30826
30558
  if (typeof target !== "string" && target.selector) {
30827
- const exact = getExactText(target.selector);
30559
+ const exact = getExactText2(target.selector);
30828
30560
  if (exact) {
30829
30561
  return { exact: truncateText(exact), isQuoted: true, isTag: false };
30830
30562
  }
@@ -30844,8 +30576,8 @@ function getEventDisplayContent(event, annotations, allEvents) {
30844
30576
  );
30845
30577
  if (annotation?.target) {
30846
30578
  try {
30847
- const targetSelector = getTargetSelector2(annotation.target);
30848
- const exact = getExactText(targetSelector);
30579
+ const targetSelector = getTargetSelector3(annotation.target);
30580
+ const exact = getExactText2(targetSelector);
30849
30581
  if (exact) {
30850
30582
  return { exact: truncateText(exact), isQuoted: true, isTag: false };
30851
30583
  }
@@ -31098,10 +30830,10 @@ function AnnotationHistory({ rUri, hoveredAnnotationId, onEventHover, onEventCli
31098
30830
  }
31099
30831
 
31100
30832
  // src/components/resource/BrowseView.tsx
31101
- import { useEffect as useEffect22, useRef as useRef15, useCallback as useCallback15, lazy as lazy2, Suspense as Suspense2 } from "react";
30833
+ import { useEffect as useEffect22, useRef as useRef15, useCallback as useCallback15, useMemo as useMemo4, memo, lazy as lazy2, Suspense as Suspense2 } from "react";
31102
30834
 
31103
30835
  // ../../node_modules/devlop/lib/default.js
31104
- function ok2() {
30836
+ function ok() {
31105
30837
  }
31106
30838
  function unreachable() {
31107
30839
  }
@@ -31128,9 +30860,9 @@ function name2(name3, options) {
31128
30860
  // ../../node_modules/hast-util-whitespace/lib/index.js
31129
30861
  var re2 = /[ \t\n\f\r]/g;
31130
30862
  function whitespace(thing) {
31131
- return typeof thing === "object" ? thing.type === "text" ? empty2(thing.value) : false : empty2(thing);
30863
+ return typeof thing === "object" ? thing.type === "text" ? empty(thing.value) : false : empty(thing);
31132
30864
  }
31133
- function empty2(value) {
30865
+ function empty(value) {
31134
30866
  return value.replace(re2, "") === "";
31135
30867
  }
31136
30868
 
@@ -32668,7 +32400,7 @@ function mdxExpression(state, node2) {
32668
32400
  if (node2.data && node2.data.estree && state.evaluater) {
32669
32401
  const program = node2.data.estree;
32670
32402
  const expression = program.body[0];
32671
- ok2(expression.type === "ExpressionStatement");
32403
+ ok(expression.type === "ExpressionStatement");
32672
32404
  return (
32673
32405
  /** @type {Child | undefined} */
32674
32406
  state.evaluater.evaluateExpression(expression.expression)
@@ -32783,11 +32515,11 @@ function createJsxElementProps(state, node2) {
32783
32515
  if (attribute.data && attribute.data.estree && state.evaluater) {
32784
32516
  const program = attribute.data.estree;
32785
32517
  const expression = program.body[0];
32786
- ok2(expression.type === "ExpressionStatement");
32518
+ ok(expression.type === "ExpressionStatement");
32787
32519
  const objectExpression = expression.expression;
32788
- ok2(objectExpression.type === "ObjectExpression");
32520
+ ok(objectExpression.type === "ObjectExpression");
32789
32521
  const property = objectExpression.properties[0];
32790
- ok2(property.type === "SpreadElement");
32522
+ ok(property.type === "SpreadElement");
32791
32523
  Object.assign(
32792
32524
  props,
32793
32525
  state.evaluater.evaluateExpression(property.argument)
@@ -32802,7 +32534,7 @@ function createJsxElementProps(state, node2) {
32802
32534
  if (attribute.value.data && attribute.value.data.estree && state.evaluater) {
32803
32535
  const program = attribute.value.data.estree;
32804
32536
  const expression = program.body[0];
32805
- ok2(expression.type === "ExpressionStatement");
32537
+ ok(expression.type === "ExpressionStatement");
32806
32538
  value = state.evaluater.evaluateExpression(expression.expression);
32807
32539
  } else {
32808
32540
  crashEstree(state, node2.position);
@@ -32896,7 +32628,7 @@ function findComponentFromName(state, name3, allowExpression) {
32896
32628
  optional: false
32897
32629
  } : prop;
32898
32630
  }
32899
- ok2(node2, "always a result");
32631
+ ok(node2, "always a result");
32900
32632
  result = node2;
32901
32633
  } else {
32902
32634
  result = name2(name3) && !/^[a-z]/.test(name3) ? { type: "Identifier", name: name3 } : { type: "Literal", value: name3 };
@@ -40799,6 +40531,209 @@ function footer(state) {
40799
40531
  };
40800
40532
  }
40801
40533
 
40534
+ // ../../node_modules/unist-util-is/lib/index.js
40535
+ var convert = (
40536
+ // Note: overloads in JSDoc can’t yet use different `@template`s.
40537
+ /**
40538
+ * @type {(
40539
+ * (<Condition extends string>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & {type: Condition}) &
40540
+ * (<Condition extends Props>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & Condition) &
40541
+ * (<Condition extends TestFunction>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & Predicate<Condition, Node>) &
40542
+ * ((test?: null | undefined) => (node?: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node) &
40543
+ * ((test?: Test) => Check)
40544
+ * )}
40545
+ */
40546
+ /**
40547
+ * @param {Test} [test]
40548
+ * @returns {Check}
40549
+ */
40550
+ (function(test) {
40551
+ if (test === null || test === void 0) {
40552
+ return ok2;
40553
+ }
40554
+ if (typeof test === "function") {
40555
+ return castFactory(test);
40556
+ }
40557
+ if (typeof test === "object") {
40558
+ return Array.isArray(test) ? anyFactory(test) : (
40559
+ // Cast because `ReadonlyArray` goes into the above but `isArray`
40560
+ // narrows to `Array`.
40561
+ propertiesFactory(
40562
+ /** @type {Props} */
40563
+ test
40564
+ )
40565
+ );
40566
+ }
40567
+ if (typeof test === "string") {
40568
+ return typeFactory(test);
40569
+ }
40570
+ throw new Error("Expected function, string, or object as test");
40571
+ })
40572
+ );
40573
+ function anyFactory(tests) {
40574
+ const checks2 = [];
40575
+ let index2 = -1;
40576
+ while (++index2 < tests.length) {
40577
+ checks2[index2] = convert(tests[index2]);
40578
+ }
40579
+ return castFactory(any);
40580
+ function any(...parameters) {
40581
+ let index3 = -1;
40582
+ while (++index3 < checks2.length) {
40583
+ if (checks2[index3].apply(this, parameters)) return true;
40584
+ }
40585
+ return false;
40586
+ }
40587
+ }
40588
+ function propertiesFactory(check) {
40589
+ const checkAsRecord = (
40590
+ /** @type {Record<string, unknown>} */
40591
+ check
40592
+ );
40593
+ return castFactory(all2);
40594
+ function all2(node2) {
40595
+ const nodeAsRecord = (
40596
+ /** @type {Record<string, unknown>} */
40597
+ /** @type {unknown} */
40598
+ node2
40599
+ );
40600
+ let key;
40601
+ for (key in check) {
40602
+ if (nodeAsRecord[key] !== checkAsRecord[key]) return false;
40603
+ }
40604
+ return true;
40605
+ }
40606
+ }
40607
+ function typeFactory(check) {
40608
+ return castFactory(type);
40609
+ function type(node2) {
40610
+ return node2 && node2.type === check;
40611
+ }
40612
+ }
40613
+ function castFactory(testFunction) {
40614
+ return check;
40615
+ function check(value, index2, parent) {
40616
+ return Boolean(
40617
+ looksLikeANode(value) && testFunction.call(
40618
+ this,
40619
+ value,
40620
+ typeof index2 === "number" ? index2 : void 0,
40621
+ parent || void 0
40622
+ )
40623
+ );
40624
+ }
40625
+ }
40626
+ function ok2() {
40627
+ return true;
40628
+ }
40629
+ function looksLikeANode(value) {
40630
+ return value !== null && typeof value === "object" && "type" in value;
40631
+ }
40632
+
40633
+ // ../../node_modules/unist-util-visit-parents/lib/color.node.js
40634
+ function color(d8) {
40635
+ return "\x1B[33m" + d8 + "\x1B[39m";
40636
+ }
40637
+
40638
+ // ../../node_modules/unist-util-visit-parents/lib/index.js
40639
+ var empty2 = [];
40640
+ var CONTINUE = true;
40641
+ var EXIT = false;
40642
+ var SKIP = "skip";
40643
+ function visitParents(tree, test, visitor, reverse) {
40644
+ let check;
40645
+ if (typeof test === "function" && typeof visitor !== "function") {
40646
+ reverse = visitor;
40647
+ visitor = test;
40648
+ } else {
40649
+ check = test;
40650
+ }
40651
+ const is2 = convert(check);
40652
+ const step = reverse ? -1 : 1;
40653
+ factory(tree, void 0, [])();
40654
+ function factory(node2, index2, parents) {
40655
+ const value = (
40656
+ /** @type {Record<string, unknown>} */
40657
+ node2 && typeof node2 === "object" ? node2 : {}
40658
+ );
40659
+ if (typeof value.type === "string") {
40660
+ const name3 = (
40661
+ // `hast`
40662
+ typeof value.tagName === "string" ? value.tagName : (
40663
+ // `xast`
40664
+ typeof value.name === "string" ? value.name : void 0
40665
+ )
40666
+ );
40667
+ Object.defineProperty(visit2, "name", {
40668
+ value: "node (" + color(node2.type + (name3 ? "<" + name3 + ">" : "")) + ")"
40669
+ });
40670
+ }
40671
+ return visit2;
40672
+ function visit2() {
40673
+ let result = empty2;
40674
+ let subresult;
40675
+ let offset;
40676
+ let grandparents;
40677
+ if (!test || is2(node2, index2, parents[parents.length - 1] || void 0)) {
40678
+ result = toResult(visitor(node2, parents));
40679
+ if (result[0] === EXIT) {
40680
+ return result;
40681
+ }
40682
+ }
40683
+ if ("children" in node2 && node2.children) {
40684
+ const nodeAsParent = (
40685
+ /** @type {UnistParent} */
40686
+ node2
40687
+ );
40688
+ if (nodeAsParent.children && result[0] !== SKIP) {
40689
+ offset = (reverse ? nodeAsParent.children.length : -1) + step;
40690
+ grandparents = parents.concat(nodeAsParent);
40691
+ while (offset > -1 && offset < nodeAsParent.children.length) {
40692
+ const child = nodeAsParent.children[offset];
40693
+ subresult = factory(child, offset, grandparents)();
40694
+ if (subresult[0] === EXIT) {
40695
+ return subresult;
40696
+ }
40697
+ offset = typeof subresult[1] === "number" ? subresult[1] : offset + step;
40698
+ }
40699
+ }
40700
+ }
40701
+ return result;
40702
+ }
40703
+ }
40704
+ }
40705
+ function toResult(value) {
40706
+ if (Array.isArray(value)) {
40707
+ return value;
40708
+ }
40709
+ if (typeof value === "number") {
40710
+ return [CONTINUE, value];
40711
+ }
40712
+ return value === null || value === void 0 ? empty2 : [value];
40713
+ }
40714
+
40715
+ // ../../node_modules/unist-util-visit/lib/index.js
40716
+ function visit(tree, testOrVisitor, visitorOrReverse, maybeReverse) {
40717
+ let reverse;
40718
+ let test;
40719
+ let visitor;
40720
+ if (typeof testOrVisitor === "function" && typeof visitorOrReverse !== "function") {
40721
+ test = void 0;
40722
+ visitor = testOrVisitor;
40723
+ reverse = visitorOrReverse;
40724
+ } else {
40725
+ test = testOrVisitor;
40726
+ visitor = visitorOrReverse;
40727
+ reverse = maybeReverse;
40728
+ }
40729
+ visitParents(tree, test, overload, reverse);
40730
+ function overload(node2, parents) {
40731
+ const parent = parents[parents.length - 1];
40732
+ const index2 = parent ? parent.children.indexOf(node2) : void 0;
40733
+ return visitor(node2, index2, parent);
40734
+ }
40735
+ }
40736
+
40802
40737
  // ../../node_modules/mdast-util-to-hast/lib/state.js
40803
40738
  var own4 = {}.hasOwnProperty;
40804
40739
  var emptyOptions3 = {};
@@ -40948,7 +40883,7 @@ function toHast(tree, options) {
40948
40883
  const foot = footer(state);
40949
40884
  const result = Array.isArray(node2) ? { type: "root", children: node2 } : node2 || { type: "root", children: [] };
40950
40885
  if (foot) {
40951
- ok2("children" in result);
40886
+ ok("children" in result);
40952
40887
  result.children.push({ type: "text", value: "\n" }, foot);
40953
40888
  }
40954
40889
  return result;
@@ -41841,7 +41776,7 @@ var Processor = class _Processor extends CallableInstance {
41841
41776
  } else if (resolve) {
41842
41777
  resolve(file2);
41843
41778
  } else {
41844
- ok2(done, "`done` is defined if `resolve` is not");
41779
+ ok(done, "`done` is defined if `resolve` is not");
41845
41780
  done(void 0, file2);
41846
41781
  }
41847
41782
  }
@@ -41886,7 +41821,7 @@ var Processor = class _Processor extends CallableInstance {
41886
41821
  assertCompiler("processSync", this.compiler || this.Compiler);
41887
41822
  this.process(file, realDone);
41888
41823
  assertDone("processSync", "process", complete);
41889
- ok2(result, "we either bailed on an error or have a tree");
41824
+ ok(result, "we either bailed on an error or have a tree");
41890
41825
  return result;
41891
41826
  function realDone(error, file2) {
41892
41827
  complete = true;
@@ -41942,7 +41877,7 @@ var Processor = class _Processor extends CallableInstance {
41942
41877
  }
41943
41878
  return done ? executor(void 0, done) : new Promise(executor);
41944
41879
  function executor(resolve, reject) {
41945
- ok2(
41880
+ ok(
41946
41881
  typeof file !== "function",
41947
41882
  "`file` can\u2019t be a `done` anymore, we checked"
41948
41883
  );
@@ -41958,7 +41893,7 @@ var Processor = class _Processor extends CallableInstance {
41958
41893
  } else if (resolve) {
41959
41894
  resolve(resultingTree);
41960
41895
  } else {
41961
- ok2(done, "`done` is defined if `resolve` is not");
41896
+ ok(done, "`done` is defined if `resolve` is not");
41962
41897
  done(void 0, resultingTree, file2);
41963
41898
  }
41964
41899
  }
@@ -41986,7 +41921,7 @@ var Processor = class _Processor extends CallableInstance {
41986
41921
  let result;
41987
41922
  this.run(tree, file, realDone);
41988
41923
  assertDone("runSync", "run", complete);
41989
- ok2(result, "we either bailed on an error or have a tree");
41924
+ ok(result, "we either bailed on an error or have a tree");
41990
41925
  return result;
41991
41926
  function realDone(error, tree2) {
41992
41927
  bail(error);
@@ -42547,7 +42482,7 @@ function exitLiteralAutolinkHttp(token) {
42547
42482
  function exitLiteralAutolinkWww(token) {
42548
42483
  this.config.exit.data.call(this, token);
42549
42484
  const node2 = this.stack[this.stack.length - 1];
42550
- ok2(node2.type === "link");
42485
+ ok(node2.type === "link");
42551
42486
  node2.url = "http://" + this.sliceSerialize(token);
42552
42487
  }
42553
42488
  function exitLiteralAutolinkEmail(token) {
@@ -42658,7 +42593,7 @@ function enterFootnoteDefinition(token) {
42658
42593
  function exitFootnoteCallString(token) {
42659
42594
  const label = this.resume();
42660
42595
  const node2 = this.stack[this.stack.length - 1];
42661
- ok2(node2.type === "footnoteReference");
42596
+ ok(node2.type === "footnoteReference");
42662
42597
  node2.identifier = normalizeIdentifier(
42663
42598
  this.sliceSerialize(token)
42664
42599
  ).toLowerCase();
@@ -42670,7 +42605,7 @@ function exitFootnoteCall(token) {
42670
42605
  function exitFootnoteDefinitionLabelString(token) {
42671
42606
  const label = this.resume();
42672
42607
  const node2 = this.stack[this.stack.length - 1];
42673
- ok2(node2.type === "footnoteDefinition");
42608
+ ok(node2.type === "footnoteDefinition");
42674
42609
  node2.identifier = normalizeIdentifier(
42675
42610
  this.sliceSerialize(token)
42676
42611
  ).toLowerCase();
@@ -43877,7 +43812,7 @@ function gfmTableFromMarkdown() {
43877
43812
  }
43878
43813
  function enterTable(token) {
43879
43814
  const align = token._align;
43880
- ok2(align, "expected `_align` on table");
43815
+ ok(align, "expected `_align` on table");
43881
43816
  this.enter(
43882
43817
  {
43883
43818
  type: "table",
@@ -43909,7 +43844,7 @@ function exitCodeText(token) {
43909
43844
  value = value.replace(/\\([\\|])/g, replace2);
43910
43845
  }
43911
43846
  const node2 = this.stack[this.stack.length - 1];
43912
- ok2(node2.type === "inlineCode");
43847
+ ok(node2.type === "inlineCode");
43913
43848
  node2.value = value;
43914
43849
  this.exit(token);
43915
43850
  }
@@ -44028,14 +43963,14 @@ function gfmTaskListItemToMarkdown() {
44028
43963
  }
44029
43964
  function exitCheck(token) {
44030
43965
  const node2 = this.stack[this.stack.length - 2];
44031
- ok2(node2.type === "listItem");
43966
+ ok(node2.type === "listItem");
44032
43967
  node2.checked = token.type === "taskListCheckValueChecked";
44033
43968
  }
44034
43969
  function exitParagraphWithTaskListItem(token) {
44035
43970
  const parent = this.stack[this.stack.length - 2];
44036
43971
  if (parent && parent.type === "listItem" && typeof parent.checked === "boolean") {
44037
43972
  const node2 = this.stack[this.stack.length - 1];
44038
- ok2(node2.type === "paragraph");
43973
+ ok(node2.type === "paragraph");
44039
43974
  const head = node2.children[0];
44040
43975
  if (head && head.type === "text") {
44041
43976
  const siblings = parent.children;
@@ -45412,7 +45347,7 @@ function remarkGfm(options) {
45412
45347
 
45413
45348
  // src/components/resource/BrowseView.tsx
45414
45349
  import { resourceUri as toResourceUri2 } from "@semiont/core";
45415
- import { getExactText as getExactText2, getTextPositionSelector as getTextPositionSelector2, getTargetSelector as getTargetSelector3, getBodySource as getBodySource3, getMimeCategory as getMimeCategory2, isPdfMimeType as isPdfMimeType3 } from "@semiont/api-client";
45350
+ import { getMimeCategory as getMimeCategory2, isPdfMimeType as isPdfMimeType3 } from "@semiont/api-client";
45416
45351
 
45417
45352
  // src/components/viewers/ImageViewer.tsx
45418
45353
  import { jsx as jsx26 } from "react/jsx-runtime";
@@ -45433,26 +45368,18 @@ function ImageViewer({ resourceUri: resourceUri2, alt = "Resource image" }) {
45433
45368
  // src/components/resource/BrowseView.tsx
45434
45369
  import { jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
45435
45370
  var PdfAnnotationCanvas2 = lazy2(() => import("./PdfAnnotationCanvas.client-HNYRKFDS.mjs").then((mod) => ({ default: mod.PdfAnnotationCanvas })));
45436
- function prepareAnnotations(annotations) {
45437
- return annotations.map((ann) => {
45438
- const targetSelector = getTargetSelector3(ann.target);
45439
- const posSelector = getTextPositionSelector2(targetSelector);
45440
- const start2 = posSelector?.start ?? 0;
45441
- const end = posSelector?.end ?? 0;
45442
- const type = Object.values(ANNOTATORS).find((a15) => a15.matchesAnnotation(ann))?.internalType || "highlight";
45443
- return {
45444
- id: ann.id,
45445
- exact: getExactText2(targetSelector),
45446
- offset: start2,
45447
- // remark plugin expects 'offset'
45448
- length: end - start2,
45449
- // remark plugin expects 'length', not 'end'
45450
- type,
45451
- source: getBodySource3(ann.body)
45452
- };
45453
- });
45454
- }
45455
- function BrowseView({
45371
+ var MemoizedMarkdown = memo(function MemoizedMarkdown2({
45372
+ content: content4
45373
+ }) {
45374
+ return /* @__PURE__ */ jsx27(
45375
+ Markdown,
45376
+ {
45377
+ remarkPlugins: [remarkGfm],
45378
+ children: content4
45379
+ }
45380
+ );
45381
+ });
45382
+ var BrowseView = memo(function BrowseView2({
45456
45383
  content: content4,
45457
45384
  mimeType,
45458
45385
  resourceUri: resourceUri2,
@@ -45466,8 +45393,27 @@ function BrowseView({
45466
45393
  const containerRef = useRef15(null);
45467
45394
  const category = getMimeCategory2(mimeType);
45468
45395
  const { highlights, references, assessments, comments, tags: tags3 } = annotations;
45469
- const allAnnotations = [...highlights, ...references, ...assessments, ...comments, ...tags3];
45470
- const preparedAnnotations = prepareAnnotations(allAnnotations);
45396
+ const allAnnotations = useMemo4(
45397
+ () => [...highlights, ...references, ...assessments, ...comments, ...tags3],
45398
+ [highlights, references, assessments, comments, tags3]
45399
+ );
45400
+ const overlayAnnotations = useMemo4(
45401
+ () => toOverlayAnnotations(allAnnotations),
45402
+ [allAnnotations]
45403
+ );
45404
+ const offsetMapRef = useRef15(null);
45405
+ useEffect22(() => {
45406
+ if (!containerRef.current) return;
45407
+ offsetMapRef.current = buildSourceToRenderedMap(content4, containerRef.current);
45408
+ }, [content4]);
45409
+ useEffect22(() => {
45410
+ if (!containerRef.current || !offsetMapRef.current || overlayAnnotations.length === 0) return;
45411
+ const container = containerRef.current;
45412
+ const textNodeIndex = buildTextNodeIndex(container);
45413
+ const ranges = resolveAnnotationRanges(overlayAnnotations, offsetMapRef.current, textNodeIndex);
45414
+ applyHighlights(ranges);
45415
+ return () => clearHighlights(container);
45416
+ }, [overlayAnnotations]);
45471
45417
  useEffect22(() => {
45472
45418
  if (!containerRef.current) return;
45473
45419
  const container = containerRef.current;
@@ -45546,19 +45492,7 @@ function BrowseView({
45546
45492
  annotators: ANNOTATORS
45547
45493
  }
45548
45494
  ),
45549
- /* @__PURE__ */ jsx27("div", { ref: containerRef, className: "semiont-browse-view__content", children: /* @__PURE__ */ jsx27(
45550
- Markdown,
45551
- {
45552
- remarkPlugins: [
45553
- remarkGfm,
45554
- [remarkAnnotations, { annotations: preparedAnnotations }]
45555
- ],
45556
- rehypePlugins: [
45557
- rehypeRenderAnnotations
45558
- ],
45559
- children: content4
45560
- }
45561
- ) })
45495
+ /* @__PURE__ */ jsx27("div", { ref: containerRef, className: "semiont-browse-view__content", children: /* @__PURE__ */ jsx27(MemoizedMarkdown, { content: content4 }) })
45562
45496
  ] });
45563
45497
  case "image":
45564
45498
  if (isPdfMimeType3(mimeType)) {
@@ -45623,10 +45557,10 @@ function BrowseView({
45623
45557
  )
45624
45558
  ] }) });
45625
45559
  }
45626
- }
45560
+ });
45627
45561
 
45628
45562
  // src/components/resource/ResourceViewer.tsx
45629
- import { useState as useState17, useEffect as useEffect23, useCallback as useCallback16, useRef as useRef16 } from "react";
45563
+ import { useState as useState17, useEffect as useEffect23, useCallback as useCallback16, useRef as useRef16, useMemo as useMemo5 } from "react";
45630
45564
  import { resourceUri } from "@semiont/core";
45631
45565
  import { getExactText as getExactText3, getTargetSelector as getTargetSelector4, isHighlight as isHighlight4, isAssessment as isAssessment3, isReference as isReference4, isComment as isComment4, isTag as isTag5, getBodySource as getBodySource4 } from "@semiont/api-client";
45632
45566
  import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
@@ -45741,7 +45675,6 @@ function ResourceViewer({
45741
45675
  const [jsonLdAnnotation, setJsonLdAnnotation] = useState17(null);
45742
45676
  const [deleteConfirmation, setDeleteConfirmation] = useState17(null);
45743
45677
  const hoveredAnnotationId = hoveredAnnotationIdProp ?? null;
45744
- const [hoveredCommentId, _setHoveredCommentId] = useState17(null);
45745
45678
  const [scrollToAnnotationId, setScrollToAnnotationId] = useState17(null);
45746
45679
  const [_focusedAnnotationId, setFocusedAnnotationId] = useState17(null);
45747
45680
  const focusAnnotation = useCallback16((annotationId) => {
@@ -45829,7 +45762,10 @@ function ResourceViewer({
45829
45762
  // Annotation clicks
45830
45763
  "attend:click": handleAnnotationClickEvent
45831
45764
  });
45832
- const annotationsCollection = { highlights, references, assessments, comments, tags: tags3 };
45765
+ const annotationsCollection = useMemo5(
45766
+ () => ({ highlights, references, assessments, comments, tags: tags3 }),
45767
+ [highlights, references, assessments, comments, tags3]
45768
+ );
45833
45769
  const uiState = {
45834
45770
  selectedMotivation,
45835
45771
  selectedClick,
@@ -45869,7 +45805,6 @@ function ResourceViewer({
45869
45805
  mimeType,
45870
45806
  resourceUri: resource["@id"],
45871
45807
  annotations: annotationsCollection,
45872
- hoveredCommentId,
45873
45808
  selectedClick,
45874
45809
  hoverDelayMs,
45875
45810
  annotateMode
@@ -46019,7 +45954,7 @@ var AssessmentEntry = forwardRef(
46019
45954
  );
46020
45955
 
46021
45956
  // src/components/resource/panels/AssessmentPanel.tsx
46022
- import { useState as useState19, useEffect as useEffect25, useRef as useRef17, useCallback as useCallback18, useMemo as useMemo4 } from "react";
45957
+ import { useState as useState19, useEffect as useEffect25, useRef as useRef17, useCallback as useCallback18, useMemo as useMemo6 } from "react";
46023
45958
  import { getTextPositionSelector as getTextPositionSelector3, getTargetSelector as getTargetSelector5 } from "@semiont/api-client";
46024
45959
 
46025
45960
  // src/components/resource/panels/AssistSection.tsx
@@ -46269,7 +46204,7 @@ function AssessmentPanel({
46269
46204
  const [focusedAnnotationId, setFocusedAnnotationId] = useState19(null);
46270
46205
  const containerRef = useRef17(null);
46271
46206
  const entryRefs = useRef17(/* @__PURE__ */ new Map());
46272
- const sortedAnnotations = useMemo4(() => {
46207
+ const sortedAnnotations = useMemo6(() => {
46273
46208
  return [...annotations].sort((a15, b8) => {
46274
46209
  const aSelector = getTextPositionSelector3(getTargetSelector5(a15.target));
46275
46210
  const bSelector = getTextPositionSelector3(getTargetSelector5(b8.target));
@@ -46630,7 +46565,7 @@ var CommentEntry = forwardRef2(
46630
46565
  );
46631
46566
 
46632
46567
  // src/components/resource/panels/CommentsPanel.tsx
46633
- import { useState as useState21, useEffect as useEffect27, useRef as useRef19, useCallback as useCallback19, useMemo as useMemo5 } from "react";
46568
+ import { useState as useState21, useEffect as useEffect27, useRef as useRef19, useCallback as useCallback19, useMemo as useMemo7 } from "react";
46634
46569
  import { getTextPositionSelector as getTextPositionSelector4, getTargetSelector as getTargetSelector6 } from "@semiont/api-client";
46635
46570
  import { jsx as jsx35, jsxs as jsxs25 } from "react/jsx-runtime";
46636
46571
  function getSelectorDisplayText2(selector) {
@@ -46662,7 +46597,7 @@ function CommentsPanel({
46662
46597
  const [focusedAnnotationId, setFocusedAnnotationId] = useState21(null);
46663
46598
  const containerRef = useRef19(null);
46664
46599
  const entryRefs = useRef19(/* @__PURE__ */ new Map());
46665
- const sortedAnnotations = useMemo5(() => {
46600
+ const sortedAnnotations = useMemo7(() => {
46666
46601
  return [...annotations].sort((a15, b8) => {
46667
46602
  const aSelector = getTextPositionSelector4(getTargetSelector6(a15.target));
46668
46603
  const bSelector = getTextPositionSelector4(getTargetSelector6(b8.target));
@@ -46873,7 +46808,7 @@ var HighlightEntry = forwardRef3(
46873
46808
  );
46874
46809
 
46875
46810
  // src/components/resource/panels/HighlightPanel.tsx
46876
- import { useEffect as useEffect28, useState as useState22, useRef as useRef20, useCallback as useCallback20, useMemo as useMemo6 } from "react";
46811
+ import { useEffect as useEffect28, useState as useState22, useRef as useRef20, useCallback as useCallback20, useMemo as useMemo8 } from "react";
46877
46812
  import { getTextPositionSelector as getTextPositionSelector5, getTargetSelector as getTargetSelector7 } from "@semiont/api-client";
46878
46813
  import { jsx as jsx36, jsxs as jsxs27 } from "react/jsx-runtime";
46879
46814
  function HighlightPanel({
@@ -46891,7 +46826,7 @@ function HighlightPanel({
46891
46826
  const [focusedAnnotationId, setFocusedAnnotationId] = useState22(null);
46892
46827
  const containerRef = useRef20(null);
46893
46828
  const entryRefs = useRef20(/* @__PURE__ */ new Map());
46894
- const sortedAnnotations = useMemo6(() => {
46829
+ const sortedAnnotations = useMemo8(() => {
46895
46830
  return [...annotations].sort((a15, b8) => {
46896
46831
  const aSelector = getTextPositionSelector5(getTargetSelector7(a15.target));
46897
46832
  const bSelector = getTextPositionSelector5(getTargetSelector7(b8.target));
@@ -47217,7 +47152,7 @@ var ReferenceEntry = forwardRef4(
47217
47152
  );
47218
47153
 
47219
47154
  // src/components/resource/panels/ReferencesPanel.tsx
47220
- import { useState as useState23, useRef as useRef22, useEffect as useEffect30, useCallback as useCallback21, useMemo as useMemo7 } from "react";
47155
+ import { useState as useState23, useRef as useRef22, useEffect as useEffect30, useCallback as useCallback21, useMemo as useMemo9 } from "react";
47221
47156
  import { getTextPositionSelector as getTextPositionSelector6, getTargetSelector as getTargetSelector9 } from "@semiont/api-client";
47222
47157
  import { Fragment as Fragment8, jsx as jsx39, jsxs as jsxs30 } from "react/jsx-runtime";
47223
47158
  function getSelectorDisplayText3(selector) {
@@ -47267,7 +47202,7 @@ function ReferencesPanel({
47267
47202
  localStorage.setItem("assist-section-expanded-reference", String(isAssistExpanded));
47268
47203
  }, [isAssistExpanded]);
47269
47204
  const entryRefs = useRef22(/* @__PURE__ */ new Map());
47270
- const sortedAnnotations = useMemo7(() => {
47205
+ const sortedAnnotations = useMemo9(() => {
47271
47206
  return [...annotations].sort((a15, b8) => {
47272
47207
  const aSelector = getTextPositionSelector6(getTargetSelector9(a15.target));
47273
47208
  const bSelector = getTextPositionSelector6(getTargetSelector9(b8.target));
@@ -47775,7 +47710,7 @@ var TagEntry = forwardRef5(
47775
47710
  );
47776
47711
 
47777
47712
  // src/components/resource/panels/TaggingPanel.tsx
47778
- import { useState as useState24, useEffect as useEffect31, useRef as useRef23, useCallback as useCallback22, useMemo as useMemo8 } from "react";
47713
+ import { useState as useState24, useEffect as useEffect31, useRef as useRef23, useCallback as useCallback22, useMemo as useMemo10 } from "react";
47779
47714
  import { getTextPositionSelector as getTextPositionSelector7, getTargetSelector as getTargetSelector10 } from "@semiont/api-client";
47780
47715
  import { Fragment as Fragment10, jsx as jsx43, jsxs as jsxs34 } from "react/jsx-runtime";
47781
47716
  function getSelectorDisplayText4(selector) {
@@ -47824,7 +47759,7 @@ function TaggingPanel({
47824
47759
  "attend:click": handleAnnotationClick
47825
47760
  });
47826
47761
  const entryRefs = useRef23(/* @__PURE__ */ new Map());
47827
- const sortedAnnotations = useMemo8(() => {
47762
+ const sortedAnnotations = useMemo10(() => {
47828
47763
  return [...annotations].sort((a15, b8) => {
47829
47764
  const aSelector = getTextPositionSelector7(getTargetSelector10(a15.target));
47830
47765
  const bSelector = getTextPositionSelector7(getTargetSelector10(b8.target));
@@ -48593,16 +48528,16 @@ function SimpleNavigation({
48593
48528
  import { useCallback as useCallback29, useState as useState31, useRef as useRef30, useEffect as useEffect39 } from "react";
48594
48529
 
48595
48530
  // ../../node_modules/@dnd-kit/core/dist/core.esm.js
48596
- import React20, { createContext as createContext7, useContext as useContext7, useEffect as useEffect36, useState as useState29, useCallback as useCallback26, useMemo as useMemo10, useRef as useRef27, memo, useReducer, cloneElement, forwardRef as forwardRef6 } from "react";
48531
+ import React20, { createContext as createContext7, useContext as useContext7, useEffect as useEffect36, useState as useState29, useCallback as useCallback26, useMemo as useMemo12, useRef as useRef27, memo as memo2, useReducer, cloneElement, forwardRef as forwardRef6 } from "react";
48597
48532
  import { createPortal, unstable_batchedUpdates } from "react-dom";
48598
48533
 
48599
48534
  // ../../node_modules/@dnd-kit/utilities/dist/utilities.esm.js
48600
- import { useMemo as useMemo9, useLayoutEffect, useEffect as useEffect35, useRef as useRef26, useCallback as useCallback24 } from "react";
48535
+ import { useMemo as useMemo11, useLayoutEffect, useEffect as useEffect35, useRef as useRef26, useCallback as useCallback24 } from "react";
48601
48536
  function useCombinedRefs() {
48602
48537
  for (var _len = arguments.length, refs = new Array(_len), _key = 0; _key < _len; _key++) {
48603
48538
  refs[_key] = arguments[_key];
48604
48539
  }
48605
- return useMemo9(
48540
+ return useMemo11(
48606
48541
  () => (node2) => {
48607
48542
  refs.forEach((ref) => ref(node2));
48608
48543
  },
@@ -48705,7 +48640,7 @@ function useLatestValue(value, dependencies) {
48705
48640
  }
48706
48641
  function useLazyMemo(callback, dependencies) {
48707
48642
  const valueRef = useRef26();
48708
- return useMemo9(
48643
+ return useMemo11(
48709
48644
  () => {
48710
48645
  const newValue = callback(valueRef.current);
48711
48646
  valueRef.current = newValue;
@@ -48739,7 +48674,7 @@ function usePrevious(value) {
48739
48674
  }
48740
48675
  var ids = {};
48741
48676
  function useUniqueId(prefix, value) {
48742
- return useMemo9(() => {
48677
+ return useMemo11(() => {
48743
48678
  if (value) {
48744
48679
  return value;
48745
48680
  }
@@ -49011,7 +48946,7 @@ function Accessibility(_ref) {
49011
48946
  useEffect36(() => {
49012
48947
  setMounted(true);
49013
48948
  }, []);
49014
- useDndMonitor(useMemo10(() => ({
48949
+ useDndMonitor(useMemo12(() => ({
49015
48950
  onDragStart(_ref2) {
49016
48951
  let {
49017
48952
  active
@@ -49089,7 +49024,7 @@ var Action;
49089
49024
  function noop() {
49090
49025
  }
49091
49026
  function useSensor(sensor, options) {
49092
- return useMemo10(
49027
+ return useMemo12(
49093
49028
  () => ({
49094
49029
  sensor,
49095
49030
  options: options != null ? options : {}
@@ -49102,7 +49037,7 @@ function useSensors() {
49102
49037
  for (var _len = arguments.length, sensors = new Array(_len), _key = 0; _key < _len; _key++) {
49103
49038
  sensors[_key] = arguments[_key];
49104
49039
  }
49105
- return useMemo10(
49040
+ return useMemo12(
49106
49041
  () => [...sensors].filter((sensor) => sensor != null),
49107
49042
  // eslint-disable-next-line react-hooks/exhaustive-deps
49108
49043
  [...sensors]
@@ -50352,7 +50287,7 @@ function useAutoScroller(_ref) {
50352
50287
  x: 0,
50353
50288
  y: 0
50354
50289
  });
50355
- const rect = useMemo10(() => {
50290
+ const rect = useMemo12(() => {
50356
50291
  switch (activator) {
50357
50292
  case AutoScrollActivator.Pointer:
50358
50293
  return pointerCoordinates ? {
@@ -50375,7 +50310,7 @@ function useAutoScroller(_ref) {
50375
50310
  const scrollTop = scrollSpeed.current.y * scrollDirection.current.y;
50376
50311
  scrollContainer.scrollBy(scrollLeft, scrollTop);
50377
50312
  }, []);
50378
- const sortedScrollableAncestors = useMemo10(() => order2 === TraversalOrder.TreeOrder ? [...scrollableAncestors].reverse() : scrollableAncestors, [order2, scrollableAncestors]);
50313
+ const sortedScrollableAncestors = useMemo12(() => order2 === TraversalOrder.TreeOrder ? [...scrollableAncestors].reverse() : scrollableAncestors, [order2, scrollableAncestors]);
50379
50314
  useEffect36(
50380
50315
  () => {
50381
50316
  if (!enabled || !scrollableAncestors.length || !rect) {
@@ -50489,7 +50424,7 @@ function useCachedNode(draggableNodes, id2) {
50489
50424
  }, [node2, id2]);
50490
50425
  }
50491
50426
  function useCombineActivators(sensors, getSyntheticHandler) {
50492
- return useMemo10(() => sensors.reduce((accumulator, sensor) => {
50427
+ return useMemo12(() => sensors.reduce((accumulator, sensor) => {
50493
50428
  const {
50494
50429
  sensor: Sensor
50495
50430
  } = sensor;
@@ -50637,7 +50572,7 @@ function useMutationObserver(_ref) {
50637
50572
  disabled
50638
50573
  } = _ref;
50639
50574
  const handleMutations = useEvent(callback);
50640
- const mutationObserver = useMemo10(() => {
50575
+ const mutationObserver = useMemo12(() => {
50641
50576
  if (disabled || typeof window === "undefined" || typeof window.MutationObserver === "undefined") {
50642
50577
  return void 0;
50643
50578
  }
@@ -50657,7 +50592,7 @@ function useResizeObserver(_ref) {
50657
50592
  disabled
50658
50593
  } = _ref;
50659
50594
  const handleResize = useEvent(callback);
50660
- const resizeObserver = useMemo10(
50595
+ const resizeObserver = useMemo12(
50661
50596
  () => {
50662
50597
  if (disabled || typeof window === "undefined" || typeof window.ResizeObserver === "undefined") {
50663
50598
  return void 0;
@@ -50799,7 +50734,7 @@ function useScrollOffsets(elements) {
50799
50734
  });
50800
50735
  }
50801
50736
  }, [handleScroll, elements]);
50802
- return useMemo10(() => {
50737
+ return useMemo12(() => {
50803
50738
  if (elements.length) {
50804
50739
  return scrollCoordinates ? Array.from(scrollCoordinates.values()).reduce((acc, coordinates) => add(acc, coordinates), defaultCoordinates) : getScrollOffsets(elements);
50805
50740
  }
@@ -50858,7 +50793,7 @@ function useSensorSetup(sensors) {
50858
50793
  );
50859
50794
  }
50860
50795
  function useSyntheticListeners(listeners, id2) {
50861
- return useMemo10(() => {
50796
+ return useMemo12(() => {
50862
50797
  return listeners.reduce((acc, _ref) => {
50863
50798
  let {
50864
50799
  eventName,
@@ -50872,7 +50807,7 @@ function useSyntheticListeners(listeners, id2) {
50872
50807
  }, [listeners, id2]);
50873
50808
  }
50874
50809
  function useWindowRect(element2) {
50875
- return useMemo10(() => element2 ? getWindowClientRect(element2) : null, [element2]);
50810
+ return useMemo12(() => element2 ? getWindowClientRect(element2) : null, [element2]);
50876
50811
  }
50877
50812
  var defaultValue$2 = [];
50878
50813
  function useRects(elements, measure) {
@@ -50944,7 +50879,7 @@ function useDragOverlayMeasuring(_ref) {
50944
50879
  setRect(node2 ? measure(node2) : null);
50945
50880
  }, [measure, resizeObserver]);
50946
50881
  const [nodeRef, setRef] = useNodeRef(handleNodeChange);
50947
- return useMemo10(() => ({
50882
+ return useMemo12(() => ({
50948
50883
  nodeRef,
50949
50884
  rect,
50950
50885
  setRef
@@ -51221,7 +51156,7 @@ function applyModifiers(modifiers2, _ref) {
51221
51156
  }, transform) : transform;
51222
51157
  }
51223
51158
  function useMeasuringConfiguration(config) {
51224
- return useMemo10(
51159
+ return useMemo12(
51225
51160
  () => ({
51226
51161
  draggable: {
51227
51162
  ...defaultMeasuringConfiguration.draggable,
@@ -51299,7 +51234,7 @@ var Status;
51299
51234
  Status2[Status2["Initializing"] = 1] = "Initializing";
51300
51235
  Status2[Status2["Initialized"] = 2] = "Initialized";
51301
51236
  })(Status || (Status = {}));
51302
- var DndContext = /* @__PURE__ */ memo(function DndContext2(_ref) {
51237
+ var DndContext = /* @__PURE__ */ memo2(function DndContext2(_ref) {
51303
51238
  var _sensorContext$curren, _dragOverlay$nodeRef$, _dragOverlay$rect, _over$rect;
51304
51239
  let {
51305
51240
  id: id2,
@@ -51332,7 +51267,7 @@ var DndContext = /* @__PURE__ */ memo(function DndContext2(_ref) {
51332
51267
  initial: null,
51333
51268
  translated: null
51334
51269
  });
51335
- const active = useMemo10(() => {
51270
+ const active = useMemo12(() => {
51336
51271
  var _node$data;
51337
51272
  return activeId != null ? {
51338
51273
  id: activeId,
@@ -51346,7 +51281,7 @@ var DndContext = /* @__PURE__ */ memo(function DndContext2(_ref) {
51346
51281
  const [activatorEvent, setActivatorEvent] = useState29(null);
51347
51282
  const latestProps = useLatestValue(props, Object.values(props));
51348
51283
  const draggableDescribedById = useUniqueId("DndDescribedBy", id2);
51349
- const enabledDroppableContainers = useMemo10(() => droppableContainers.getEnabled(), [droppableContainers]);
51284
+ const enabledDroppableContainers = useMemo12(() => droppableContainers.getEnabled(), [droppableContainers]);
51350
51285
  const measuringConfiguration = useMeasuringConfiguration(measuring);
51351
51286
  const {
51352
51287
  droppableRects,
@@ -51358,7 +51293,7 @@ var DndContext = /* @__PURE__ */ memo(function DndContext2(_ref) {
51358
51293
  config: measuringConfiguration.droppable
51359
51294
  });
51360
51295
  const activeNode = useCachedNode(draggableNodes, activeId);
51361
- const activationCoordinates = useMemo10(() => activatorEvent ? getEventCoordinates(activatorEvent) : null, [activatorEvent]);
51296
+ const activationCoordinates = useMemo12(() => activatorEvent ? getEventCoordinates(activatorEvent) : null, [activatorEvent]);
51362
51297
  const autoScrollOptions = getAutoScrollerOptions();
51363
51298
  const initialActiveNodeRect = useInitialRect(activeNode, measuringConfiguration.draggable.measure);
51364
51299
  useLayoutShiftScrollCompensation({
@@ -51729,7 +51664,7 @@ var DndContext = /* @__PURE__ */ memo(function DndContext2(_ref) {
51729
51664
  scrollableAncestors,
51730
51665
  scrollableAncestorRects
51731
51666
  });
51732
- const publicContext = useMemo10(() => {
51667
+ const publicContext = useMemo12(() => {
51733
51668
  const context = {
51734
51669
  active,
51735
51670
  activeNode,
@@ -51751,7 +51686,7 @@ var DndContext = /* @__PURE__ */ memo(function DndContext2(_ref) {
51751
51686
  };
51752
51687
  return context;
51753
51688
  }, [active, activeNode, activeNodeRect, activatorEvent, collisions, containerNodeRect, dragOverlay, draggableNodes, droppableContainers, droppableRects, over, measureDroppableContainers, scrollableAncestors, scrollableAncestorRects, measuringConfiguration, measuringScheduled, windowRect2]);
51754
- const internalContext = useMemo10(() => {
51689
+ const internalContext = useMemo12(() => {
51755
51690
  const context = {
51756
51691
  activatorEvent,
51757
51692
  activators,
@@ -51846,7 +51781,7 @@ function useDraggable(_ref) {
51846
51781
  // eslint-disable-next-line react-hooks/exhaustive-deps
51847
51782
  [draggableNodes, id2]
51848
51783
  );
51849
- const memoizedAttributes = useMemo10(() => ({
51784
+ const memoizedAttributes = useMemo12(() => ({
51850
51785
  role,
51851
51786
  tabIndex,
51852
51787
  "aria-disabled": disabled,
@@ -51991,7 +51926,7 @@ function useDroppable(_ref) {
51991
51926
  }
51992
51927
 
51993
51928
  // ../../node_modules/@dnd-kit/sortable/dist/sortable.esm.js
51994
- import React21, { useMemo as useMemo11, useRef as useRef28, useEffect as useEffect37, useState as useState30, useContext as useContext8 } from "react";
51929
+ import React21, { useMemo as useMemo13, useRef as useRef28, useEffect as useEffect37, useState as useState30, useContext as useContext8 } from "react";
51995
51930
  function arrayMove(array, from, to) {
51996
51931
  const newArray = array.slice();
51997
51932
  newArray.splice(to < 0 ? newArray.length + to : to, 0, newArray.splice(from, 1)[0]);
@@ -52145,7 +52080,7 @@ function SortableContext(_ref) {
52145
52080
  } = useDndContext();
52146
52081
  const containerId = useUniqueId(ID_PREFIX2, id2);
52147
52082
  const useDragOverlay = Boolean(dragOverlay.rect !== null);
52148
- const items = useMemo11(() => userDefinedItems.map((item) => typeof item === "object" && "id" in item ? item.id : item), [userDefinedItems]);
52083
+ const items = useMemo13(() => userDefinedItems.map((item) => typeof item === "object" && "id" in item ? item.id : item), [userDefinedItems]);
52149
52084
  const isDragging = active != null;
52150
52085
  const activeIndex = active ? items.indexOf(active.id) : -1;
52151
52086
  const overIndex = over ? items.indexOf(over.id) : -1;
@@ -52161,7 +52096,7 @@ function SortableContext(_ref) {
52161
52096
  useEffect37(() => {
52162
52097
  previousItemsRef.current = items;
52163
52098
  }, [items]);
52164
- const contextValue = useMemo11(
52099
+ const contextValue = useMemo13(
52165
52100
  () => ({
52166
52101
  activeIndex,
52167
52102
  containerId,
@@ -52288,7 +52223,7 @@ function useSortable(_ref) {
52288
52223
  } = useContext8(Context2);
52289
52224
  const disabled = normalizeLocalDisabled(localDisabled, globalDisabled);
52290
52225
  const index2 = items.indexOf(id2);
52291
- const data2 = useMemo11(() => ({
52226
+ const data2 = useMemo13(() => ({
52292
52227
  sortable: {
52293
52228
  containerId,
52294
52229
  index: index2,
@@ -52296,7 +52231,7 @@ function useSortable(_ref) {
52296
52231
  },
52297
52232
  ...customData
52298
52233
  }), [containerId, customData, index2, items]);
52299
- const itemsAfterCurrentSortable = useMemo11(() => items.slice(items.indexOf(id2)), [items, id2]);
52234
+ const itemsAfterCurrentSortable = useMemo13(() => items.slice(items.indexOf(id2)), [items, id2]);
52300
52235
  const {
52301
52236
  rect,
52302
52237
  node: node2,
@@ -54693,6 +54628,68 @@ function UserCircleIcon({
54693
54628
  var ForwardRef17 = /* @__PURE__ */ React44.forwardRef(UserCircleIcon);
54694
54629
  var UserCircleIcon_default = ForwardRef17;
54695
54630
 
54631
+ // src/hooks/usePanelNavigation.ts
54632
+ import { useState as useState36, useCallback as useCallback31, useEffect as useEffect43 } from "react";
54633
+ var COMMON_PANELS = ["user", "settings"];
54634
+ var RESOURCE_PANELS = ["history", "info", "annotations", "collaboration", "jsonld"];
54635
+ var tabGenerationCounter = 0;
54636
+ function usePanelNavigation() {
54637
+ const [activePanel, setActivePanel] = useState36(() => {
54638
+ if (typeof window !== "undefined") {
54639
+ const saved = localStorage.getItem("activeToolbarPanel");
54640
+ return saved || null;
54641
+ }
54642
+ return null;
54643
+ });
54644
+ const [scrollToAnnotationId, setScrollToAnnotationId] = useState36(null);
54645
+ const [panelInitialTab, setPanelInitialTab] = useState36(null);
54646
+ useEffect43(() => {
54647
+ if (typeof window === "undefined") return;
54648
+ if (activePanel) {
54649
+ localStorage.setItem("activeToolbarPanel", activePanel);
54650
+ } else {
54651
+ localStorage.removeItem("activeToolbarPanel");
54652
+ }
54653
+ }, [activePanel]);
54654
+ const handleScrollCompleted = useCallback31(() => {
54655
+ setScrollToAnnotationId(null);
54656
+ }, []);
54657
+ const handlePanelToggle = useCallback31(({ panel }) => {
54658
+ setActivePanel((current) => current === panel ? null : panel);
54659
+ }, []);
54660
+ const handlePanelOpen = useCallback31(({ panel, scrollToAnnotationId: scrollTarget, motivation }) => {
54661
+ if (scrollTarget) {
54662
+ setScrollToAnnotationId(scrollTarget);
54663
+ }
54664
+ if (motivation) {
54665
+ const motivationToTab = {
54666
+ "linking": "reference",
54667
+ "commenting": "comment",
54668
+ "tagging": "tag",
54669
+ "highlighting": "highlight",
54670
+ "assessing": "assessment"
54671
+ };
54672
+ const tab2 = motivationToTab[motivation] || "highlight";
54673
+ setPanelInitialTab({ tab: tab2, generation: ++tabGenerationCounter });
54674
+ }
54675
+ setActivePanel(panel);
54676
+ }, []);
54677
+ const handlePanelClose = useCallback31(() => {
54678
+ setActivePanel(null);
54679
+ }, []);
54680
+ useEventSubscriptions({
54681
+ "attend:panel-toggle": handlePanelToggle,
54682
+ "attend:panel-open": handlePanelOpen,
54683
+ "attend:panel-close": handlePanelClose
54684
+ });
54685
+ return {
54686
+ activePanel,
54687
+ scrollToAnnotationId,
54688
+ panelInitialTab,
54689
+ onScrollCompleted: handleScrollCompleted
54690
+ };
54691
+ }
54692
+
54696
54693
  // src/features/admin-devops/components/AdminDevOpsPage.tsx
54697
54694
  import { jsx as jsx66, jsxs as jsxs54 } from "react/jsx-runtime";
54698
54695
  function AdminDevOpsPage({
@@ -54705,7 +54702,7 @@ function AdminDevOpsPage({
54705
54702
  ToolbarPanels,
54706
54703
  Toolbar: Toolbar2
54707
54704
  }) {
54708
- return /* @__PURE__ */ jsxs54("div", { className: `semiont-page${activePanel ? " semiont-page--panel-open" : ""}`, children: [
54705
+ return /* @__PURE__ */ jsxs54("div", { className: `semiont-page${activePanel && COMMON_PANELS.includes(activePanel) ? " semiont-page--panel-open" : ""}`, children: [
54709
54706
  /* @__PURE__ */ jsxs54("div", { className: "semiont-page__content", children: [
54710
54707
  /* @__PURE__ */ jsxs54("div", { className: "semiont-page__header", children: [
54711
54708
  /* @__PURE__ */ jsx66("h1", { className: "semiont-page__title", children: t12.title }),
@@ -54778,7 +54775,7 @@ function AdminSecurityPage({
54778
54775
  ToolbarPanels,
54779
54776
  Toolbar: Toolbar2
54780
54777
  }) {
54781
- return /* @__PURE__ */ jsxs55("div", { className: `semiont-page${activePanel ? " semiont-page--panel-open" : ""}`, children: [
54778
+ return /* @__PURE__ */ jsxs55("div", { className: `semiont-page${activePanel && COMMON_PANELS.includes(activePanel) ? " semiont-page--panel-open" : ""}`, children: [
54782
54779
  /* @__PURE__ */ jsx67("div", { className: "semiont-page__content", children: /* @__PURE__ */ jsxs55("div", { className: "semiont-page__sections", children: [
54783
54780
  /* @__PURE__ */ jsxs55("div", { className: "semiont-page__header", children: [
54784
54781
  /* @__PURE__ */ jsx67("h1", { className: "semiont-page__title", children: t12.title }),
@@ -54861,7 +54858,7 @@ function AdminSecurityPage({
54861
54858
  }
54862
54859
 
54863
54860
  // src/features/admin-users/components/AdminUsersPage.tsx
54864
- import { useState as useState36 } from "react";
54861
+ import { useState as useState37 } from "react";
54865
54862
  import { Fragment as Fragment15, jsx as jsx68, jsxs as jsxs56 } from "react/jsx-runtime";
54866
54863
  function UserTableRow({
54867
54864
  user,
@@ -54943,9 +54940,9 @@ function AdminUsersPage({
54943
54940
  Toolbar: Toolbar2,
54944
54941
  buttonStyles: buttonStyles2
54945
54942
  }) {
54946
- const [searchTerm, setSearchTerm] = useState36("");
54947
- const [selectedRole, setSelectedRole] = useState36("all");
54948
- const [selectedStatus, setSelectedStatus] = useState36("all");
54943
+ const [searchTerm, setSearchTerm] = useState37("");
54944
+ const [selectedRole, setSelectedRole] = useState37("all");
54945
+ const [selectedStatus, setSelectedStatus] = useState37("all");
54949
54946
  const filteredUsers = users.filter((user) => {
54950
54947
  const matchesSearch = (user.name || "").toLowerCase().includes(searchTerm.toLowerCase()) || user.email.toLowerCase().includes(searchTerm.toLowerCase());
54951
54948
  const userRole = user.isAdmin ? "admin" : "user";
@@ -54954,7 +54951,7 @@ function AdminUsersPage({
54954
54951
  const matchesStatus = selectedStatus === "all" || userStatus === selectedStatus;
54955
54952
  return matchesSearch && matchesRole && matchesStatus;
54956
54953
  });
54957
- return /* @__PURE__ */ jsxs56("div", { className: `semiont-page${activePanel ? " semiont-page--panel-open" : ""}`, children: [
54954
+ return /* @__PURE__ */ jsxs56("div", { className: `semiont-page${activePanel && COMMON_PANELS.includes(activePanel) ? " semiont-page--panel-open" : ""}`, children: [
54958
54955
  /* @__PURE__ */ jsx68("div", { className: "semiont-page__content", children: /* @__PURE__ */ jsxs56("div", { className: "semiont-page__sections", children: [
54959
54956
  /* @__PURE__ */ jsxs56("div", { className: "semiont-page__header-with-action", children: [
54960
54957
  /* @__PURE__ */ jsxs56("div", { children: [
@@ -55260,7 +55257,7 @@ function SignInForm({
55260
55257
  }
55261
55258
 
55262
55259
  // src/features/auth/components/SignUpForm.tsx
55263
- import { useState as useState37 } from "react";
55260
+ import { useState as useState38 } from "react";
55264
55261
  import { jsx as jsx70, jsxs as jsxs58 } from "react/jsx-runtime";
55265
55262
  function GoogleIcon2() {
55266
55263
  return /* @__PURE__ */ jsxs58("svg", { className: "semiont-icon semiont-icon--small semiont-icon--inline", viewBox: "0 0 24 24", children: [
@@ -55295,7 +55292,7 @@ function GoogleIcon2() {
55295
55292
  ] });
55296
55293
  }
55297
55294
  function SignUpForm({ onSignUp, Link, translations: t12 }) {
55298
- const [isLoading, setIsLoading] = useState37(false);
55295
+ const [isLoading, setIsLoading] = useState38(false);
55299
55296
  const handleSignUp = async () => {
55300
55297
  setIsLoading(true);
55301
55298
  try {
@@ -55520,7 +55517,7 @@ function EntityTagsPage({
55520
55517
  onAddTag();
55521
55518
  }
55522
55519
  };
55523
- return /* @__PURE__ */ jsxs61("div", { className: `semiont-page${activePanel ? " semiont-page--panel-open" : ""}`, children: [
55520
+ return /* @__PURE__ */ jsxs61("div", { className: `semiont-page${activePanel && COMMON_PANELS.includes(activePanel) ? " semiont-page--panel-open" : ""}`, children: [
55524
55521
  /* @__PURE__ */ jsxs61("div", { className: "semiont-page__content", children: [
55525
55522
  /* @__PURE__ */ jsxs61("div", { className: "semiont-page__header", children: [
55526
55523
  /* @__PURE__ */ jsx73("h1", { className: "semiont-page__title", children: t12.pageTitle }),
@@ -55608,7 +55605,7 @@ function RecentDocumentsPage({
55608
55605
  if (isLoading) {
55609
55606
  return /* @__PURE__ */ jsx74("div", { className: "semiont-page__loading", children: /* @__PURE__ */ jsx74("p", { className: "semiont-page__loading-text", children: t12.loading }) });
55610
55607
  }
55611
- return /* @__PURE__ */ jsxs62("div", { className: `semiont-page${activePanel ? " semiont-page--panel-open" : ""}`, children: [
55608
+ return /* @__PURE__ */ jsxs62("div", { className: `semiont-page${activePanel && COMMON_PANELS.includes(activePanel) ? " semiont-page--panel-open" : ""}`, children: [
55612
55609
  /* @__PURE__ */ jsxs62("div", { className: "semiont-page__content", children: [
55613
55610
  /* @__PURE__ */ jsxs62("div", { className: "semiont-page__header", children: [
55614
55611
  /* @__PURE__ */ jsx74("h1", { className: "semiont-page__title", children: t12.pageTitle }),
@@ -55674,7 +55671,7 @@ function TagSchemasPage({
55674
55671
  if (isLoading) {
55675
55672
  return /* @__PURE__ */ jsx75("div", { className: "semiont-page__loading", children: /* @__PURE__ */ jsx75("p", { className: "semiont-page__loading-text", children: t12.loading }) });
55676
55673
  }
55677
- return /* @__PURE__ */ jsxs63("div", { className: `semiont-page${activePanel ? " semiont-page--panel-open" : ""}`, children: [
55674
+ return /* @__PURE__ */ jsxs63("div", { className: `semiont-page${activePanel && COMMON_PANELS.includes(activePanel) ? " semiont-page--panel-open" : ""}`, children: [
55678
55675
  /* @__PURE__ */ jsxs63("div", { className: "semiont-page__content", children: [
55679
55676
  /* @__PURE__ */ jsxs63("div", { className: "semiont-page__header", children: [
55680
55677
  /* @__PURE__ */ jsx75("h1", { className: "semiont-page__title", children: t12.pageTitle }),
@@ -55752,7 +55749,7 @@ function TagSchemasPage({
55752
55749
  }
55753
55750
 
55754
55751
  // src/features/resource-compose/components/ResourceComposePage.tsx
55755
- import { useState as useState38, useEffect as useEffect43 } from "react";
55752
+ import { useState as useState39, useEffect as useEffect44 } from "react";
55756
55753
  import { isImageMimeType, isPdfMimeType as isPdfMimeType4, LOCALES as LOCALES2 } from "@semiont/api-client";
55757
55754
  import { jsx as jsx76, jsxs as jsxs64 } from "react/jsx-runtime";
55758
55755
  function ResourceComposePage({
@@ -55772,19 +55769,19 @@ function ResourceComposePage({
55772
55769
  Toolbar: Toolbar2
55773
55770
  }) {
55774
55771
  const { announceFormSubmitting, announceFormSuccess, announceFormError } = useFormAnnouncements();
55775
- const [newResourceName, setNewResourceName] = useState38("");
55776
- const [newResourceContent, setNewResourceContent] = useState38("");
55777
- const [selectedEntityTypes, setSelectedEntityTypes] = useState38([]);
55778
- const [isCreating, setIsCreating] = useState38(false);
55779
- const [inputMethod, setInputMethod] = useState38("write");
55780
- const [uploadedFile, setUploadedFile] = useState38(null);
55781
- const [fileMimeType, setFileMimeType] = useState38("text/markdown");
55782
- const [filePreviewUrl, setFilePreviewUrl] = useState38(null);
55783
- const [selectedFormat, setSelectedFormat] = useState38("text/markdown");
55784
- const [selectedLanguage, setSelectedLanguage] = useState38(initialLocale);
55785
- const [selectedCharset, setSelectedCharset] = useState38("");
55786
- const [archiveOriginal, setArchiveOriginal] = useState38(true);
55787
- useEffect43(() => {
55772
+ const [newResourceName, setNewResourceName] = useState39("");
55773
+ const [newResourceContent, setNewResourceContent] = useState39("");
55774
+ const [selectedEntityTypes, setSelectedEntityTypes] = useState39([]);
55775
+ const [isCreating, setIsCreating] = useState39(false);
55776
+ const [inputMethod, setInputMethod] = useState39("write");
55777
+ const [uploadedFile, setUploadedFile] = useState39(null);
55778
+ const [fileMimeType, setFileMimeType] = useState39("text/markdown");
55779
+ const [filePreviewUrl, setFilePreviewUrl] = useState39(null);
55780
+ const [selectedFormat, setSelectedFormat] = useState39("text/markdown");
55781
+ const [selectedLanguage, setSelectedLanguage] = useState39(initialLocale);
55782
+ const [selectedCharset, setSelectedCharset] = useState39("");
55783
+ const [archiveOriginal, setArchiveOriginal] = useState39(true);
55784
+ useEffect44(() => {
55788
55785
  if (mode === "clone" && cloneData) {
55789
55786
  setNewResourceName(cloneData.sourceResource.name);
55790
55787
  setNewResourceContent(cloneData.sourceContent);
@@ -55817,7 +55814,7 @@ function ResourceComposePage({
55817
55814
  reader.readAsText(file);
55818
55815
  }
55819
55816
  };
55820
- useEffect43(() => {
55817
+ useEffect44(() => {
55821
55818
  return () => {
55822
55819
  if (filePreviewUrl) {
55823
55820
  URL.revokeObjectURL(filePreviewUrl);
@@ -55865,7 +55862,7 @@ function ResourceComposePage({
55865
55862
  };
55866
55863
  const isClone = mode === "clone";
55867
55864
  const isReferenceCompletion = mode === "reference";
55868
- return /* @__PURE__ */ jsxs64("div", { className: `semiont-page${activePanel ? " semiont-page--panel-open" : ""}`, children: [
55865
+ return /* @__PURE__ */ jsxs64("div", { className: `semiont-page${activePanel && COMMON_PANELS.includes(activePanel) ? " semiont-page--panel-open" : ""}`, children: [
55869
55866
  /* @__PURE__ */ jsxs64("div", { className: "semiont-page__content semiont-page__compose", children: [
55870
55867
  /* @__PURE__ */ jsxs64("div", { className: "semiont-page__header", children: [
55871
55868
  /* @__PURE__ */ jsx76("h1", { className: "semiont-page__title", children: isClone ? t12.titleEditClone : isReferenceCompletion ? t12.titleCompleteReference : t12.title }),
@@ -56166,7 +56163,7 @@ function ResourceComposePage({
56166
56163
  }
56167
56164
 
56168
56165
  // src/features/resource-discovery/components/ResourceDiscoveryPage.tsx
56169
- import { useState as useState39, useCallback as useCallback31, useRef as useRef31 } from "react";
56166
+ import { useState as useState40, useCallback as useCallback32, useRef as useRef31 } from "react";
56170
56167
  import { getResourceId as getResourceId2 } from "@semiont/api-client";
56171
56168
 
56172
56169
  // src/features/resource-discovery/components/ResourceCard.tsx
@@ -56239,8 +56236,8 @@ function ResourceDiscoveryPage({
56239
56236
  translations: t12,
56240
56237
  ToolbarPanels
56241
56238
  }) {
56242
- const [searchQuery2, setSearchQuery] = useState39("");
56243
- const [selectedEntityType, setSelectedEntityType] = useState39("");
56239
+ const [searchQuery2, setSearchQuery] = useState40("");
56240
+ const [selectedEntityType, setSelectedEntityType] = useState40("");
56244
56241
  const hasSearchQuery = searchQuery2.trim() !== "";
56245
56242
  const hasSearchResults = searchDocuments.length > 0;
56246
56243
  const baseDocuments = hasSearchResults ? searchDocuments : recentDocuments;
@@ -56259,23 +56256,23 @@ function ResourceDiscoveryPage({
56259
56256
  );
56260
56257
  const onNavigateToResourceRef = useRef31(onNavigateToResource);
56261
56258
  onNavigateToResourceRef.current = onNavigateToResource;
56262
- const handleEntityTypeFilter = useCallback31((entityType3) => {
56259
+ const handleEntityTypeFilter = useCallback32((entityType3) => {
56263
56260
  setSelectedEntityType(entityType3);
56264
56261
  }, []);
56265
- const openResource = useCallback31((resource) => {
56262
+ const openResource = useCallback32((resource) => {
56266
56263
  const resourceId = getResourceId2(resource);
56267
56264
  if (resourceId) {
56268
56265
  onNavigateToResourceRef.current(resourceId);
56269
56266
  }
56270
56267
  }, []);
56271
- const handleSearchSubmit = useCallback31((e6) => {
56268
+ const handleSearchSubmit = useCallback32((e6) => {
56272
56269
  e6.preventDefault();
56273
56270
  }, []);
56274
56271
  if (isLoadingRecent) {
56275
56272
  return /* @__PURE__ */ jsx78("div", { className: "semiont-page__loading", children: /* @__PURE__ */ jsx78("p", { className: "semiont-page__loading-text", children: t12.loadingKnowledgeBase }) });
56276
56273
  }
56277
56274
  const showNoResultsWarning = hasSearchQuery && !hasSearchResults && !isSearching;
56278
- return /* @__PURE__ */ jsxs66("div", { className: `semiont-page${activePanel ? " semiont-page--panel-open" : ""}`, children: [
56275
+ return /* @__PURE__ */ jsxs66("div", { className: `semiont-page${activePanel && COMMON_PANELS.includes(activePanel) ? " semiont-page--panel-open" : ""}`, children: [
56279
56276
  /* @__PURE__ */ jsxs66("div", { className: "semiont-page__content", children: [
56280
56277
  /* @__PURE__ */ jsxs66("div", { className: "semiont-page__header", children: [
56281
56278
  /* @__PURE__ */ jsx78("h1", { className: "semiont-page__title", children: t12.title }),
@@ -56400,14 +56397,14 @@ function ResourceDiscoveryPage({
56400
56397
  }
56401
56398
 
56402
56399
  // src/features/resource-viewer/components/ResourceViewerPage.tsx
56403
- import { useState as useState45, useEffect as useEffect49, useCallback as useCallback36, useMemo as useMemo12 } from "react";
56400
+ import { useState as useState45, useEffect as useEffect49, useCallback as useCallback36, useMemo as useMemo14 } from "react";
56404
56401
  import { useQueryClient as useQueryClient2 } from "@tanstack/react-query";
56405
56402
  import { resourceAnnotationUri as resourceAnnotationUri3 } from "@semiont/core";
56406
56403
  import { getLanguage, getPrimaryRepresentation, getPrimaryMediaType as getPrimaryMediaType2 } from "@semiont/api-client";
56407
56404
  import { uriToAnnotationId as uriToAnnotationId2 } from "@semiont/core";
56408
56405
 
56409
56406
  // src/hooks/useResolutionFlow.ts
56410
- import { useCallback as useCallback32, useEffect as useEffect44, useRef as useRef32, useState as useState40 } from "react";
56407
+ import { useCallback as useCallback33, useEffect as useEffect45, useRef as useRef32, useState as useState41 } from "react";
56411
56408
  import { resourceAnnotationUri, accessToken as accessToken3 } from "@semiont/core";
56412
56409
  import { uriToAnnotationIdOrPassthrough } from "@semiont/core";
56413
56410
  function toAccessToken2(token) {
@@ -56418,24 +56415,24 @@ function useResolutionFlow(rUri) {
56418
56415
  const client = useApiClient();
56419
56416
  const token = useAuthToken();
56420
56417
  const { showError } = useToast();
56421
- const [searchModalOpen, setSearchModalOpen] = useState40(false);
56422
- const [pendingReferenceId, setPendingReferenceId] = useState40(null);
56423
- const onCloseSearchModal = useCallback32(() => {
56418
+ const [searchModalOpen, setSearchModalOpen] = useState41(false);
56419
+ const [pendingReferenceId, setPendingReferenceId] = useState41(null);
56420
+ const onCloseSearchModal = useCallback33(() => {
56424
56421
  setSearchModalOpen(false);
56425
56422
  }, []);
56426
56423
  const rUriRef = useRef32(rUri);
56427
- useEffect44(() => {
56424
+ useEffect45(() => {
56428
56425
  rUriRef.current = rUri;
56429
56426
  });
56430
56427
  const clientRef = useRef32(client);
56431
- useEffect44(() => {
56428
+ useEffect45(() => {
56432
56429
  clientRef.current = client;
56433
56430
  });
56434
56431
  const tokenRef = useRef32(token);
56435
- useEffect44(() => {
56432
+ useEffect45(() => {
56436
56433
  tokenRef.current = token;
56437
56434
  });
56438
- useEffect44(() => {
56435
+ useEffect45(() => {
56439
56436
  const handleAnnotationUpdateBody = async (event) => {
56440
56437
  try {
56441
56438
  const annotationIdSegment = uriToAnnotationIdOrPassthrough(event.annotationUri);
@@ -56463,7 +56460,7 @@ function useResolutionFlow(rUri) {
56463
56460
  subscription2.unsubscribe();
56464
56461
  };
56465
56462
  }, [eventBus]);
56466
- useEffect44(() => {
56463
+ useEffect45(() => {
56467
56464
  const handleResolutionSearchRequested = (event) => {
56468
56465
  setPendingReferenceId(event.referenceId);
56469
56466
  setSearchModalOpen(true);
@@ -56478,7 +56475,7 @@ function useResolutionFlow(rUri) {
56478
56475
  }
56479
56476
 
56480
56477
  // src/hooks/useAnnotationFlow.ts
56481
- import { useState as useState41, useRef as useRef33, useEffect as useEffect45, useCallback as useCallback33 } from "react";
56478
+ import { useState as useState42, useRef as useRef33, useEffect as useEffect46, useCallback as useCallback34 } from "react";
56482
56479
  import { resourceAnnotationUri as resourceAnnotationUri2, accessToken as accessToken4, entityType as entityType2 } from "@semiont/core";
56483
56480
  import { uriToAnnotationIdOrPassthrough as uriToAnnotationIdOrPassthrough2 } from "@semiont/core";
56484
56481
  function toAccessToken3(token) {
@@ -56492,17 +56489,17 @@ function useAnnotationFlow(rUri) {
56492
56489
  const clientRef = useRef33(client);
56493
56490
  const rUriRef = useRef33(rUri);
56494
56491
  const tokenRef = useRef33(token);
56495
- useEffect45(() => {
56492
+ useEffect46(() => {
56496
56493
  clientRef.current = client;
56497
56494
  });
56498
- useEffect45(() => {
56495
+ useEffect46(() => {
56499
56496
  rUriRef.current = rUri;
56500
56497
  });
56501
- useEffect45(() => {
56498
+ useEffect46(() => {
56502
56499
  tokenRef.current = token;
56503
56500
  });
56504
- const [pendingAnnotation, setPendingAnnotation] = useState41(null);
56505
- const handleAnnotationRequested = useCallback33((pending) => {
56501
+ const [pendingAnnotation, setPendingAnnotation] = useState42(null);
56502
+ const handleAnnotationRequested = useCallback34((pending) => {
56506
56503
  const MOTIVATION_TO_TAB = {
56507
56504
  highlighting: "annotations",
56508
56505
  commenting: "annotations",
@@ -56521,7 +56518,7 @@ function useAnnotationFlow(rUri) {
56521
56518
  eventBus.get("attend:panel-open").next({ panel: MOTIVATION_TO_TAB[pending.motivation] || "annotations" });
56522
56519
  setPendingAnnotation(pending);
56523
56520
  }, []);
56524
- const selectionToSelector = useCallback33((selection2) => {
56521
+ const selectionToSelector = useCallback34((selection2) => {
56525
56522
  if (selection2.svgSelector) {
56526
56523
  return {
56527
56524
  type: "SvgSelector",
@@ -56553,29 +56550,29 @@ function useAnnotationFlow(rUri) {
56553
56550
  ...selection2.suffix && { suffix: selection2.suffix }
56554
56551
  };
56555
56552
  }, []);
56556
- const handleCommentRequested = useCallback33((selection2) => {
56553
+ const handleCommentRequested = useCallback34((selection2) => {
56557
56554
  handleAnnotationRequested({ selector: selectionToSelector(selection2), motivation: "commenting" });
56558
56555
  }, [handleAnnotationRequested, selectionToSelector]);
56559
- const handleTagRequested = useCallback33((selection2) => {
56556
+ const handleTagRequested = useCallback34((selection2) => {
56560
56557
  handleAnnotationRequested({ selector: selectionToSelector(selection2), motivation: "tagging" });
56561
56558
  }, [handleAnnotationRequested, selectionToSelector]);
56562
- const handleAssessmentRequested = useCallback33((selection2) => {
56559
+ const handleAssessmentRequested = useCallback34((selection2) => {
56563
56560
  handleAnnotationRequested({ selector: selectionToSelector(selection2), motivation: "assessing" });
56564
56561
  }, [handleAnnotationRequested, selectionToSelector]);
56565
- const handleReferenceRequested = useCallback33((selection2) => {
56562
+ const handleReferenceRequested = useCallback34((selection2) => {
56566
56563
  handleAnnotationRequested({ selector: selectionToSelector(selection2), motivation: "linking" });
56567
56564
  }, [handleAnnotationRequested, selectionToSelector]);
56568
- const handleAnnotationCancelPending = useCallback33(() => {
56565
+ const handleAnnotationCancelPending = useCallback34(() => {
56569
56566
  setPendingAnnotation(null);
56570
56567
  }, []);
56571
- const [assistingMotivation, setAssistingMotivation] = useState41(null);
56572
- const [progress, setProgress] = useState41(null);
56568
+ const [assistingMotivation, setAssistingMotivation] = useState42(null);
56569
+ const [progress, setProgress] = useState42(null);
56573
56570
  const assistStreamRef = useRef33(null);
56574
56571
  const progressDismissTimeoutRef = useRef33(null);
56575
- const handleAnnotationProgress = useCallback33((chunk) => {
56572
+ const handleAnnotationProgress = useCallback34((chunk) => {
56576
56573
  setProgress(chunk);
56577
56574
  }, []);
56578
- const handleAnnotationComplete = useCallback33((event) => {
56575
+ const handleAnnotationComplete = useCallback34((event) => {
56579
56576
  setAssistingMotivation((prev) => {
56580
56577
  if (!event.motivation || event.motivation !== prev) return prev;
56581
56578
  return null;
@@ -56589,7 +56586,7 @@ function useAnnotationFlow(rUri) {
56589
56586
  progressDismissTimeoutRef.current = null;
56590
56587
  }, 5e3);
56591
56588
  }, [showSuccess]);
56592
- const handleAnnotationFailed = useCallback33((event) => {
56589
+ const handleAnnotationFailed = useCallback34((event) => {
56593
56590
  if (progressDismissTimeoutRef.current) {
56594
56591
  clearTimeout(progressDismissTimeoutRef.current);
56595
56592
  progressDismissTimeoutRef.current = null;
@@ -56599,14 +56596,14 @@ function useAnnotationFlow(rUri) {
56599
56596
  const errorMessage = event.payload.error || "Annotation failed";
56600
56597
  showError(errorMessage);
56601
56598
  }, [showError]);
56602
- const handleProgressDismiss = useCallback33(() => {
56599
+ const handleProgressDismiss = useCallback34(() => {
56603
56600
  if (progressDismissTimeoutRef.current) {
56604
56601
  clearTimeout(progressDismissTimeoutRef.current);
56605
56602
  progressDismissTimeoutRef.current = null;
56606
56603
  }
56607
56604
  setProgress(null);
56608
56605
  }, []);
56609
- useEffect45(() => {
56606
+ useEffect46(() => {
56610
56607
  const handleAnnotationCreate = async (event) => {
56611
56608
  const currentClient = clientRef.current;
56612
56609
  const currentRUri = rUriRef.current;
@@ -56736,7 +56733,7 @@ function useAnnotationFlow(rUri) {
56736
56733
  "annotate:create-failed": ({ error }) => showError(`Failed to create annotation: ${error.message}`),
56737
56734
  "annotate:delete-failed": ({ error }) => showError(`Failed to delete annotation: ${error.message}`)
56738
56735
  });
56739
- useEffect45(() => {
56736
+ useEffect46(() => {
56740
56737
  return () => {
56741
56738
  if (progressDismissTimeoutRef.current) {
56742
56739
  clearTimeout(progressDismissTimeoutRef.current);
@@ -56751,66 +56748,6 @@ function useAnnotationFlow(rUri) {
56751
56748
  };
56752
56749
  }
56753
56750
 
56754
- // src/hooks/usePanelNavigation.ts
56755
- import { useState as useState42, useCallback as useCallback34, useEffect as useEffect46 } from "react";
56756
- var tabGenerationCounter = 0;
56757
- function usePanelNavigation() {
56758
- const [activePanel, setActivePanel] = useState42(() => {
56759
- if (typeof window !== "undefined") {
56760
- const saved = localStorage.getItem("activeToolbarPanel");
56761
- return saved || null;
56762
- }
56763
- return null;
56764
- });
56765
- const [scrollToAnnotationId, setScrollToAnnotationId] = useState42(null);
56766
- const [panelInitialTab, setPanelInitialTab] = useState42(null);
56767
- useEffect46(() => {
56768
- if (typeof window === "undefined") return;
56769
- if (activePanel) {
56770
- localStorage.setItem("activeToolbarPanel", activePanel);
56771
- } else {
56772
- localStorage.removeItem("activeToolbarPanel");
56773
- }
56774
- }, [activePanel]);
56775
- const handleScrollCompleted = useCallback34(() => {
56776
- setScrollToAnnotationId(null);
56777
- }, []);
56778
- const handlePanelToggle = useCallback34(({ panel }) => {
56779
- setActivePanel((current) => current === panel ? null : panel);
56780
- }, []);
56781
- const handlePanelOpen = useCallback34(({ panel, scrollToAnnotationId: scrollTarget, motivation }) => {
56782
- if (scrollTarget) {
56783
- setScrollToAnnotationId(scrollTarget);
56784
- }
56785
- if (motivation) {
56786
- const motivationToTab = {
56787
- "linking": "reference",
56788
- "commenting": "comment",
56789
- "tagging": "tag",
56790
- "highlighting": "highlight",
56791
- "assessing": "assessment"
56792
- };
56793
- const tab2 = motivationToTab[motivation] || "highlight";
56794
- setPanelInitialTab({ tab: tab2, generation: ++tabGenerationCounter });
56795
- }
56796
- setActivePanel(panel);
56797
- }, []);
56798
- const handlePanelClose = useCallback34(() => {
56799
- setActivePanel(null);
56800
- }, []);
56801
- useEventSubscriptions({
56802
- "attend:panel-toggle": handlePanelToggle,
56803
- "attend:panel-open": handlePanelOpen,
56804
- "attend:panel-close": handlePanelClose
56805
- });
56806
- return {
56807
- activePanel,
56808
- scrollToAnnotationId,
56809
- panelInitialTab,
56810
- onScrollCompleted: handleScrollCompleted
56811
- };
56812
- }
56813
-
56814
56751
  // src/hooks/useGenerationFlow.ts
56815
56752
  import { useState as useState43, useCallback as useCallback35, useEffect as useEffect47, useRef as useRef34 } from "react";
56816
56753
  import { annotationUri, accessToken as accessToken5 } from "@semiont/core";
@@ -57035,7 +56972,7 @@ function ResourceViewerPage({
57035
56972
  const entityTypesAPI = useEntityTypes();
57036
56973
  const { content: content4, loading: contentLoading } = useResourceContent(rUri, resource);
57037
56974
  const { data: annotationsData } = resources.annotations.useQuery(rUri);
57038
- const annotations = useMemo12(
56975
+ const annotations = useMemo14(
57039
56976
  () => annotationsData?.annotations || [],
57040
56977
  [annotationsData?.annotations]
57041
56978
  );
@@ -57165,8 +57102,8 @@ function ResourceViewerPage({
57165
57102
  }, [updateMutation, rUri, refetchDocument, showError]);
57166
57103
  const handleResourceClone = useCallback36(async () => {
57167
57104
  try {
57168
- const result2 = await generateCloneTokenMutation.mutateAsync(rUri);
57169
- const token = result2.token;
57105
+ const result = await generateCloneTokenMutation.mutateAsync(rUri);
57106
+ const token = result.token;
57170
57107
  eventBus.get("navigation:router-push").next({ path: `/know/compose?mode=clone&token=${token}`, reason: "clone" });
57171
57108
  } catch (err) {
57172
57109
  console.error("Failed to generate clone token:", err);
@@ -57251,23 +57188,25 @@ function ResourceViewerPage({
57251
57188
  }
57252
57189
  return false;
57253
57190
  });
57254
- const result = {
57255
- highlights: [],
57256
- references: [],
57257
- assessments: [],
57258
- comments: [],
57259
- tags: []
57260
- };
57261
- for (const ann of annotations) {
57262
- const annotator = Object.values(ANNOTATORS).find((a15) => a15.matchesAnnotation(ann));
57263
- if (annotator) {
57264
- const key = annotator.internalType + "s";
57265
- if (result[key]) {
57266
- result[key].push(ann);
57191
+ const groups = useMemo14(() => {
57192
+ const result = {
57193
+ highlights: [],
57194
+ references: [],
57195
+ assessments: [],
57196
+ comments: [],
57197
+ tags: []
57198
+ };
57199
+ for (const ann of annotations) {
57200
+ const annotator = Object.values(ANNOTATORS).find((a15) => a15.matchesAnnotation(ann));
57201
+ if (annotator) {
57202
+ const key = annotator.internalType + "s";
57203
+ if (result[key]) {
57204
+ result[key].push(ann);
57205
+ }
57267
57206
  }
57268
57207
  }
57269
- }
57270
- const groups = result;
57208
+ return result;
57209
+ }, [annotations]);
57271
57210
  const resourceWithContent = { ...resource, content: content4 };
57272
57211
  const handleEventHover = useCallback36((annotationId) => {
57273
57212
  if (annotationId) {
@@ -57461,6 +57400,7 @@ export {
57461
57400
  BrowseView,
57462
57401
  Button,
57463
57402
  ButtonGroup,
57403
+ COMMON_PANELS,
57464
57404
  CacheProvider,
57465
57405
  CodeMirrorRenderer,
57466
57406
  CollaborationPanel,
@@ -57494,6 +57434,7 @@ export {
57494
57434
  PopupHeader,
57495
57435
  ProposeEntitiesModal,
57496
57436
  QUERY_KEYS,
57437
+ RESOURCE_PANELS,
57497
57438
  RecentDocumentsPage,
57498
57439
  ReferenceEntry,
57499
57440
  ReferenceResolutionWidget,
@@ -57539,7 +57480,11 @@ export {
57539
57480
  UnifiedHeader,
57540
57481
  UserMenuSkeleton,
57541
57482
  WelcomePage,
57483
+ applyHighlights,
57484
+ buildSourceToRenderedMap,
57485
+ buildTextNodeIndex,
57542
57486
  buttonStyles,
57487
+ clearHighlights,
57543
57488
  createHoverHandlers,
57544
57489
  cssVariables,
57545
57490
  dispatch401Error,
@@ -57557,17 +57502,19 @@ export {
57557
57502
  getSchemaCategory as getTagCategory,
57558
57503
  getTagSchema,
57559
57504
  getTagSchemasByDomain,
57505
+ hideWidgetPreview,
57560
57506
  isShapeSupported,
57561
57507
  isValidCategory,
57562
57508
  jsonLightHighlightStyle,
57563
57509
  jsonLightTheme,
57564
57510
  onAuthEvent,
57565
- rehypeRenderAnnotations,
57566
- remarkAnnotations,
57567
57511
  resetEventBusForTesting,
57512
+ resolveAnnotationRanges,
57568
57513
  sanitizeImageURL,
57569
57514
  saveSelectedShapeForSelectorType,
57515
+ showWidgetPreview,
57570
57516
  supportsDetection,
57517
+ toOverlayAnnotations,
57571
57518
  tokens,
57572
57519
  useAdmin,
57573
57520
  useAnnotationFlow,