Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions apps/desktop/src/preview/AnnotationIds.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { describe, expect, it } from "vite-plus/test";

import { createAnnotationIdSource } from "./AnnotationIds.ts";

describe("createAnnotationIdSource", () => {
it("gives annotations picked on separate page loads distinct ids", () => {
// The picker preload runs afresh on every page load, while the composer
// keeps earlier annotations keyed by id.
const firstLoad = createAnnotationIdSource();
firstLoad("element");
const firstAnnotation = firstLoad("annotation");

const secondLoad = createAnnotationIdSource();
secondLoad("element");
const secondAnnotation = secondLoad("annotation");

expect(secondAnnotation).not.toBe(firstAnnotation);
});

it("never repeats an id within one page load", () => {
const nextId = createAnnotationIdSource();
const ids = Array.from({ length: 1_000 }, () => nextId("annotation"));
expect(new Set(ids).size).toBe(ids.length);
});
});
18 changes: 18 additions & 0 deletions apps/desktop/src/preview/AnnotationIds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Id source for picker annotations and their targets, one per page load.
*
* The composer keeps annotations keyed by id across preview reloads, and this
* preload restarts on every page load, so a bare counter reissues ids that a
* draft already holds. `getRandomValues` rather than `randomUUID`, because
* plain-http previews (LAN, tailnet) are not secure contexts.
*/
export function createAnnotationIdSource(): (prefix: string) => string {
const pageLoad = Array.from(crypto.getRandomValues(new Uint32Array(2)), (part) =>
part.toString(36),
).join("");
let sequence = 0;
return (prefix) => {
sequence += 1;
return `${prefix}_${pageLoad}_${sequence.toString(36)}`;
};
}
7 changes: 2 additions & 5 deletions apps/desktop/src/preview/PickPreload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
PreviewAnnotationSubmission,
} from "@t3tools/contracts";

import { createAnnotationIdSource } from "./AnnotationIds.ts";
import { resolveAnnotationSubmission } from "./AnnotationKeyboard.ts";
import { previewAnnotationStyles } from "./AnnotationStyles.generated.ts";
import { installRecordingCursor } from "./RecordingCursor.ts";
Expand Down Expand Up @@ -132,7 +133,6 @@ interface AnnotationSession {
}

let activeSession: AnnotationSession | null = null;
let idSequence = 0;
let annotationTheme: DesktopPreviewAnnotationTheme | null = null;

const applyAnnotationTheme = (
Expand Down Expand Up @@ -220,10 +220,7 @@ window.addEventListener("mousedown", suppressNavigationButton, true);
window.addEventListener("mouseup", requestNavigationForButton, true);
window.addEventListener("auxclick", suppressNavigationButton, true);

const nextId = (prefix: string): string => {
idSequence += 1;
return `${prefix}_${idSequence.toString(36)}`;
};
const nextId = createAnnotationIdSource();

const rectFromDomRect = (rect: DOMRect): PreviewAnnotationRect => ({
x: rect.left,
Expand Down
Loading