web-annotation-renderer 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +176 -6
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +23 -19
- package/dist/index.js.map +1 -1
- package/dist/index12.cjs +1 -1
- package/dist/index12.cjs.map +1 -1
- package/dist/index12.js +118 -189
- package/dist/index12.js.map +1 -1
- package/dist/index13.cjs +1 -1
- package/dist/index13.cjs.map +1 -1
- package/dist/index13.js +200 -15
- package/dist/index13.js.map +1 -1
- package/dist/index14.cjs +1 -1
- package/dist/index14.cjs.map +1 -1
- package/dist/index14.js +15 -123
- package/dist/index14.js.map +1 -1
- package/dist/index15.cjs +1 -1
- package/dist/index15.cjs.map +1 -1
- package/dist/index15.js +123 -32
- package/dist/index15.js.map +1 -1
- package/dist/index16.cjs +2 -0
- package/dist/index16.cjs.map +1 -0
- package/dist/index16.js +35 -0
- package/dist/index16.js.map +1 -0
- package/package.json +5 -1
package/dist/index13.js
CHANGED
|
@@ -1,18 +1,203 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { HIGHLIGHT_DEFAULTS as f, TEXT_DEFAULTS as a, INK_DEFAULTS as d, BASE_DEFAULTS as p } from "./index16.js";
|
|
2
|
+
function r(t, n, o, s, e) {
|
|
3
|
+
let i = t;
|
|
4
|
+
return typeof t == "string" && (i = parseFloat(t)), typeof i != "number" || isNaN(i) ? (e.push(
|
|
5
|
+
`[${o}]: Field "${s}" invalid value "${t}", using default ${n}`
|
|
6
|
+
), n) : i < 0 ? (e.push(
|
|
7
|
+
`[${o}]: Field "${s}" value ${i} below range [0,1], clamping to 0`
|
|
8
|
+
), 0) : i > 1 ? (e.push(
|
|
9
|
+
`[${o}]: Field "${s}" value ${i} exceeds range [0,1], clamping to 1`
|
|
10
|
+
), 1) : i;
|
|
11
|
+
}
|
|
12
|
+
function c(t, n, o, s) {
|
|
13
|
+
if (typeof t != "string" || t.trim().length === 0)
|
|
14
|
+
return s.push(
|
|
15
|
+
`[${o}]: Invalid color format "${t}", using default ${n}`
|
|
16
|
+
), n;
|
|
17
|
+
const e = t.trim(), i = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/, l = /^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*[\d.]+\s*)?\)$/, u = [
|
|
18
|
+
"red",
|
|
19
|
+
"blue",
|
|
20
|
+
"green",
|
|
21
|
+
"yellow",
|
|
22
|
+
"black",
|
|
23
|
+
"white",
|
|
24
|
+
"gray",
|
|
25
|
+
"grey",
|
|
26
|
+
"orange",
|
|
27
|
+
"purple",
|
|
28
|
+
"pink",
|
|
29
|
+
"brown",
|
|
30
|
+
"transparent"
|
|
31
|
+
], m = i.test(e), y = l.test(e), g = u.includes(e.toLowerCase());
|
|
32
|
+
return m || y || g ? e : (s.push(
|
|
33
|
+
`[${o}]: Invalid color format "${t}", using default ${n}`
|
|
34
|
+
), n);
|
|
35
|
+
}
|
|
36
|
+
function h(t, n, o, s, e) {
|
|
37
|
+
let i = t;
|
|
38
|
+
return typeof t == "string" && (i = parseFloat(t)), typeof i != "number" || isNaN(i) || i <= 0 ? (e.push(
|
|
39
|
+
`[${o}]: Field "${s}" invalid value "${t}", using default ${n}`
|
|
40
|
+
), n) : i;
|
|
41
|
+
}
|
|
42
|
+
function $(t, n, o) {
|
|
43
|
+
const s = {};
|
|
44
|
+
if (typeof t.id != "string" || t.id.trim().length === 0) {
|
|
45
|
+
const e = Date.now(), i = Math.random().toString(36).substr(2, 9);
|
|
46
|
+
s.id = `anno-${e}-${i}`, o.push(`[${s.id}]: Auto-generated ID (original was missing or invalid)`);
|
|
47
|
+
} else
|
|
48
|
+
s.id = t.id.trim();
|
|
49
|
+
return s.type = t.type, typeof t.page != "number" || t.page < 1 ? (n.push(
|
|
50
|
+
`[${s.id}]: Field "page" invalid value "${t.page}", using default ${p.page}`
|
|
51
|
+
), s.page = p.page) : s.page = Math.floor(t.page), typeof t.start != "number" || t.start < 0 ? (n.push(
|
|
52
|
+
`[${s.id}]: Field "start" invalid value "${t.start}", using default ${p.start}`
|
|
53
|
+
), s.start = p.start) : s.start = t.start, typeof t.end != "number" || t.end < 0 ? (n.push(
|
|
54
|
+
`[${s.id}]: Field "end" invalid value "${t.end}", using start value ${s.start}`
|
|
55
|
+
), s.end = s.start) : t.end < s.start ? (n.push(
|
|
56
|
+
`[${s.id}]: Field "end" (${t.end}) less than start (${s.start}), clamping to start`
|
|
57
|
+
), s.end = s.start) : s.end = t.end, s;
|
|
58
|
+
}
|
|
59
|
+
function z(t, n, o) {
|
|
60
|
+
return !t || typeof t != "object" ? (o.push(`[${n}]: Invalid quad object, using default`), { x: 0.1, y: 0.1, w: 0.8, h: 0.05 }) : {
|
|
61
|
+
x: r(t.x, 0.1, n, "quad.x", o),
|
|
62
|
+
y: r(t.y, 0.1, n, "quad.y", o),
|
|
63
|
+
w: r(t.w, 0.8, n, "quad.w", o),
|
|
64
|
+
h: r(t.h, 0.05, n, "quad.h", o)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function A(t, n, o, s) {
|
|
68
|
+
const e = { ...t };
|
|
69
|
+
n.mode !== "quads" ? (o.push(
|
|
70
|
+
`[${t.id}]: Field "mode" invalid value "${n.mode}", using default "${f.mode}"`
|
|
71
|
+
), e.mode = f.mode) : e.mode = n.mode, !Array.isArray(n.quads) || n.quads.length === 0 ? (o.push(
|
|
72
|
+
`[${t.id}]: Field "quads" missing or empty, using default`
|
|
73
|
+
), e.quads = f.quads) : e.quads = n.quads.map((l, u) => z(l, t.id, o));
|
|
74
|
+
const i = f.style.color;
|
|
75
|
+
return !n.style || typeof n.style != "object" ? (o.push(
|
|
76
|
+
`[${t.id}]: Field "style" missing or invalid, using default`
|
|
77
|
+
), e.style = { color: i }) : e.style = {
|
|
78
|
+
color: c(n.style.color, i, t.id, o)
|
|
79
|
+
}, e;
|
|
80
|
+
}
|
|
81
|
+
function F(t, n, o, s) {
|
|
82
|
+
const e = { ...t };
|
|
83
|
+
typeof n.content != "string" || n.content.trim().length === 0 ? (o.push(
|
|
84
|
+
`[${t.id}]: Field "content" missing or empty, using default "${a.content}"`
|
|
85
|
+
), e.content = a.content) : e.content = n.content, e.x = r(n.x, a.x, t.id, "x", o), e.y = r(n.y, a.y, t.id, "y", o), e.w = r(n.w, a.w, t.id, "w", o), e.h = r(n.h, a.h, t.id, "h", o);
|
|
86
|
+
const i = a.style.bg, l = a.style.color;
|
|
87
|
+
return !n.style || typeof n.style != "object" ? (o.push(
|
|
88
|
+
`[${t.id}]: Field "style" missing or invalid, using defaults`
|
|
89
|
+
), e.style = {
|
|
90
|
+
bg: i,
|
|
91
|
+
color: l
|
|
92
|
+
}) : e.style = {
|
|
93
|
+
bg: c(n.style.bg, i, t.id, o),
|
|
94
|
+
color: c(n.style.color, l, t.id, o)
|
|
95
|
+
}, e;
|
|
96
|
+
}
|
|
97
|
+
function k(t, n, o) {
|
|
98
|
+
return !t || typeof t != "object" ? (o.push(`[${n}]: Invalid point object, using default`), { t: 0, x: 0.1, y: 0.1 }) : {
|
|
99
|
+
t: r(t.t, 0, n, "point.t", o),
|
|
100
|
+
x: r(t.x, 0.1, n, "point.x", o),
|
|
101
|
+
y: r(t.y, 0.1, n, "point.y", o)
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function x(t, n, o) {
|
|
105
|
+
if (!t || typeof t != "object")
|
|
106
|
+
return o.push(`[${n}]: Invalid stroke object, using default`), d.strokes[0];
|
|
107
|
+
const s = {
|
|
108
|
+
color: c(t.color, d.strokes[0].color, n, o),
|
|
109
|
+
size: h(t.size, d.strokes[0].size, n, "stroke.size", o)
|
|
110
|
+
};
|
|
111
|
+
return !Array.isArray(t.points) || t.points.length === 0 ? (o.push(`[${n}]: Stroke missing points array, using default`), s.points = d.strokes[0].points) : s.points = t.points.map((e) => k(e, n, o)), s;
|
|
112
|
+
}
|
|
113
|
+
function v(t, n, o, s) {
|
|
114
|
+
const e = { ...t };
|
|
115
|
+
return !Array.isArray(n.strokes) || n.strokes.length === 0 ? (o.push(
|
|
116
|
+
`[${t.id}]: Field "strokes" missing or empty, using default`
|
|
117
|
+
), e.strokes = d.strokes) : e.strokes = n.strokes.map((i) => x(i, t.id, o)), e;
|
|
118
|
+
}
|
|
119
|
+
function b(t, n) {
|
|
120
|
+
const o = [], s = [];
|
|
121
|
+
if (!t || typeof t != "object")
|
|
122
|
+
return {
|
|
123
|
+
annotation: null,
|
|
124
|
+
warnings: [],
|
|
125
|
+
info: [],
|
|
126
|
+
critical: `Annotation at index ${n}: Not a valid object`
|
|
127
|
+
};
|
|
128
|
+
if (typeof t.type != "string" || t.type.trim().length === 0)
|
|
129
|
+
return {
|
|
130
|
+
annotation: null,
|
|
131
|
+
warnings: [],
|
|
132
|
+
info: [],
|
|
133
|
+
critical: `Annotation at index ${n}: Missing or invalid type field`
|
|
134
|
+
};
|
|
135
|
+
const e = t.type.trim(), i = $(t, o, s);
|
|
136
|
+
let l;
|
|
137
|
+
if (e === "highlight")
|
|
138
|
+
l = A(i, t, o);
|
|
139
|
+
else if (e === "text")
|
|
140
|
+
l = F(i, t, o);
|
|
141
|
+
else if (e === "ink")
|
|
142
|
+
l = v(i, t, o);
|
|
143
|
+
else
|
|
144
|
+
return {
|
|
145
|
+
annotation: null,
|
|
146
|
+
warnings: [],
|
|
147
|
+
info: [],
|
|
148
|
+
critical: `Annotation at index ${n}: Unsupported type "${e}"`
|
|
149
|
+
};
|
|
150
|
+
return {
|
|
151
|
+
annotation: l,
|
|
152
|
+
warnings: o,
|
|
153
|
+
info: s,
|
|
154
|
+
critical: null
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function E(t, n = {}) {
|
|
158
|
+
n.skipInvalid;
|
|
159
|
+
const o = n.warnInConsole !== !1, s = n.onWarning || null, e = {
|
|
160
|
+
normalized: [],
|
|
161
|
+
warnings: [],
|
|
162
|
+
info: [],
|
|
163
|
+
skipped: []
|
|
164
|
+
};
|
|
165
|
+
if (!Array.isArray(t)) {
|
|
166
|
+
const i = "normalizeAnnotationArray: Input is not an array, returning empty result";
|
|
167
|
+
return e.warnings.push(i), o && console.warn(`[Annotation Normalizer] ${i}`), e;
|
|
168
|
+
}
|
|
169
|
+
return t.forEach((i, l) => {
|
|
170
|
+
if (i == null) {
|
|
171
|
+
e.skipped.push({
|
|
172
|
+
index: l,
|
|
173
|
+
annotation: i,
|
|
174
|
+
reason: "Annotation is null or undefined"
|
|
175
|
+
});
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const u = b(i, l);
|
|
179
|
+
if (u.critical) {
|
|
180
|
+
e.skipped.push({
|
|
181
|
+
index: l,
|
|
182
|
+
annotation: i,
|
|
183
|
+
reason: u.critical
|
|
184
|
+
}), o && console.error(`[Annotation Normalizer] ${u.critical}`);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
e.normalized.push(u.annotation), e.warnings.push(...u.warnings), e.info.push(...u.info);
|
|
188
|
+
}), o && (e.warnings.length > 0 || e.info.length > 0 || e.skipped.length > 0) && (console.group("[Annotation Normalizer] Validation Summary"), e.normalized.length > 0 && console.info(`✓ Normalized ${e.normalized.length} annotation(s)`), e.skipped.length > 0 && (console.error(`✗ Skipped ${e.skipped.length} annotation(s)`), e.skipped.forEach((i) => {
|
|
189
|
+
console.error(` Index ${i.index}: ${i.reason}`);
|
|
190
|
+
})), e.warnings.length > 0 && (console.warn(`⚠ ${e.warnings.length} warning(s):`), e.warnings.forEach((i) => console.warn(` ${i}`))), e.info.length > 0 && (console.info(`ℹ ${e.info.length} info message(s):`), e.info.forEach((i) => console.info(` ${i}`))), console.groupEnd()), s && typeof s == "function" && s(e), e;
|
|
191
|
+
}
|
|
3
192
|
export {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
m as normalizeHighlight,
|
|
14
|
-
t as normalizeInk,
|
|
15
|
-
z as normalizePositiveNumber,
|
|
16
|
-
A as normalizeText
|
|
193
|
+
b as normalizeAnnotation,
|
|
194
|
+
E as normalizeAnnotationArray,
|
|
195
|
+
$ as normalizeBaseFields,
|
|
196
|
+
c as normalizeColor,
|
|
197
|
+
r as normalizeCoordinate,
|
|
198
|
+
A as normalizeHighlight,
|
|
199
|
+
v as normalizeInk,
|
|
200
|
+
h as normalizePositiveNumber,
|
|
201
|
+
F as normalizeText
|
|
17
202
|
};
|
|
18
203
|
//# sourceMappingURL=index13.js.map
|
package/dist/index13.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index13.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
1
|
+
{"version":3,"file":"index13.js","sources":["../src/types/validators.js"],"sourcesContent":["/**\n * Annotation Data Normalization Utilities\n *\n * This module provides defensive normalization functions that validate and fix\n * annotation data. Invalid values are replaced with safe defaults and warnings\n * are collected for user feedback.\n *\n * @module types/validators\n */\n\nimport {\n BASE_DEFAULTS,\n HIGHLIGHT_DEFAULTS,\n TEXT_DEFAULTS,\n INK_DEFAULTS\n} from './defaults.js';\n\n// ============================================================================\n// FIELD-LEVEL NORMALIZERS\n// ============================================================================\n\n/**\n * Normalize coordinate value to 0-1 range\n *\n * Validates that a value is a number in the 0-1 range. Out-of-range values\n * are clamped. Invalid values use the provided default.\n *\n * @param {*} value - Value to normalize\n * @param {number} defaultValue - Fallback value if invalid\n * @param {string} id - Annotation ID for warning messages\n * @param {string} fieldName - Field name for warning messages\n * @param {Array<string>} warnings - Array to collect warning messages\n * @returns {number} Normalized coordinate value in range [0, 1]\n *\n * @example\n * normalizeCoordinate(0.5, 0.1, 'txt-1', 'x', warnings) // Returns: 0.5\n * normalizeCoordinate(5, 0.1, 'txt-1', 'x', warnings) // Returns: 1, adds warning\n * normalizeCoordinate('abc', 0.1, 'txt-1', 'x', warnings) // Returns: 0.1, adds warning\n */\nexport function normalizeCoordinate(value, defaultValue, id, fieldName, warnings) {\n // Type coercion: parse string to number if needed\n let numValue = value;\n if (typeof value === 'string') {\n numValue = parseFloat(value);\n if (!isNaN(numValue) && numValue === value) {\n // Successfully parsed - no warning needed\n }\n }\n\n // Validate is valid number\n if (typeof numValue !== 'number' || isNaN(numValue)) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" invalid value \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n }\n\n // Range check: clamp to [0, 1]\n if (numValue < 0) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" value ${numValue} below range [0,1], clamping to 0`\n );\n return 0;\n }\n\n if (numValue > 1) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" value ${numValue} exceeds range [0,1], clamping to 1`\n );\n return 1;\n }\n\n // Valid value\n return numValue;\n}\n\n/**\n * Normalize color string\n *\n * Validates that a value is a valid color string. Supports hex, rgb/rgba,\n * and named colors. Invalid colors use the provided default.\n *\n * @param {*} value - Color value to normalize\n * @param {string} defaultValue - Fallback color if invalid\n * @param {string} id - Annotation ID for warning messages\n * @param {Array<string>} warnings - Array to collect warning messages\n * @returns {string} Valid color string\n *\n * @example\n * normalizeColor('#fff', '#000', 'txt-1', warnings) // Returns: '#fff'\n * normalizeColor('rgba(255,0,0,0.5)', '#000', 'txt-1', warnings) // Returns: 'rgba(255,0,0,0.5)'\n * normalizeColor('notacolor', '#000', 'txt-1', warnings) // Returns: '#000', adds warning\n */\nexport function normalizeColor(value, defaultValue, id, warnings) {\n // Type check: must be non-empty string\n if (typeof value !== 'string' || value.trim().length === 0) {\n warnings.push(\n `[${id}]: Invalid color format \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n }\n\n const trimmed = value.trim();\n\n // Regex patterns for color validation (cached at module level)\n const hexPattern = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;\n const rgbPattern = /^rgba?\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*(,\\s*[\\d.]+\\s*)?\\)$/;\n\n // Named colors (basic set)\n const namedColors = [\n 'red', 'blue', 'green', 'yellow', 'black', 'white', 'gray',\n 'grey', 'orange', 'purple', 'pink', 'brown', 'transparent'\n ];\n\n // Validate format\n const isHex = hexPattern.test(trimmed);\n const isRgb = rgbPattern.test(trimmed);\n const isNamed = namedColors.includes(trimmed.toLowerCase());\n\n if (isHex || isRgb || isNamed) {\n return trimmed;\n }\n\n // Invalid format\n warnings.push(\n `[${id}]: Invalid color format \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n}\n\n/**\n * Normalize positive number\n *\n * Validates that a value is a positive number. Invalid values use the\n * provided default.\n *\n * @param {*} value - Value to normalize\n * @param {number} defaultValue - Fallback value if invalid\n * @param {string} id - Annotation ID for warning messages\n * @param {string} fieldName - Field name for warning messages\n * @param {Array<string>} warnings - Array to collect warning messages\n * @returns {number} Positive number\n *\n * @example\n * normalizePositiveNumber(5, 3, 'ink-1', 'size', warnings) // Returns: 5\n * normalizePositiveNumber(-1, 3, 'ink-1', 'size', warnings) // Returns: 3, adds warning\n * normalizePositiveNumber('abc', 3, 'ink-1', 'size', warnings) // Returns: 3, adds warning\n */\nexport function normalizePositiveNumber(value, defaultValue, id, fieldName, warnings) {\n // Type coercion: parse string to number if needed\n let numValue = value;\n if (typeof value === 'string') {\n numValue = parseFloat(value);\n }\n\n // Validate is valid number and positive\n if (typeof numValue !== 'number' || isNaN(numValue) || numValue <= 0) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" invalid value \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n }\n\n return numValue;\n}\n\n// ============================================================================\n// BASE FIELDS NORMALIZER\n// ============================================================================\n\n/**\n * Normalize common base annotation fields\n *\n * Validates and normalizes fields common to all annotation types: id, type,\n * page, start, and end. Auto-generates ID if missing. Applies safe defaults\n * for invalid values.\n *\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Array to collect warning messages\n * @param {Array<string>} info - Array to collect info messages\n * @returns {Object} Object with normalized base fields\n *\n * @example\n * normalizeBaseFields({ type: 'text', page: 2 }, warnings, info)\n * // Returns: { id: 'anno-1234...', type: 'text', page: 2, start: 0, end: 0 }\n */\nexport function normalizeBaseFields(raw, warnings, info) {\n const base = {};\n\n // ===== ID Field =====\n // Check: non-empty string\n // Invalid: auto-generate unique ID\n if (typeof raw.id !== 'string' || raw.id.trim().length === 0) {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substr(2, 9);\n base.id = `anno-${timestamp}-${random}`;\n info.push(`[${base.id}]: Auto-generated ID (original was missing or invalid)`);\n } else {\n base.id = raw.id.trim();\n }\n\n // ===== Type Field =====\n // Pass through as-is (validated in parent function)\n base.type = raw.type;\n\n // ===== Page Field =====\n // Check: positive integer\n // Invalid: default to 1\n if (typeof raw.page !== 'number' || raw.page < 1) {\n warnings.push(\n `[${base.id}]: Field \"page\" invalid value \"${raw.page}\", using default ${BASE_DEFAULTS.page}`\n );\n base.page = BASE_DEFAULTS.page;\n } else {\n // Floor to ensure integer\n base.page = Math.floor(raw.page);\n }\n\n // ===== Start Field =====\n // Check: non-negative number\n // Invalid: default to 0\n if (typeof raw.start !== 'number' || raw.start < 0) {\n warnings.push(\n `[${base.id}]: Field \"start\" invalid value \"${raw.start}\", using default ${BASE_DEFAULTS.start}`\n );\n base.start = BASE_DEFAULTS.start;\n } else {\n base.start = raw.start;\n }\n\n // ===== End Field =====\n // Check: non-negative number >= start\n // Invalid: clamp to start value\n if (typeof raw.end !== 'number' || raw.end < 0) {\n warnings.push(\n `[${base.id}]: Field \"end\" invalid value \"${raw.end}\", using start value ${base.start}`\n );\n base.end = base.start;\n } else if (raw.end < base.start) {\n warnings.push(\n `[${base.id}]: Field \"end\" (${raw.end}) less than start (${base.start}), clamping to start`\n );\n base.end = base.start;\n } else {\n base.end = raw.end;\n }\n\n return base;\n}\n\n// ============================================================================\n// TYPE-SPECIFIC NORMALIZERS\n// ============================================================================\n\n/**\n * Normalize a single quad (rectangular region)\n *\n * @private\n * @param {Object} quad - Quad object with x, y, w, h\n * @param {string} id - Annotation ID\n * @param {Array<string>} warnings - Warnings array\n * @returns {Object} Normalized quad\n */\nfunction normalizeQuad(quad, id, warnings) {\n if (!quad || typeof quad !== 'object') {\n warnings.push(`[${id}]: Invalid quad object, using default`);\n return { x: 0.1, y: 0.1, w: 0.8, h: 0.05 };\n }\n\n return {\n x: normalizeCoordinate(quad.x, 0.1, id, 'quad.x', warnings),\n y: normalizeCoordinate(quad.y, 0.1, id, 'quad.y', warnings),\n w: normalizeCoordinate(quad.w, 0.8, id, 'quad.w', warnings),\n h: normalizeCoordinate(quad.h, 0.05, id, 'quad.h', warnings)\n };\n}\n\n/**\n * Normalize highlight annotation\n *\n * Validates and normalizes highlight-specific fields: mode, quads array,\n * and style.color. Applies defaults for invalid fields.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized highlight annotation\n *\n * @example\n * normalizeHighlight(base, raw, warnings, info)\n * // Returns: { ...base, mode: 'quads', quads: [...], style: {...} }\n */\nexport function normalizeHighlight(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Mode Field =====\n // Check: value equals \"quads\"\n // Invalid: default to \"quads\"\n if (raw.mode !== 'quads') {\n warnings.push(\n `[${base.id}]: Field \"mode\" invalid value \"${raw.mode}\", using default \"${HIGHLIGHT_DEFAULTS.mode}\"`\n );\n annotation.mode = HIGHLIGHT_DEFAULTS.mode;\n } else {\n annotation.mode = raw.mode;\n }\n\n // ===== Quads Array =====\n // Check: non-empty array\n // Invalid: use default quads\n if (!Array.isArray(raw.quads) || raw.quads.length === 0) {\n warnings.push(\n `[${base.id}]: Field \"quads\" missing or empty, using default`\n );\n annotation.quads = HIGHLIGHT_DEFAULTS.quads;\n } else {\n // Normalize each quad\n annotation.quads = raw.quads.map((quad, idx) => normalizeQuad(quad, base.id, warnings));\n }\n\n // ===== Style Object =====\n // Check: object with color property\n const defaultColor = HIGHLIGHT_DEFAULTS.style.color;\n if (!raw.style || typeof raw.style !== 'object') {\n warnings.push(\n `[${base.id}]: Field \"style\" missing or invalid, using default`\n );\n annotation.style = { color: defaultColor };\n } else {\n annotation.style = {\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n/**\n * Normalize text annotation\n *\n * Validates and normalizes text-specific fields: content, position (x, y),\n * dimensions (w, h), and style (bg, color). Applies defaults for invalid fields.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized text annotation\n *\n * @example\n * normalizeText(base, raw, warnings, info)\n * // Returns: { ...base, content: '...', x: 0.1, y: 0.1, w: 0.3, h: 0.1, style: {...} }\n */\nexport function normalizeText(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Content Field =====\n // Check: non-empty string\n // Invalid: default to placeholder\n if (typeof raw.content !== 'string' || raw.content.trim().length === 0) {\n warnings.push(\n `[${base.id}]: Field \"content\" missing or empty, using default \"${TEXT_DEFAULTS.content}\"`\n );\n annotation.content = TEXT_DEFAULTS.content;\n } else {\n annotation.content = raw.content;\n }\n\n // ===== Position Fields (x, y) =====\n annotation.x = normalizeCoordinate(raw.x, TEXT_DEFAULTS.x, base.id, 'x', warnings);\n annotation.y = normalizeCoordinate(raw.y, TEXT_DEFAULTS.y, base.id, 'y', warnings);\n\n // ===== Dimension Fields (w, h) =====\n annotation.w = normalizeCoordinate(raw.w, TEXT_DEFAULTS.w, base.id, 'w', warnings);\n annotation.h = normalizeCoordinate(raw.h, TEXT_DEFAULTS.h, base.id, 'h', warnings);\n\n // ===== Style Object =====\n const defaultBg = TEXT_DEFAULTS.style.bg;\n const defaultColor = TEXT_DEFAULTS.style.color;\n\n if (!raw.style || typeof raw.style !== 'object') {\n warnings.push(\n `[${base.id}]: Field \"style\" missing or invalid, using defaults`\n );\n annotation.style = {\n bg: defaultBg,\n color: defaultColor\n };\n } else {\n annotation.style = {\n bg: normalizeColor(raw.style.bg, defaultBg, base.id, warnings),\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n/**\n * Normalize a single ink point\n *\n * @private\n * @param {Object} point - Point object with t, x, y\n * @param {string} id - Annotation ID\n * @param {Array<string>} warnings - Warnings array\n * @returns {Object} Normalized point\n */\nfunction normalizePoint(point, id, warnings) {\n if (!point || typeof point !== 'object') {\n warnings.push(`[${id}]: Invalid point object, using default`);\n return { t: 0, x: 0.1, y: 0.1 };\n }\n\n return {\n t: normalizeCoordinate(point.t, 0, id, 'point.t', warnings),\n x: normalizeCoordinate(point.x, 0.1, id, 'point.x', warnings),\n y: normalizeCoordinate(point.y, 0.1, id, 'point.y', warnings)\n };\n}\n\n/**\n * Normalize a single ink stroke\n *\n * @private\n * @param {Object} stroke - Stroke object with color, size, points\n * @param {string} id - Annotation ID\n * @param {Array<string>} warnings - Warnings array\n * @returns {Object} Normalized stroke\n */\nfunction normalizeStroke(stroke, id, warnings) {\n if (!stroke || typeof stroke !== 'object') {\n warnings.push(`[${id}]: Invalid stroke object, using default`);\n return INK_DEFAULTS.strokes[0];\n }\n\n const normalized = {\n color: normalizeColor(stroke.color, INK_DEFAULTS.strokes[0].color, id, warnings),\n size: normalizePositiveNumber(stroke.size, INK_DEFAULTS.strokes[0].size, id, 'stroke.size', warnings)\n };\n\n // ===== Points Array =====\n if (!Array.isArray(stroke.points) || stroke.points.length === 0) {\n warnings.push(`[${id}]: Stroke missing points array, using default`);\n normalized.points = INK_DEFAULTS.strokes[0].points;\n } else {\n normalized.points = stroke.points.map(point => normalizePoint(point, id, warnings));\n }\n\n return normalized;\n}\n\n/**\n * Normalize ink annotation\n *\n * Validates and normalizes ink-specific fields: strokes array with color,\n * size, and points. Applies defaults for invalid fields.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized ink annotation\n *\n * @example\n * normalizeInk(base, raw, warnings, info)\n * // Returns: { ...base, strokes: [{ color: '...', size: 3, points: [...] }] }\n */\nexport function normalizeInk(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Strokes Array =====\n // Check: non-empty array\n // Invalid: use default single stroke\n if (!Array.isArray(raw.strokes) || raw.strokes.length === 0) {\n warnings.push(\n `[${base.id}]: Field \"strokes\" missing or empty, using default`\n );\n annotation.strokes = INK_DEFAULTS.strokes;\n } else {\n // Normalize each stroke\n annotation.strokes = raw.strokes.map(stroke => normalizeStroke(stroke, base.id, warnings));\n }\n\n return annotation;\n}\n\n// ============================================================================\n// ORCHESTRATION - SINGLE ANNOTATION & ARRAY\n// ============================================================================\n\n/**\n * Normalize a single annotation\n *\n * Routes annotation to appropriate type-specific normalizer based on type field.\n * Handles critical validation errors (missing/invalid type).\n *\n * @param {Object} raw - Raw annotation object\n * @param {number} index - Position in original array (for error context)\n * @returns {Object} Result object with annotation, warnings, info, and critical error\n * @returns {Object|null} return.annotation - Normalized annotation or null if critical error\n * @returns {Array<string>} return.warnings - Warning messages\n * @returns {Array<string>} return.info - Info messages\n * @returns {string|null} return.critical - Critical error message or null\n *\n * @example\n * normalizeAnnotation({ type: 'text', content: 'Hello' }, 0)\n * // Returns: { annotation: {...}, warnings: [], info: [], critical: null }\n */\nexport function normalizeAnnotation(raw, index) {\n const warnings = [];\n const info = [];\n\n // Validate input is object\n if (!raw || typeof raw !== 'object') {\n return {\n annotation: null,\n warnings: [],\n info: [],\n critical: `Annotation at index ${index}: Not a valid object`\n };\n }\n\n // Check type field (critical - cannot route without type)\n if (typeof raw.type !== 'string' || raw.type.trim().length === 0) {\n return {\n annotation: null,\n warnings: [],\n info: [],\n critical: `Annotation at index ${index}: Missing or invalid type field`\n };\n }\n\n const type = raw.type.trim();\n\n // Normalize base fields first\n const base = normalizeBaseFields(raw, warnings, info);\n\n // Route to type-specific normalizer\n let annotation;\n\n if (type === 'highlight') {\n annotation = normalizeHighlight(base, raw, warnings, info);\n } else if (type === 'text') {\n annotation = normalizeText(base, raw, warnings, info);\n } else if (type === 'ink') {\n annotation = normalizeInk(base, raw, warnings, info);\n } else {\n return {\n annotation: null,\n warnings: [],\n info: [],\n critical: `Annotation at index ${index}: Unsupported type \"${type}\"`\n };\n }\n\n return {\n annotation,\n warnings,\n info,\n critical: null\n };\n}\n\n/**\n * Normalize array of annotations\n *\n * MAIN ENTRY POINT for annotation normalization. Processes each annotation,\n * collects warnings, and returns normalized data ready for rendering.\n *\n * @param {Array} rawAnnotations - Array of raw annotation objects\n * @param {Object} [options] - Configuration options\n * @param {boolean} [options.skipInvalid=true] - Skip critically invalid annotations\n * @param {boolean} [options.warnInConsole=true] - Log warnings to console\n * @param {Function} [options.onWarning] - Custom warning callback\n * @returns {Object} ValidationResult with normalized annotations and messages\n * @returns {Array} return.normalized - Successfully normalized annotations\n * @returns {Array<string>} return.warnings - Warning messages\n * @returns {Array<string>} return.info - Informational messages\n * @returns {Array<Object>} return.skipped - Skipped annotations with reasons\n *\n * @example\n * const result = normalizeAnnotationArray(rawAnnotations, {\n * skipInvalid: true,\n * warnInConsole: true\n * });\n *\n * renderer.setAnnotations(result.normalized);\n */\nexport function normalizeAnnotationArray(rawAnnotations, options = {}) {\n // Default options\n const skipInvalid = options.skipInvalid !== false; // Default: true\n const warnInConsole = options.warnInConsole !== false; // Default: true\n const onWarning = options.onWarning || null;\n\n // Initialize result structure\n const result = {\n normalized: [],\n warnings: [],\n info: [],\n skipped: []\n };\n\n // Validate input is array\n if (!Array.isArray(rawAnnotations)) {\n const warning = 'normalizeAnnotationArray: Input is not an array, returning empty result';\n result.warnings.push(warning);\n\n if (warnInConsole) {\n console.warn(`[Annotation Normalizer] ${warning}`);\n }\n\n return result;\n }\n\n // Process each annotation\n rawAnnotations.forEach((raw, index) => {\n // Skip null/undefined\n if (raw == null) {\n result.skipped.push({\n index,\n annotation: raw,\n reason: 'Annotation is null or undefined'\n });\n return;\n }\n\n // Normalize annotation\n const normalized = normalizeAnnotation(raw, index);\n\n // Check for critical error\n if (normalized.critical) {\n result.skipped.push({\n index,\n annotation: raw,\n reason: normalized.critical\n });\n\n if (warnInConsole) {\n console.error(`[Annotation Normalizer] ${normalized.critical}`);\n }\n\n return;\n }\n\n // Add to normalized array\n result.normalized.push(normalized.annotation);\n\n // Collect warnings and info\n result.warnings.push(...normalized.warnings);\n result.info.push(...normalized.info);\n });\n\n // Console output\n if (warnInConsole) {\n if (result.warnings.length > 0 || result.info.length > 0 || result.skipped.length > 0) {\n console.group('[Annotation Normalizer] Validation Summary');\n\n if (result.normalized.length > 0) {\n console.info(`✓ Normalized ${result.normalized.length} annotation(s)`);\n }\n\n if (result.skipped.length > 0) {\n console.error(`✗ Skipped ${result.skipped.length} annotation(s)`);\n result.skipped.forEach(s => {\n console.error(` Index ${s.index}: ${s.reason}`);\n });\n }\n\n if (result.warnings.length > 0) {\n console.warn(`⚠ ${result.warnings.length} warning(s):`);\n result.warnings.forEach(w => console.warn(` ${w}`));\n }\n\n if (result.info.length > 0) {\n console.info(`ℹ ${result.info.length} info message(s):`);\n result.info.forEach(i => console.info(` ${i}`));\n }\n\n console.groupEnd();\n }\n }\n\n // Call custom warning handler\n if (onWarning && typeof onWarning === 'function') {\n onWarning(result);\n }\n\n return result;\n}\n"],"names":["normalizeCoordinate","value","defaultValue","id","fieldName","warnings","numValue","normalizeColor","trimmed","hexPattern","rgbPattern","namedColors","isHex","isRgb","isNamed","normalizePositiveNumber","normalizeBaseFields","raw","info","base","timestamp","random","BASE_DEFAULTS","normalizeQuad","quad","normalizeHighlight","annotation","HIGHLIGHT_DEFAULTS","idx","defaultColor","normalizeText","TEXT_DEFAULTS","defaultBg","normalizePoint","point","normalizeStroke","stroke","INK_DEFAULTS","normalized","normalizeInk","normalizeAnnotation","index","type","normalizeAnnotationArray","rawAnnotations","options","warnInConsole","onWarning","result","warning","s","w"],"mappings":"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"}
|
package/dist/index14.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./index13.cjs"),e=require("./index16.cjs");exports.normalizeAnnotation=o.normalizeAnnotation;exports.normalizeAnnotationArray=o.normalizeAnnotationArray;exports.normalizeBaseFields=o.normalizeBaseFields;exports.normalizeColor=o.normalizeColor;exports.normalizeCoordinate=o.normalizeCoordinate;exports.normalizeHighlight=o.normalizeHighlight;exports.normalizeInk=o.normalizeInk;exports.normalizePositiveNumber=o.normalizePositiveNumber;exports.normalizeText=o.normalizeText;exports.BASE_DEFAULTS=e.BASE_DEFAULTS;exports.HIGHLIGHT_DEFAULTS=e.HIGHLIGHT_DEFAULTS;exports.INK_DEFAULTS=e.INK_DEFAULTS;exports.TEXT_DEFAULTS=e.TEXT_DEFAULTS;
|
|
2
2
|
//# sourceMappingURL=index14.cjs.map
|
package/dist/index14.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index14.cjs","sources":["../src/adapters/AnnotPdf.jsx"],"sourcesContent":["// ============================================================================\n// SECTION 1: IMPORTS\n// ============================================================================\n\nimport { useRef, useEffect, useCallback } from 'react';\nimport { AnnotationRenderer } from '../core/AnnotationRenderer.js';\n\n// ============================================================================\n// SECTION 2: JSDOC DOCUMENTATION\n// ============================================================================\n\n/**\n * AnnotPdf - Declarative React component for PDF annotation rendering\n *\n * A React wrapper around the AnnotationRenderer core engine that provides\n * a declarative, props-based API for rendering PDF documents with\n * timeline-synchronized annotations.\n *\n * Features:\n * - Automatic lifecycle management (initialization and cleanup)\n * - Declarative prop-to-method synchronization\n * - PDF rendering with pdf.js\n * - Timeline-synchronized annotation display\n * - Support for highlight, text, and ink annotations\n * - Page navigation and zoom control\n *\n * @component\n * @example\n * // Basic usage\n * <AnnotPdf\n * pdfUrl=\"/document.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={[]}\n * currentTime={0}\n * />\n *\n * @example\n * // With audio synchronization\n * const [currentTime, setCurrentTime] = useState(0);\n *\n * <div>\n * <AnnotPdf\n * pdfUrl=\"/lecture.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={annotations}\n * currentTime={currentTime}\n * onLoad={({ pageCount }) => console.log('Loaded:', pageCount)}\n * />\n * <audio\n * src=\"/lecture.mp3\"\n * onTimeUpdate={(e) => setCurrentTime(e.target.currentTime)}\n * controls\n * />\n * </div>\n *\n * @param {Object} props - Component props\n * @param {string} props.pdfUrl - PDF document URL (required)\n * @param {number} [props.page=1] - Current page number (1-indexed)\n * @param {number} [props.scale=1.5] - Zoom scale factor\n * @param {Array} [props.annotations=[]] - Array of annotation objects\n * @param {number} [props.currentTime=0] - Timeline position in seconds\n * @param {Function} [props.onLoad] - Callback when PDF loads: ({pageCount}) => void\n * @param {Function} [props.onError] - Callback on error: (error) => void\n * @param {Function} [props.onPageChange] - Callback when page changes: (page) => void\n * @param {string} [props.className] - CSS class for container div\n * @param {Object} [props.style] - Inline styles for container div\n * @param {Object} [props.canvasStyle] - Inline styles for canvas element\n * @returns {JSX.Element} PDF viewer component with annotation layers\n */\n\n// ============================================================================\n// SECTION 3: COMPONENT DEFINITION\n// ============================================================================\n\nfunction AnnotPdf({\n // Required props\n pdfUrl,\n\n // Optional props with defaults\n page = 1,\n scale = 1.5,\n annotations = [],\n currentTime = 0,\n\n // Callbacks\n onLoad,\n onError,\n onPageChange,\n\n // Styling\n className,\n style,\n canvasStyle\n}) {\n\n // ==========================================================================\n // SECTION 4: REFS INITIALIZATION\n // ==========================================================================\n\n /**\n * Reference to the canvas element for PDF rendering\n * @type {React.RefObject<HTMLCanvasElement>}\n */\n const canvasRef = useRef(null);\n\n /**\n * Reference to the layer container div for annotation layers\n * @type {React.RefObject<HTMLDivElement>}\n */\n const layerContainerRef = useRef(null);\n\n /**\n * Reference to the AnnotationRenderer engine instance\n * Stored in ref to avoid triggering re-renders\n * @type {React.RefObject<AnnotationRenderer|null>}\n */\n const engineRef = useRef(null);\n\n /**\n * Reference to the render operation queue\n * Ensures sequential execution of async canvas operations\n * Prevents PDF.js race condition: \"Cannot use the same canvas during multiple render() operations\"\n * @type {React.RefObject<Promise<void>>}\n */\n const renderQueue = useRef(Promise.resolve());\n\n // ==========================================================================\n // SECTION 4.5: RENDER QUEUE HELPER\n // ==========================================================================\n\n /**\n * Queue a render operation to execute sequentially\n *\n * This helper ensures that async canvas operations (loadPDF, setPage, setScale)\n * execute one at a time, preventing concurrent access to the PDF.js canvas.\n * Uses Promise chaining to maintain operation order.\n *\n * @param {Function} operation - Async function returning a Promise\n * @returns {void}\n */\n const queueOperation = useCallback((operation) => {\n renderQueue.current = renderQueue.current\n .then(operation)\n .catch(error => {\n // Log errors but don't break the queue\n console.error('AnnotPdf: Queued operation failed:', error);\n });\n }, []);\n\n // ==========================================================================\n // SECTION 5: ENGINE INITIALIZATION AND CLEANUP\n // ==========================================================================\n\n /**\n * Initialize AnnotationRenderer on component mount\n * Cleanup on component unmount\n */\n useEffect(() => {\n // Guard: Wait for DOM elements to be ready\n if (!canvasRef.current || !layerContainerRef.current) {\n return;\n }\n\n // Initialize engine\n try {\n engineRef.current = new AnnotationRenderer({\n canvasElement: canvasRef.current,\n container: layerContainerRef.current\n });\n } catch (error) {\n console.error('AnnotPdf: Failed to initialize renderer:', error);\n if (onError) {\n onError(error);\n }\n }\n\n // Cleanup on unmount\n return () => {\n if (engineRef.current) {\n engineRef.current.destroy();\n engineRef.current = null;\n }\n };\n }, []); // Empty deps - run once on mount\n\n // ==========================================================================\n // SECTION 6: PDF LOADING SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Load PDF document when pdfUrl prop changes\n * Handles async operation with cancellation support\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and pdfUrl must be valid\n if (!engineRef.current || !pdfUrl) {\n return;\n }\n\n let cancelled = false;\n\n const loadPdf = async () => {\n try {\n const result = await engineRef.current.loadPDF(pdfUrl);\n\n // Check if component unmounted during async operation\n if (cancelled) return;\n\n // Check if load was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to load PDF:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Call onLoad callback with pageCount from result\n if (onLoad) {\n onLoad({ pageCount: result.pageCount });\n }\n } catch (error) {\n if (cancelled) return;\n\n console.error('AnnotPdf: Failed to load PDF:', error);\n if (onError) {\n onError(error);\n }\n }\n };\n\n // Queue the PDF loading operation to prevent race conditions\n queueOperation(loadPdf);\n\n // Cleanup: Prevent state updates if component unmounts during load\n return () => {\n cancelled = true;\n };\n }, [pdfUrl, queueOperation]);\n\n // ==========================================================================\n // SECTION 7: PAGE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync page prop to engine.setPage() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and page must be valid\n if (!engineRef.current || !page || typeof page !== 'number') {\n return;\n }\n\n // Queue the page change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setPage(page);\n\n // Check if page change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set page:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Optional: Notify parent of successful page change\n if (onPageChange) {\n onPageChange(page);\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set page:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [page, queueOperation]);\n\n // ==========================================================================\n // SECTION 8: SCALE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync scale prop to engine.setScale() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and scale must be valid\n if (!engineRef.current || !scale || typeof scale !== 'number') {\n return;\n }\n\n // Queue the scale change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setScale(scale);\n\n // Check if scale change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set scale:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set scale:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [scale, queueOperation]);\n\n // ==========================================================================\n // SECTION 9: ANNOTATIONS SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync annotations prop to engine.setAnnotations() method\n */\n useEffect(() => {\n // Guard: Engine must exist\n if (!engineRef.current) {\n return;\n }\n\n // Sync annotations to engine (default to empty array)\n try {\n engineRef.current.setAnnotations(annotations || []);\n } catch (error) {\n console.error('AnnotPdf: Failed to set annotations:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [annotations]);\n\n // ==========================================================================\n // SECTION 10: TIMELINE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync currentTime prop to engine.setTime() method\n */\n useEffect(() => {\n // Guard: Engine must exist and currentTime must be defined\n if (!engineRef.current || currentTime === undefined || currentTime === null) {\n return;\n }\n\n // Sync timeline to engine\n try {\n engineRef.current.setTime(currentTime);\n } catch (error) {\n console.error('AnnotPdf: Failed to set time:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [currentTime]);\n\n // ==========================================================================\n // SECTION 11: STYLING DEFINITIONS\n // ==========================================================================\n\n /**\n * Default container styles\n * Merged with user-provided styles (user styles override defaults)\n */\n const defaultContainerStyle = {\n position: 'relative',\n display: 'inline-block',\n lineHeight: 0, // Remove extra space below canvas\n ...style // User styles override defaults\n };\n\n /**\n * Default layer container styles\n * Positions layer div absolutely over canvas\n */\n const defaultLayerStyle = {\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: '100%',\n pointerEvents: 'none', // Allow clicks to pass through to canvas\n overflow: 'hidden'\n };\n\n /**\n * Default canvas styles\n * Merged with user-provided canvasStyle\n */\n const defaultCanvasStyle = {\n display: 'block',\n ...canvasStyle // User styles override defaults\n };\n\n // ==========================================================================\n // SECTION 12: JSX RETURN\n // ==========================================================================\n\n return (\n <div className={className} style={defaultContainerStyle}>\n <canvas ref={canvasRef} style={defaultCanvasStyle} />\n <div ref={layerContainerRef} style={defaultLayerStyle} />\n </div>\n );\n}\n\n// ============================================================================\n// SECTION 13: EXPORT\n// ============================================================================\n\nexport default AnnotPdf;\n"],"names":["AnnotPdf","pdfUrl","page","scale","annotations","currentTime","onLoad","onError","onPageChange","className","style","canvasStyle","canvasRef","useRef","layerContainerRef","engineRef","renderQueue","queueOperation","useCallback","operation","error","useEffect","AnnotationRenderer","cancelled","result","defaultContainerStyle","defaultLayerStyle","defaultCanvasStyle","jsxs","jsx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index14.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/dist/index14.js
CHANGED
|
@@ -1,126 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { AnnotationRenderer as x } from "./index2.js";
|
|
4
|
-
function Q({
|
|
5
|
-
// Required props
|
|
6
|
-
pdfUrl: a,
|
|
7
|
-
// Optional props with defaults
|
|
8
|
-
page: i = 1,
|
|
9
|
-
scale: s = 1.5,
|
|
10
|
-
annotations: y = [],
|
|
11
|
-
currentTime: l = 0,
|
|
12
|
-
// Callbacks
|
|
13
|
-
onLoad: P,
|
|
14
|
-
onError: t,
|
|
15
|
-
onPageChange: h,
|
|
16
|
-
// Styling
|
|
17
|
-
className: v,
|
|
18
|
-
style: m,
|
|
19
|
-
canvasStyle: w
|
|
20
|
-
}) {
|
|
21
|
-
const f = u(null), d = u(null), r = u(null), A = u(Promise.resolve()), o = k((e) => {
|
|
22
|
-
A.current = A.current.then(e).catch((p) => {
|
|
23
|
-
console.error("AnnotPdf: Queued operation failed:", p);
|
|
24
|
-
});
|
|
25
|
-
}, []);
|
|
26
|
-
c(() => {
|
|
27
|
-
if (!(!f.current || !d.current)) {
|
|
28
|
-
try {
|
|
29
|
-
r.current = new x({
|
|
30
|
-
canvasElement: f.current,
|
|
31
|
-
container: d.current
|
|
32
|
-
});
|
|
33
|
-
} catch (e) {
|
|
34
|
-
console.error("AnnotPdf: Failed to initialize renderer:", e), t && t(e);
|
|
35
|
-
}
|
|
36
|
-
return () => {
|
|
37
|
-
r.current && (r.current.destroy(), r.current = null);
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
}, []), c(() => {
|
|
41
|
-
if (!r.current || !a)
|
|
42
|
-
return;
|
|
43
|
-
let e = !1;
|
|
44
|
-
return o(async () => {
|
|
45
|
-
try {
|
|
46
|
-
const n = await r.current.loadPDF(a);
|
|
47
|
-
if (e) return;
|
|
48
|
-
if (!n.success) {
|
|
49
|
-
console.error("AnnotPdf: Failed to load PDF:", n.error), t && t(new Error(n.error));
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
P && P({ pageCount: n.pageCount });
|
|
53
|
-
} catch (n) {
|
|
54
|
-
if (e) return;
|
|
55
|
-
console.error("AnnotPdf: Failed to load PDF:", n), t && t(n);
|
|
56
|
-
}
|
|
57
|
-
}), () => {
|
|
58
|
-
e = !0;
|
|
59
|
-
};
|
|
60
|
-
}, [a, o]), c(() => {
|
|
61
|
-
!r.current || !i || typeof i != "number" || o(async () => {
|
|
62
|
-
try {
|
|
63
|
-
const e = await r.current.setPage(i);
|
|
64
|
-
if (!e.success) {
|
|
65
|
-
console.error("AnnotPdf: Failed to set page:", e.error), t && t(new Error(e.error));
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
h && h(i);
|
|
69
|
-
} catch (e) {
|
|
70
|
-
console.error("AnnotPdf: Failed to set page:", e), t && t(e);
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
}, [i, o]), c(() => {
|
|
74
|
-
!r.current || !s || typeof s != "number" || o(async () => {
|
|
75
|
-
try {
|
|
76
|
-
const e = await r.current.setScale(s);
|
|
77
|
-
e.success || (console.error("AnnotPdf: Failed to set scale:", e.error), t && t(new Error(e.error)));
|
|
78
|
-
} catch (e) {
|
|
79
|
-
console.error("AnnotPdf: Failed to set scale:", e), t && t(e);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}, [s, o]), c(() => {
|
|
83
|
-
if (r.current)
|
|
84
|
-
try {
|
|
85
|
-
r.current.setAnnotations(y || []);
|
|
86
|
-
} catch (e) {
|
|
87
|
-
console.error("AnnotPdf: Failed to set annotations:", e), t && t(e);
|
|
88
|
-
}
|
|
89
|
-
}, [y]), c(() => {
|
|
90
|
-
if (!(!r.current || l === void 0 || l === null))
|
|
91
|
-
try {
|
|
92
|
-
r.current.setTime(l);
|
|
93
|
-
} catch (e) {
|
|
94
|
-
console.error("AnnotPdf: Failed to set time:", e), t && t(e);
|
|
95
|
-
}
|
|
96
|
-
}, [l]);
|
|
97
|
-
const b = {
|
|
98
|
-
position: "relative",
|
|
99
|
-
display: "inline-block",
|
|
100
|
-
lineHeight: 0,
|
|
101
|
-
// Remove extra space below canvas
|
|
102
|
-
...m
|
|
103
|
-
// User styles override defaults
|
|
104
|
-
}, C = {
|
|
105
|
-
position: "absolute",
|
|
106
|
-
top: 0,
|
|
107
|
-
left: 0,
|
|
108
|
-
width: "100%",
|
|
109
|
-
height: "100%",
|
|
110
|
-
pointerEvents: "none",
|
|
111
|
-
// Allow clicks to pass through to canvas
|
|
112
|
-
overflow: "hidden"
|
|
113
|
-
}, R = {
|
|
114
|
-
display: "block",
|
|
115
|
-
...w
|
|
116
|
-
// User styles override defaults
|
|
117
|
-
};
|
|
118
|
-
return /* @__PURE__ */ S("div", { className: v, style: b, children: [
|
|
119
|
-
/* @__PURE__ */ F("canvas", { ref: f, style: R }),
|
|
120
|
-
/* @__PURE__ */ F("div", { ref: d, style: C })
|
|
121
|
-
] });
|
|
122
|
-
}
|
|
1
|
+
import { normalizeAnnotation as e, normalizeAnnotationArray as i, normalizeBaseFields as n, normalizeColor as a, normalizeCoordinate as l, normalizeHighlight as m, normalizeInk as t, normalizePositiveNumber as z, normalizeText as A } from "./index13.js";
|
|
2
|
+
import { BASE_DEFAULTS as E, HIGHLIGHT_DEFAULTS as F, INK_DEFAULTS as L, TEXT_DEFAULTS as S } from "./index16.js";
|
|
123
3
|
export {
|
|
124
|
-
|
|
4
|
+
E as BASE_DEFAULTS,
|
|
5
|
+
F as HIGHLIGHT_DEFAULTS,
|
|
6
|
+
L as INK_DEFAULTS,
|
|
7
|
+
S as TEXT_DEFAULTS,
|
|
8
|
+
e as normalizeAnnotation,
|
|
9
|
+
i as normalizeAnnotationArray,
|
|
10
|
+
n as normalizeBaseFields,
|
|
11
|
+
a as normalizeColor,
|
|
12
|
+
l as normalizeCoordinate,
|
|
13
|
+
m as normalizeHighlight,
|
|
14
|
+
t as normalizeInk,
|
|
15
|
+
z as normalizePositiveNumber,
|
|
16
|
+
A as normalizeText
|
|
125
17
|
};
|
|
126
18
|
//# sourceMappingURL=index14.js.map
|
package/dist/index14.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index14.js","sources":["../src/adapters/AnnotPdf.jsx"],"sourcesContent":["// ============================================================================\n// SECTION 1: IMPORTS\n// ============================================================================\n\nimport { useRef, useEffect, useCallback } from 'react';\nimport { AnnotationRenderer } from '../core/AnnotationRenderer.js';\n\n// ============================================================================\n// SECTION 2: JSDOC DOCUMENTATION\n// ============================================================================\n\n/**\n * AnnotPdf - Declarative React component for PDF annotation rendering\n *\n * A React wrapper around the AnnotationRenderer core engine that provides\n * a declarative, props-based API for rendering PDF documents with\n * timeline-synchronized annotations.\n *\n * Features:\n * - Automatic lifecycle management (initialization and cleanup)\n * - Declarative prop-to-method synchronization\n * - PDF rendering with pdf.js\n * - Timeline-synchronized annotation display\n * - Support for highlight, text, and ink annotations\n * - Page navigation and zoom control\n *\n * @component\n * @example\n * // Basic usage\n * <AnnotPdf\n * pdfUrl=\"/document.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={[]}\n * currentTime={0}\n * />\n *\n * @example\n * // With audio synchronization\n * const [currentTime, setCurrentTime] = useState(0);\n *\n * <div>\n * <AnnotPdf\n * pdfUrl=\"/lecture.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={annotations}\n * currentTime={currentTime}\n * onLoad={({ pageCount }) => console.log('Loaded:', pageCount)}\n * />\n * <audio\n * src=\"/lecture.mp3\"\n * onTimeUpdate={(e) => setCurrentTime(e.target.currentTime)}\n * controls\n * />\n * </div>\n *\n * @param {Object} props - Component props\n * @param {string} props.pdfUrl - PDF document URL (required)\n * @param {number} [props.page=1] - Current page number (1-indexed)\n * @param {number} [props.scale=1.5] - Zoom scale factor\n * @param {Array} [props.annotations=[]] - Array of annotation objects\n * @param {number} [props.currentTime=0] - Timeline position in seconds\n * @param {Function} [props.onLoad] - Callback when PDF loads: ({pageCount}) => void\n * @param {Function} [props.onError] - Callback on error: (error) => void\n * @param {Function} [props.onPageChange] - Callback when page changes: (page) => void\n * @param {string} [props.className] - CSS class for container div\n * @param {Object} [props.style] - Inline styles for container div\n * @param {Object} [props.canvasStyle] - Inline styles for canvas element\n * @returns {JSX.Element} PDF viewer component with annotation layers\n */\n\n// ============================================================================\n// SECTION 3: COMPONENT DEFINITION\n// ============================================================================\n\nfunction AnnotPdf({\n // Required props\n pdfUrl,\n\n // Optional props with defaults\n page = 1,\n scale = 1.5,\n annotations = [],\n currentTime = 0,\n\n // Callbacks\n onLoad,\n onError,\n onPageChange,\n\n // Styling\n className,\n style,\n canvasStyle\n}) {\n\n // ==========================================================================\n // SECTION 4: REFS INITIALIZATION\n // ==========================================================================\n\n /**\n * Reference to the canvas element for PDF rendering\n * @type {React.RefObject<HTMLCanvasElement>}\n */\n const canvasRef = useRef(null);\n\n /**\n * Reference to the layer container div for annotation layers\n * @type {React.RefObject<HTMLDivElement>}\n */\n const layerContainerRef = useRef(null);\n\n /**\n * Reference to the AnnotationRenderer engine instance\n * Stored in ref to avoid triggering re-renders\n * @type {React.RefObject<AnnotationRenderer|null>}\n */\n const engineRef = useRef(null);\n\n /**\n * Reference to the render operation queue\n * Ensures sequential execution of async canvas operations\n * Prevents PDF.js race condition: \"Cannot use the same canvas during multiple render() operations\"\n * @type {React.RefObject<Promise<void>>}\n */\n const renderQueue = useRef(Promise.resolve());\n\n // ==========================================================================\n // SECTION 4.5: RENDER QUEUE HELPER\n // ==========================================================================\n\n /**\n * Queue a render operation to execute sequentially\n *\n * This helper ensures that async canvas operations (loadPDF, setPage, setScale)\n * execute one at a time, preventing concurrent access to the PDF.js canvas.\n * Uses Promise chaining to maintain operation order.\n *\n * @param {Function} operation - Async function returning a Promise\n * @returns {void}\n */\n const queueOperation = useCallback((operation) => {\n renderQueue.current = renderQueue.current\n .then(operation)\n .catch(error => {\n // Log errors but don't break the queue\n console.error('AnnotPdf: Queued operation failed:', error);\n });\n }, []);\n\n // ==========================================================================\n // SECTION 5: ENGINE INITIALIZATION AND CLEANUP\n // ==========================================================================\n\n /**\n * Initialize AnnotationRenderer on component mount\n * Cleanup on component unmount\n */\n useEffect(() => {\n // Guard: Wait for DOM elements to be ready\n if (!canvasRef.current || !layerContainerRef.current) {\n return;\n }\n\n // Initialize engine\n try {\n engineRef.current = new AnnotationRenderer({\n canvasElement: canvasRef.current,\n container: layerContainerRef.current\n });\n } catch (error) {\n console.error('AnnotPdf: Failed to initialize renderer:', error);\n if (onError) {\n onError(error);\n }\n }\n\n // Cleanup on unmount\n return () => {\n if (engineRef.current) {\n engineRef.current.destroy();\n engineRef.current = null;\n }\n };\n }, []); // Empty deps - run once on mount\n\n // ==========================================================================\n // SECTION 6: PDF LOADING SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Load PDF document when pdfUrl prop changes\n * Handles async operation with cancellation support\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and pdfUrl must be valid\n if (!engineRef.current || !pdfUrl) {\n return;\n }\n\n let cancelled = false;\n\n const loadPdf = async () => {\n try {\n const result = await engineRef.current.loadPDF(pdfUrl);\n\n // Check if component unmounted during async operation\n if (cancelled) return;\n\n // Check if load was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to load PDF:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Call onLoad callback with pageCount from result\n if (onLoad) {\n onLoad({ pageCount: result.pageCount });\n }\n } catch (error) {\n if (cancelled) return;\n\n console.error('AnnotPdf: Failed to load PDF:', error);\n if (onError) {\n onError(error);\n }\n }\n };\n\n // Queue the PDF loading operation to prevent race conditions\n queueOperation(loadPdf);\n\n // Cleanup: Prevent state updates if component unmounts during load\n return () => {\n cancelled = true;\n };\n }, [pdfUrl, queueOperation]);\n\n // ==========================================================================\n // SECTION 7: PAGE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync page prop to engine.setPage() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and page must be valid\n if (!engineRef.current || !page || typeof page !== 'number') {\n return;\n }\n\n // Queue the page change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setPage(page);\n\n // Check if page change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set page:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Optional: Notify parent of successful page change\n if (onPageChange) {\n onPageChange(page);\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set page:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [page, queueOperation]);\n\n // ==========================================================================\n // SECTION 8: SCALE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync scale prop to engine.setScale() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and scale must be valid\n if (!engineRef.current || !scale || typeof scale !== 'number') {\n return;\n }\n\n // Queue the scale change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setScale(scale);\n\n // Check if scale change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set scale:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set scale:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [scale, queueOperation]);\n\n // ==========================================================================\n // SECTION 9: ANNOTATIONS SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync annotations prop to engine.setAnnotations() method\n */\n useEffect(() => {\n // Guard: Engine must exist\n if (!engineRef.current) {\n return;\n }\n\n // Sync annotations to engine (default to empty array)\n try {\n engineRef.current.setAnnotations(annotations || []);\n } catch (error) {\n console.error('AnnotPdf: Failed to set annotations:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [annotations]);\n\n // ==========================================================================\n // SECTION 10: TIMELINE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync currentTime prop to engine.setTime() method\n */\n useEffect(() => {\n // Guard: Engine must exist and currentTime must be defined\n if (!engineRef.current || currentTime === undefined || currentTime === null) {\n return;\n }\n\n // Sync timeline to engine\n try {\n engineRef.current.setTime(currentTime);\n } catch (error) {\n console.error('AnnotPdf: Failed to set time:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [currentTime]);\n\n // ==========================================================================\n // SECTION 11: STYLING DEFINITIONS\n // ==========================================================================\n\n /**\n * Default container styles\n * Merged with user-provided styles (user styles override defaults)\n */\n const defaultContainerStyle = {\n position: 'relative',\n display: 'inline-block',\n lineHeight: 0, // Remove extra space below canvas\n ...style // User styles override defaults\n };\n\n /**\n * Default layer container styles\n * Positions layer div absolutely over canvas\n */\n const defaultLayerStyle = {\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: '100%',\n pointerEvents: 'none', // Allow clicks to pass through to canvas\n overflow: 'hidden'\n };\n\n /**\n * Default canvas styles\n * Merged with user-provided canvasStyle\n */\n const defaultCanvasStyle = {\n display: 'block',\n ...canvasStyle // User styles override defaults\n };\n\n // ==========================================================================\n // SECTION 12: JSX RETURN\n // ==========================================================================\n\n return (\n <div className={className} style={defaultContainerStyle}>\n <canvas ref={canvasRef} style={defaultCanvasStyle} />\n <div ref={layerContainerRef} style={defaultLayerStyle} />\n </div>\n );\n}\n\n// ============================================================================\n// SECTION 13: EXPORT\n// ============================================================================\n\nexport default AnnotPdf;\n"],"names":["AnnotPdf","pdfUrl","page","scale","annotations","currentTime","onLoad","onError","onPageChange","className","style","canvasStyle","canvasRef","useRef","layerContainerRef","engineRef","renderQueue","queueOperation","useCallback","operation","error","useEffect","AnnotationRenderer","cancelled","result","defaultContainerStyle","defaultLayerStyle","defaultCanvasStyle","jsxs","jsx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index14.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
package/dist/index15.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const d=require("react/jsx-runtime"),n=require("react"),j=require("./index2.cjs");function m({pdfUrl:l,page:c=1,scale:u=1.5,annotations:y=[],currentTime:i=0,onLoad:P,onError:t,onPageChange:A,className:F,style:R,canvasStyle:p}){const f=n.useRef(null),a=n.useRef(null),r=n.useRef(null),h=n.useRef(Promise.resolve()),o=n.useCallback(e=>{h.current=h.current.then(e).catch(v=>{console.error("AnnotPdf: Queued operation failed:",v)})},[]);n.useEffect(()=>{if(!(!f.current||!a.current)){try{r.current=new j.AnnotationRenderer({canvasElement:f.current,container:a.current})}catch(e){console.error("AnnotPdf: Failed to initialize renderer:",e),t&&t(e)}return()=>{r.current&&(r.current.destroy(),r.current=null)}}},[]),n.useEffect(()=>{if(!r.current||!l)return;let e=!1;return o(async()=>{try{const s=await r.current.loadPDF(l);if(e)return;if(!s.success){console.error("AnnotPdf: Failed to load PDF:",s.error),t&&t(new Error(s.error));return}P&&P({pageCount:s.pageCount})}catch(s){if(e)return;console.error("AnnotPdf: Failed to load PDF:",s),t&&t(s)}}),()=>{e=!0}},[l,o]),n.useEffect(()=>{!r.current||!c||typeof c!="number"||o(async()=>{try{const e=await r.current.setPage(c);if(!e.success){console.error("AnnotPdf: Failed to set page:",e.error),t&&t(new Error(e.error));return}A&&A(c)}catch(e){console.error("AnnotPdf: Failed to set page:",e),t&&t(e)}})},[c,o]),n.useEffect(()=>{!r.current||!u||typeof u!="number"||o(async()=>{try{const e=await r.current.setScale(u);e.success||(console.error("AnnotPdf: Failed to set scale:",e.error),t&&t(new Error(e.error)))}catch(e){console.error("AnnotPdf: Failed to set scale:",e),t&&t(e)}})},[u,o]),n.useEffect(()=>{if(r.current)try{r.current.setAnnotations(y||[])}catch(e){console.error("AnnotPdf: Failed to set annotations:",e),t&&t(e)}},[y]),n.useEffect(()=>{if(!(!r.current||i===void 0||i===null))try{r.current.setTime(i)}catch(e){console.error("AnnotPdf: Failed to set time:",e),t&&t(e)}},[i]);const w={position:"relative",display:"inline-block",lineHeight:0,...R},b={position:"absolute",top:0,left:0,width:"100%",height:"100%",pointerEvents:"none",overflow:"hidden"},S={display:"block",...p};return d.jsxs("div",{className:F,style:w,children:[d.jsx("canvas",{ref:f,style:S}),d.jsx("div",{ref:a,style:b})]})}exports.default=m;
|
|
2
2
|
//# sourceMappingURL=index15.cjs.map
|
package/dist/index15.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index15.cjs","sources":["../src/types/defaults.js"],"sourcesContent":["/**\n * Default Values for Annotation Normalization\n *\n * This module defines default values used when annotation fields are missing\n * or invalid. These defaults ensure annotations render visibly and safely.\n *\n * @module types/defaults\n */\n\n/**\n * Default values for base annotation fields (common to all types)\n *\n * @constant {Object}\n * @property {number} page - Default page number (first page)\n * @property {number} start - Default start time (display immediately)\n * @property {number} end - Default end time (static display, no animation)\n */\nexport const BASE_DEFAULTS = {\n page: 1,\n start: 0,\n end: 0\n};\n\n/**\n * Default values for highlight annotations\n *\n * Creates a visible yellow highlight near the top of the page.\n *\n * @constant {Object}\n * @property {string} mode - Highlight mode (only 'quads' supported)\n * @property {Array<Object>} quads - Default rectangular regions\n * @property {Object} style - Default styling\n */\nexport const HIGHLIGHT_DEFAULTS = {\n mode: 'quads',\n quads: [{ x: 0.1, y: 0.1, w: 0.8, h: 0.05 }],\n style: { color: 'rgba(255, 255, 0, 0.3)' }\n};\n\n/**\n * Default values for text annotations\n *\n * Creates a visible text box in the top-left with placeholder content.\n *\n * @constant {Object}\n * @property {string} content - Placeholder text\n * @property {number} x - Normalized x position (10% from left)\n * @property {number} y - Normalized y position (10% from top)\n * @property {number} w - Normalized width (30% of page width)\n * @property {number} h - Normalized height (10% of page height)\n * @property {Object} style - Default styling with white background and black text\n */\nexport const TEXT_DEFAULTS = {\n content: '[No content]',\n x: 0.1,\n y: 0.1,\n w: 0.3,\n h: 0.1,\n style: {\n bg: 'rgba(255, 255, 255, 0.9)',\n color: '#000000'\n }\n};\n\n/**\n * Default values for ink annotations\n *\n * Creates a visible diagonal line in dark gray.\n *\n * @constant {Object}\n * @property {Array<Object>} strokes - Default stroke with two points\n */\nexport const INK_DEFAULTS = {\n strokes: [{\n color: '#1f2937',\n size: 3,\n points: [\n { t: 0, x: 0.1, y: 0.1 },\n { t: 1, x: 0.2, y: 0.2 }\n ]\n }]\n};\n"],"names":["BASE_DEFAULTS","HIGHLIGHT_DEFAULTS","TEXT_DEFAULTS","INK_DEFAULTS"],"mappings":"gFAiBY,MAACA,EAAgB,CAC3B,KAAM,EACN,MAAO,EACP,IAAK,CACP,EAYaC,EAAqB,CAChC,KAAM,QACN,MAAO,CAAC,CAAE,EAAG,GAAK,EAAG,GAAK,EAAG,GAAK,EAAG,IAAM,EAC3C,MAAO,CAAE,MAAO,wBAAwB,CAC1C,EAeaC,EAAgB,CAC3B,QAAS,eACT,EAAG,GACH,EAAG,GACH,EAAG,GACH,EAAG,GACH,MAAO,CACL,GAAI,2BACJ,MAAO,SACX,CACA,EAUaC,EAAe,CAC1B,QAAS,CAAC,CACR,MAAO,UACP,KAAM,EACN,OAAQ,CACN,CAAE,EAAG,EAAG,EAAG,GAAK,EAAG,EAAG,EACtB,CAAE,EAAG,EAAG,EAAG,GAAK,EAAG,EAAG,CAC5B,CACA,CAAG,CACH"}
|
|
1
|
+
{"version":3,"file":"index15.cjs","sources":["../src/adapters/AnnotPdf.jsx"],"sourcesContent":["// ============================================================================\n// SECTION 1: IMPORTS\n// ============================================================================\n\nimport { useRef, useEffect, useCallback } from 'react';\nimport { AnnotationRenderer } from '../core/AnnotationRenderer.js';\n\n// ============================================================================\n// SECTION 2: JSDOC DOCUMENTATION\n// ============================================================================\n\n/**\n * AnnotPdf - Declarative React component for PDF annotation rendering\n *\n * A React wrapper around the AnnotationRenderer core engine that provides\n * a declarative, props-based API for rendering PDF documents with\n * timeline-synchronized annotations.\n *\n * Features:\n * - Automatic lifecycle management (initialization and cleanup)\n * - Declarative prop-to-method synchronization\n * - PDF rendering with pdf.js\n * - Timeline-synchronized annotation display\n * - Support for highlight, text, and ink annotations\n * - Page navigation and zoom control\n *\n * @component\n * @example\n * // Basic usage\n * <AnnotPdf\n * pdfUrl=\"/document.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={[]}\n * currentTime={0}\n * />\n *\n * @example\n * // With audio synchronization\n * const [currentTime, setCurrentTime] = useState(0);\n *\n * <div>\n * <AnnotPdf\n * pdfUrl=\"/lecture.pdf\"\n * page={1}\n * scale={1.5}\n * annotations={annotations}\n * currentTime={currentTime}\n * onLoad={({ pageCount }) => console.log('Loaded:', pageCount)}\n * />\n * <audio\n * src=\"/lecture.mp3\"\n * onTimeUpdate={(e) => setCurrentTime(e.target.currentTime)}\n * controls\n * />\n * </div>\n *\n * @param {Object} props - Component props\n * @param {string} props.pdfUrl - PDF document URL (required)\n * @param {number} [props.page=1] - Current page number (1-indexed)\n * @param {number} [props.scale=1.5] - Zoom scale factor\n * @param {Array} [props.annotations=[]] - Array of annotation objects\n * @param {number} [props.currentTime=0] - Timeline position in seconds\n * @param {Function} [props.onLoad] - Callback when PDF loads: ({pageCount}) => void\n * @param {Function} [props.onError] - Callback on error: (error) => void\n * @param {Function} [props.onPageChange] - Callback when page changes: (page) => void\n * @param {string} [props.className] - CSS class for container div\n * @param {Object} [props.style] - Inline styles for container div\n * @param {Object} [props.canvasStyle] - Inline styles for canvas element\n * @returns {JSX.Element} PDF viewer component with annotation layers\n */\n\n// ============================================================================\n// SECTION 3: COMPONENT DEFINITION\n// ============================================================================\n\nfunction AnnotPdf({\n // Required props\n pdfUrl,\n\n // Optional props with defaults\n page = 1,\n scale = 1.5,\n annotations = [],\n currentTime = 0,\n\n // Callbacks\n onLoad,\n onError,\n onPageChange,\n\n // Styling\n className,\n style,\n canvasStyle\n}) {\n\n // ==========================================================================\n // SECTION 4: REFS INITIALIZATION\n // ==========================================================================\n\n /**\n * Reference to the canvas element for PDF rendering\n * @type {React.RefObject<HTMLCanvasElement>}\n */\n const canvasRef = useRef(null);\n\n /**\n * Reference to the layer container div for annotation layers\n * @type {React.RefObject<HTMLDivElement>}\n */\n const layerContainerRef = useRef(null);\n\n /**\n * Reference to the AnnotationRenderer engine instance\n * Stored in ref to avoid triggering re-renders\n * @type {React.RefObject<AnnotationRenderer|null>}\n */\n const engineRef = useRef(null);\n\n /**\n * Reference to the render operation queue\n * Ensures sequential execution of async canvas operations\n * Prevents PDF.js race condition: \"Cannot use the same canvas during multiple render() operations\"\n * @type {React.RefObject<Promise<void>>}\n */\n const renderQueue = useRef(Promise.resolve());\n\n // ==========================================================================\n // SECTION 4.5: RENDER QUEUE HELPER\n // ==========================================================================\n\n /**\n * Queue a render operation to execute sequentially\n *\n * This helper ensures that async canvas operations (loadPDF, setPage, setScale)\n * execute one at a time, preventing concurrent access to the PDF.js canvas.\n * Uses Promise chaining to maintain operation order.\n *\n * @param {Function} operation - Async function returning a Promise\n * @returns {void}\n */\n const queueOperation = useCallback((operation) => {\n renderQueue.current = renderQueue.current\n .then(operation)\n .catch(error => {\n // Log errors but don't break the queue\n console.error('AnnotPdf: Queued operation failed:', error);\n });\n }, []);\n\n // ==========================================================================\n // SECTION 5: ENGINE INITIALIZATION AND CLEANUP\n // ==========================================================================\n\n /**\n * Initialize AnnotationRenderer on component mount\n * Cleanup on component unmount\n */\n useEffect(() => {\n // Guard: Wait for DOM elements to be ready\n if (!canvasRef.current || !layerContainerRef.current) {\n return;\n }\n\n // Initialize engine\n try {\n engineRef.current = new AnnotationRenderer({\n canvasElement: canvasRef.current,\n container: layerContainerRef.current\n });\n } catch (error) {\n console.error('AnnotPdf: Failed to initialize renderer:', error);\n if (onError) {\n onError(error);\n }\n }\n\n // Cleanup on unmount\n return () => {\n if (engineRef.current) {\n engineRef.current.destroy();\n engineRef.current = null;\n }\n };\n }, []); // Empty deps - run once on mount\n\n // ==========================================================================\n // SECTION 6: PDF LOADING SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Load PDF document when pdfUrl prop changes\n * Handles async operation with cancellation support\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and pdfUrl must be valid\n if (!engineRef.current || !pdfUrl) {\n return;\n }\n\n let cancelled = false;\n\n const loadPdf = async () => {\n try {\n const result = await engineRef.current.loadPDF(pdfUrl);\n\n // Check if component unmounted during async operation\n if (cancelled) return;\n\n // Check if load was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to load PDF:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Call onLoad callback with pageCount from result\n if (onLoad) {\n onLoad({ pageCount: result.pageCount });\n }\n } catch (error) {\n if (cancelled) return;\n\n console.error('AnnotPdf: Failed to load PDF:', error);\n if (onError) {\n onError(error);\n }\n }\n };\n\n // Queue the PDF loading operation to prevent race conditions\n queueOperation(loadPdf);\n\n // Cleanup: Prevent state updates if component unmounts during load\n return () => {\n cancelled = true;\n };\n }, [pdfUrl, queueOperation]);\n\n // ==========================================================================\n // SECTION 7: PAGE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync page prop to engine.setPage() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and page must be valid\n if (!engineRef.current || !page || typeof page !== 'number') {\n return;\n }\n\n // Queue the page change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setPage(page);\n\n // Check if page change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set page:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n return;\n }\n\n // Optional: Notify parent of successful page change\n if (onPageChange) {\n onPageChange(page);\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set page:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [page, queueOperation]);\n\n // ==========================================================================\n // SECTION 8: SCALE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync scale prop to engine.setScale() method\n * Uses render queue to prevent concurrent canvas operations\n */\n useEffect(() => {\n // Guard: Engine must exist and scale must be valid\n if (!engineRef.current || !scale || typeof scale !== 'number') {\n return;\n }\n\n // Queue the scale change operation to prevent race conditions\n queueOperation(async () => {\n try {\n const result = await engineRef.current.setScale(scale);\n\n // Check if scale change was successful\n if (!result.success) {\n console.error('AnnotPdf: Failed to set scale:', result.error);\n if (onError) {\n onError(new Error(result.error));\n }\n }\n } catch (error) {\n console.error('AnnotPdf: Failed to set scale:', error);\n if (onError) {\n onError(error);\n }\n }\n });\n }, [scale, queueOperation]);\n\n // ==========================================================================\n // SECTION 9: ANNOTATIONS SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync annotations prop to engine.setAnnotations() method\n */\n useEffect(() => {\n // Guard: Engine must exist\n if (!engineRef.current) {\n return;\n }\n\n // Sync annotations to engine (default to empty array)\n try {\n engineRef.current.setAnnotations(annotations || []);\n } catch (error) {\n console.error('AnnotPdf: Failed to set annotations:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [annotations]);\n\n // ==========================================================================\n // SECTION 10: TIMELINE SYNCHRONIZATION\n // ==========================================================================\n\n /**\n * Sync currentTime prop to engine.setTime() method\n */\n useEffect(() => {\n // Guard: Engine must exist and currentTime must be defined\n if (!engineRef.current || currentTime === undefined || currentTime === null) {\n return;\n }\n\n // Sync timeline to engine\n try {\n engineRef.current.setTime(currentTime);\n } catch (error) {\n console.error('AnnotPdf: Failed to set time:', error);\n if (onError) {\n onError(error);\n }\n }\n }, [currentTime]);\n\n // ==========================================================================\n // SECTION 11: STYLING DEFINITIONS\n // ==========================================================================\n\n /**\n * Default container styles\n * Merged with user-provided styles (user styles override defaults)\n */\n const defaultContainerStyle = {\n position: 'relative',\n display: 'inline-block',\n lineHeight: 0, // Remove extra space below canvas\n ...style // User styles override defaults\n };\n\n /**\n * Default layer container styles\n * Positions layer div absolutely over canvas\n */\n const defaultLayerStyle = {\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: '100%',\n pointerEvents: 'none', // Allow clicks to pass through to canvas\n overflow: 'hidden'\n };\n\n /**\n * Default canvas styles\n * Merged with user-provided canvasStyle\n */\n const defaultCanvasStyle = {\n display: 'block',\n ...canvasStyle // User styles override defaults\n };\n\n // ==========================================================================\n // SECTION 12: JSX RETURN\n // ==========================================================================\n\n return (\n <div className={className} style={defaultContainerStyle}>\n <canvas ref={canvasRef} style={defaultCanvasStyle} />\n <div ref={layerContainerRef} style={defaultLayerStyle} />\n </div>\n );\n}\n\n// ============================================================================\n// SECTION 13: EXPORT\n// ============================================================================\n\nexport default AnnotPdf;\n"],"names":["AnnotPdf","pdfUrl","page","scale","annotations","currentTime","onLoad","onError","onPageChange","className","style","canvasStyle","canvasRef","useRef","layerContainerRef","engineRef","renderQueue","queueOperation","useCallback","operation","error","useEffect","AnnotationRenderer","cancelled","result","defaultContainerStyle","defaultLayerStyle","defaultCanvasStyle","jsxs","jsx"],"mappings":"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"}
|