@deepcitation/deepcitation-js 1.0.8 → 1.1.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 +1 -1
- package/lib/client/DeepCitation.d.ts +2 -2
- package/lib/client/DeepCitation.js +16 -10
- package/lib/client/types.d.ts +12 -4
- package/lib/index.d.ts +2 -2
- package/lib/index.js +1 -1
- package/lib/parsing/parseCitation.d.ts +3 -3
- package/lib/parsing/parseCitation.js +50 -16
- package/lib/react/CitationComponent.d.ts +3 -3
- package/lib/react/CitationComponent.js +37 -19
- package/lib/react/CitationVariants.d.ts +2 -2
- package/lib/react/CitationVariants.js +8 -7
- package/lib/react/primitives.d.ts +3 -3
- package/lib/react/primitives.js +8 -3
- package/lib/react/types.d.ts +3 -3
- package/lib/react/utils.js +4 -2
- package/lib/types/citation.d.ts +4 -6
- package/lib/types/index.d.ts +2 -2
- package/lib/types/index.js +1 -1
- package/lib/types/{foundHighlight.d.ts → verification.d.ts} +5 -5
- package/lib/types/verification.js +23 -0
- package/package.json +1 -1
- package/lib/types/foundHighlight.js +0 -22
package/README.md
CHANGED
|
@@ -154,7 +154,7 @@ export declare class DeepCitation {
|
|
|
154
154
|
* const citations = getAllCitationsFromLlmOutput(llmResponse);
|
|
155
155
|
* const verified = await dc.verifyCitations(fileId, citations);
|
|
156
156
|
*
|
|
157
|
-
* for (const [key, result] of Object.entries(verified.
|
|
157
|
+
* for (const [key, result] of Object.entries(verified.verifications)) {
|
|
158
158
|
* console.log(key, result.searchState?.status);
|
|
159
159
|
* // "found", "partial_text_found", "not_found", etc.
|
|
160
160
|
* }
|
|
@@ -175,7 +175,7 @@ export declare class DeepCitation {
|
|
|
175
175
|
* fileDataParts, // From prepareFiles()
|
|
176
176
|
* });
|
|
177
177
|
*
|
|
178
|
-
* for (const [key, result] of Object.entries(result.
|
|
178
|
+
* for (const [key, result] of Object.entries(result.verifications)) {
|
|
179
179
|
* console.log(key, result.searchState?.status);
|
|
180
180
|
* }
|
|
181
181
|
* ```
|
|
@@ -237,13 +237,19 @@ export class DeepCitation {
|
|
|
237
237
|
return { fileDataParts: [], deepTextPromptPortion: [] };
|
|
238
238
|
}
|
|
239
239
|
// Upload all files in parallel
|
|
240
|
-
const uploadPromises = files.map(({ file, filename, fileId }) => this.uploadFile(file, { filename, fileId }))
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
240
|
+
const uploadPromises = files.map(({ file, filename, fileId }) => this.uploadFile(file, { filename, fileId }).then((result) => ({
|
|
241
|
+
result,
|
|
242
|
+
filename,
|
|
243
|
+
})));
|
|
244
|
+
const uploadResults = await Promise.all(uploadPromises);
|
|
245
|
+
// Extract file data parts with deepTextPromptPortion included (single source of truth)
|
|
246
|
+
const fileDataParts = uploadResults.map(({ result, filename }) => ({
|
|
244
247
|
fileId: result.fileId,
|
|
248
|
+
deepTextPromptPortion: result.deepTextPromptPortion,
|
|
249
|
+
filename: filename || result.metadata?.filename,
|
|
245
250
|
}));
|
|
246
|
-
|
|
251
|
+
// Also return separate array for backwards compatibility (deprecated)
|
|
252
|
+
const deepTextPromptPortion = fileDataParts.map((part) => part.deepTextPromptPortion);
|
|
247
253
|
return { fileDataParts, deepTextPromptPortion };
|
|
248
254
|
}
|
|
249
255
|
/**
|
|
@@ -261,7 +267,7 @@ export class DeepCitation {
|
|
|
261
267
|
* const citations = getAllCitationsFromLlmOutput(llmResponse);
|
|
262
268
|
* const verified = await dc.verifyCitations(fileId, citations);
|
|
263
269
|
*
|
|
264
|
-
* for (const [key, result] of Object.entries(verified.
|
|
270
|
+
* for (const [key, result] of Object.entries(verified.verifications)) {
|
|
265
271
|
* console.log(key, result.searchState?.status);
|
|
266
272
|
* // "found", "partial_text_found", "not_found", etc.
|
|
267
273
|
* }
|
|
@@ -328,7 +334,7 @@ export class DeepCitation {
|
|
|
328
334
|
* fileDataParts, // From prepareFiles()
|
|
329
335
|
* });
|
|
330
336
|
*
|
|
331
|
-
* for (const [key, result] of Object.entries(result.
|
|
337
|
+
* for (const [key, result] of Object.entries(result.verifications)) {
|
|
332
338
|
* console.log(key, result.searchState?.status);
|
|
333
339
|
* }
|
|
334
340
|
* ```
|
|
@@ -340,7 +346,7 @@ export class DeepCitation {
|
|
|
340
346
|
citations = getAllCitationsFromLlmOutput(llmOutput);
|
|
341
347
|
// If no citations found, return empty result
|
|
342
348
|
if (Object.keys(citations).length === 0) {
|
|
343
|
-
return {
|
|
349
|
+
return { verifications: {} };
|
|
344
350
|
}
|
|
345
351
|
// Group citations by fileId
|
|
346
352
|
const citationsByFile = new Map();
|
|
@@ -361,8 +367,8 @@ export class DeepCitation {
|
|
|
361
367
|
const results = await Promise.all(verificationPromises);
|
|
362
368
|
const allHighlights = {};
|
|
363
369
|
for (const result of results) {
|
|
364
|
-
Object.assign(allHighlights, result.
|
|
370
|
+
Object.assign(allHighlights, result.verifications);
|
|
365
371
|
}
|
|
366
|
-
return {
|
|
372
|
+
return { verifications: allHighlights };
|
|
367
373
|
}
|
|
368
374
|
}
|
package/lib/client/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Citation,
|
|
1
|
+
import type { Citation, Verification } from "../types/index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Configuration options for the DeepCitation client
|
|
4
4
|
*/
|
|
@@ -51,7 +51,7 @@ export interface UploadFileOptions {
|
|
|
51
51
|
*/
|
|
52
52
|
export interface VerifyCitationsResponse {
|
|
53
53
|
/** Map of citation keys to their verification results */
|
|
54
|
-
|
|
54
|
+
verifications: Record<string, Verification>;
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
57
|
* Options for citation verification
|
|
@@ -81,14 +81,22 @@ export interface FileInput {
|
|
|
81
81
|
export interface FileDataPart {
|
|
82
82
|
/** The file ID assigned by DeepCitation */
|
|
83
83
|
fileId: string;
|
|
84
|
+
/** The formatted text content for LLM prompts (with page markers and line IDs) */
|
|
85
|
+
deepTextPromptPortion: string;
|
|
86
|
+
/** Optional filename for display purposes */
|
|
87
|
+
filename?: string;
|
|
84
88
|
}
|
|
85
89
|
/**
|
|
86
90
|
* Result from prepareFiles
|
|
87
91
|
*/
|
|
88
92
|
export interface PrepareFilesResult {
|
|
89
|
-
/** Array of file references for verification */
|
|
93
|
+
/** Array of file references for verification (includes deepTextPromptPortion for each file) */
|
|
90
94
|
fileDataParts: FileDataPart[];
|
|
91
|
-
/**
|
|
95
|
+
/**
|
|
96
|
+
* Array of formatted text content for LLM prompts (with page markers and line IDs).
|
|
97
|
+
* @deprecated Use fileDataParts[].deepTextPromptPortion instead for single source of truth.
|
|
98
|
+
* This is kept for backwards compatibility but will be removed in a future version.
|
|
99
|
+
*/
|
|
92
100
|
deepTextPromptPortion: string[];
|
|
93
101
|
}
|
|
94
102
|
/**
|
package/lib/index.d.ts
CHANGED
|
@@ -9,8 +9,8 @@ export { normalizeCitations, getCitationPageNumber, } from "./parsing/normalizeC
|
|
|
9
9
|
export { isGeminiGarbage, cleanRepeatingLastSentence, } from "./parsing/parseWorkAround.js";
|
|
10
10
|
export type { Citation, CitationStatus, VerifyCitationRequest, VerifyCitationResponse, OutputImageFormat, } from "./types/citation.js";
|
|
11
11
|
export { DEFAULT_OUTPUT_IMAGE_FORMAT } from "./types/citation.js";
|
|
12
|
-
export type {
|
|
13
|
-
export {
|
|
12
|
+
export type { Verification } from "./types/verification.js";
|
|
13
|
+
export { NOT_FOUND_VERIFICATION_INDEX, PENDING_VERIFICATION_INDEX, BLANK_VERIFICATION, deterministicIdFromVerification, } from "./types/verification.js";
|
|
14
14
|
export type { SearchState, SearchStatus, SearchMethod, SearchAttempt, } from "./types/search.js";
|
|
15
15
|
export type { ScreenBox, PdfSpaceItem, IVertex } from "./types/boxes.js";
|
|
16
16
|
export { sha1Hash } from "./utils/sha.js";
|
package/lib/index.js
CHANGED
|
@@ -9,7 +9,7 @@ export { parseCitation, getCitationStatus, getAllCitationsFromLlmOutput, groupCi
|
|
|
9
9
|
export { normalizeCitations, getCitationPageNumber, } from "./parsing/normalizeCitation.js";
|
|
10
10
|
export { isGeminiGarbage, cleanRepeatingLastSentence, } from "./parsing/parseWorkAround.js";
|
|
11
11
|
export { DEFAULT_OUTPUT_IMAGE_FORMAT } from "./types/citation.js";
|
|
12
|
-
export {
|
|
12
|
+
export { NOT_FOUND_VERIFICATION_INDEX, PENDING_VERIFICATION_INDEX, BLANK_VERIFICATION, deterministicIdFromVerification, } from "./types/verification.js";
|
|
13
13
|
// Utilities
|
|
14
14
|
export { sha1Hash } from "./utils/sha.js";
|
|
15
15
|
export { generateCitationKey } from "./react/utils.js";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Verification } from "../types/verification.js";
|
|
2
2
|
import { type Citation, type CitationStatus } from "../types/citation.js";
|
|
3
3
|
/**
|
|
4
4
|
* Calculates the verification status of a citation based on the found highlight and search state.
|
|
5
5
|
*
|
|
6
|
-
* @param
|
|
6
|
+
* @param verification - The found highlight location, or null/undefined if not found
|
|
7
7
|
* @returns An object containing boolean flags for verification status
|
|
8
8
|
*/
|
|
9
|
-
export declare function getCitationStatus(
|
|
9
|
+
export declare function getCitationStatus(verification: Verification | null | undefined): CitationStatus;
|
|
10
10
|
export declare const parseCitation: (fragment: string, mdAttachmentId?: string | null, citationCounterRef?: any | null, isVerbose?: boolean) => {
|
|
11
11
|
beforeCite: string;
|
|
12
12
|
afterCite: string;
|
|
@@ -1,14 +1,58 @@
|
|
|
1
|
-
import { sha1Hash } from "../utils/sha.js";
|
|
2
1
|
import { normalizeCitations } from "./normalizeCitation.js";
|
|
3
2
|
import { generateCitationKey } from "../react/utils.js";
|
|
3
|
+
/**
|
|
4
|
+
* Parses a line_ids string that may contain individual numbers, ranges, or both.
|
|
5
|
+
* Examples: "1,2,3", "5-10", "1,5-7,10", "20-20"
|
|
6
|
+
*
|
|
7
|
+
* @param lineIdsString - The raw line_ids string (e.g., "1,5-7,10")
|
|
8
|
+
* @returns Sorted array of unique line IDs, or undefined if empty/invalid
|
|
9
|
+
*/
|
|
10
|
+
function parseLineIds(lineIdsString) {
|
|
11
|
+
if (!lineIdsString)
|
|
12
|
+
return undefined;
|
|
13
|
+
const lineIds = [];
|
|
14
|
+
const parts = lineIdsString.split(",");
|
|
15
|
+
for (const part of parts) {
|
|
16
|
+
const trimmed = part.trim();
|
|
17
|
+
if (!trimmed)
|
|
18
|
+
continue;
|
|
19
|
+
// Check if this part is a range (e.g., "5-10")
|
|
20
|
+
if (trimmed.includes("-")) {
|
|
21
|
+
const [startStr, endStr] = trimmed.split("-");
|
|
22
|
+
const start = parseInt(startStr, 10);
|
|
23
|
+
const end = parseInt(endStr, 10);
|
|
24
|
+
if (!isNaN(start) && !isNaN(end) && start <= end) {
|
|
25
|
+
// Expand the range
|
|
26
|
+
for (let i = start; i <= end; i++) {
|
|
27
|
+
lineIds.push(i);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else if (!isNaN(start)) {
|
|
31
|
+
// If only start is valid, just use it
|
|
32
|
+
lineIds.push(start);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// Single number
|
|
37
|
+
const num = parseInt(trimmed, 10);
|
|
38
|
+
if (!isNaN(num)) {
|
|
39
|
+
lineIds.push(num);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (lineIds.length === 0)
|
|
44
|
+
return undefined;
|
|
45
|
+
// Sort and deduplicate
|
|
46
|
+
return [...new Set(lineIds)].sort((a, b) => a - b);
|
|
47
|
+
}
|
|
4
48
|
/**
|
|
5
49
|
* Calculates the verification status of a citation based on the found highlight and search state.
|
|
6
50
|
*
|
|
7
|
-
* @param
|
|
51
|
+
* @param verification - The found highlight location, or null/undefined if not found
|
|
8
52
|
* @returns An object containing boolean flags for verification status
|
|
9
53
|
*/
|
|
10
|
-
export function getCitationStatus(
|
|
11
|
-
const searchState =
|
|
54
|
+
export function getCitationStatus(verification) {
|
|
55
|
+
const searchState = verification?.searchState;
|
|
12
56
|
const isMiss = searchState?.status === "not_found";
|
|
13
57
|
const isFullMatchWithMissedValue = searchState?.status === "found_phrase_missed_value";
|
|
14
58
|
const isFoundValueMissedFullMatch = searchState?.status === "found_value_only";
|
|
@@ -55,7 +99,6 @@ export const parseCitation = (fragment, mdAttachmentId, citationCounterRef, isVe
|
|
|
55
99
|
const citationRegex = /<cite\s+file(?:_id|Id)='(\w{0,25})'\s+start_page[\_a-zA-Z]*='page[\_a-zA-Z]*(\d+)_index_(\d+)'\s+full_phrase='((?:[^'\\]|\\.)*)'\s+key_span='((?:[^'\\]|\\.)*)'\s+line(?:_ids|Ids)='([^']+)'(?:\s+(value|reasoning)='((?:[^'\\]|\\.)*)')?\s*\/>/g;
|
|
56
100
|
const citationMatches = [...middleCite.matchAll(citationRegex)];
|
|
57
101
|
const match = citationMatches?.[0];
|
|
58
|
-
const rawCitationMd = match?.[0];
|
|
59
102
|
const pageNumber = match?.[2] ? parseInt(match?.[2]) : undefined;
|
|
60
103
|
let fileId = match?.[1];
|
|
61
104
|
let attachmentId = fileId?.length === 20 ? fileId : mdAttachmentId || match?.[1];
|
|
@@ -75,15 +118,9 @@ export const parseCitation = (fragment, mdAttachmentId, citationCounterRef, isVe
|
|
|
75
118
|
}
|
|
76
119
|
let lineIds;
|
|
77
120
|
try {
|
|
78
|
-
// match[
|
|
121
|
+
// match[6] is line_ids
|
|
79
122
|
const lineIdsString = match?.[6]?.replace(/[A-Za-z_[\](){}:]/g, "");
|
|
80
|
-
lineIds = lineIdsString
|
|
81
|
-
? lineIdsString
|
|
82
|
-
.split(",")
|
|
83
|
-
.map((id) => (isNaN(parseInt(id)) ? undefined : parseInt(id)))
|
|
84
|
-
.filter((id) => id !== undefined)
|
|
85
|
-
.sort((a, b) => a - b)
|
|
86
|
-
: undefined;
|
|
123
|
+
lineIds = lineIdsString ? parseLineIds(lineIdsString) : undefined;
|
|
87
124
|
}
|
|
88
125
|
catch (e) {
|
|
89
126
|
if (isVerbose)
|
|
@@ -116,16 +153,13 @@ export const parseCitation = (fragment, mdAttachmentId, citationCounterRef, isVe
|
|
|
116
153
|
}
|
|
117
154
|
timestamps = { startTime, endTime };
|
|
118
155
|
}
|
|
119
|
-
const fragmentContext = sha1Hash(fragment).toString().slice(0, 8);
|
|
120
156
|
const citation = {
|
|
121
|
-
fragmentContext,
|
|
122
157
|
fileId: attachmentId,
|
|
123
158
|
pageNumber,
|
|
124
159
|
fullPhrase,
|
|
125
160
|
keySpan,
|
|
126
161
|
citationNumber,
|
|
127
162
|
lineIds,
|
|
128
|
-
rawCitationMd,
|
|
129
163
|
beforeCite,
|
|
130
164
|
value,
|
|
131
165
|
timestamps,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { type ReactNode } from "react";
|
|
2
2
|
import { type CitationStatus } from "../types/citation.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { Verification } from "../types/verification.js";
|
|
4
4
|
import type { BaseCitationProps, CitationEventHandlers, CitationRenderProps, CitationVariant } from "./types.js";
|
|
5
5
|
import "./styles.css";
|
|
6
6
|
export type { CitationVariant } from "./types.js";
|
|
@@ -70,7 +70,7 @@ export interface CitationComponentProps extends BaseCitationProps {
|
|
|
70
70
|
* Verification result from the DeepCitation API.
|
|
71
71
|
* Contains match snippet, page number, and verification image.
|
|
72
72
|
*/
|
|
73
|
-
foundCitation?:
|
|
73
|
+
foundCitation?: Verification | null;
|
|
74
74
|
/**
|
|
75
75
|
* Display variant for the citation.
|
|
76
76
|
* - `brackets`: Shows value/number in brackets, blue text styling (default)
|
|
@@ -110,7 +110,7 @@ export interface CitationComponentProps extends BaseCitationProps {
|
|
|
110
110
|
*/
|
|
111
111
|
renderPopoverContent?: (props: {
|
|
112
112
|
citation: BaseCitationProps["citation"];
|
|
113
|
-
foundCitation:
|
|
113
|
+
foundCitation: Verification | null;
|
|
114
114
|
status: CitationStatus;
|
|
115
115
|
}) => ReactNode;
|
|
116
116
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef, memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { forwardRef, memo, useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
4
|
import { CheckIcon, WarningIcon } from "./icons.js";
|
|
5
|
-
import { classNames, generateCitationInstanceId, generateCitationKey, getCitationDisplayText } from "./utils.js";
|
|
5
|
+
import { classNames, generateCitationInstanceId, generateCitationKey, getCitationDisplayText, } from "./utils.js";
|
|
6
6
|
import { getCitationStatus } from "../parsing/parseCitation.js";
|
|
7
7
|
import "./styles.css";
|
|
8
8
|
const TWO_DOTS_THINKING_CONTENT = "..";
|
|
@@ -80,7 +80,7 @@ const StatusTooltipContent = ({ citation, status, foundCitation, isExpanded, onT
|
|
|
80
80
|
return null;
|
|
81
81
|
// Get search attempts from foundCitation
|
|
82
82
|
const searchAttempts = foundCitation?.searchState?.searchAttempts;
|
|
83
|
-
const failedAttempts = searchAttempts?.filter(a => !a.success) || [];
|
|
83
|
+
const failedAttempts = searchAttempts?.filter((a) => !a.success) || [];
|
|
84
84
|
// Collect all unique phrases tried
|
|
85
85
|
const allPhrases = [];
|
|
86
86
|
const seenPhrases = new Set();
|
|
@@ -106,7 +106,9 @@ const StatusTooltipContent = ({ citation, status, foundCitation, isExpanded, onT
|
|
|
106
106
|
if (isPartialMatch) {
|
|
107
107
|
const expectedText = citation.fullPhrase || citation.value || "";
|
|
108
108
|
const actualText = foundCitation?.matchSnippet || "";
|
|
109
|
-
const truncatedExpected = expectedText.length > 100
|
|
109
|
+
const truncatedExpected = expectedText.length > 100
|
|
110
|
+
? expectedText.slice(0, 100) + "…"
|
|
111
|
+
: expectedText;
|
|
110
112
|
const truncatedActual = actualText.length > 100 ? actualText.slice(0, 100) + "…" : actualText;
|
|
111
113
|
return (_jsxs("span", { className: "dc-status-tooltip", role: "tooltip", children: [_jsxs("span", { className: "dc-status-header dc-status-header--partial", children: [_jsx(WarningIcon, {}), _jsx("span", { children: "Partial match" })] }), _jsx("span", { className: "dc-status-description", children: "Text differs from citation." }), truncatedExpected && (_jsxs("span", { className: "dc-status-searched", children: [_jsx("span", { className: "dc-status-label", children: "Expected" }), _jsx("span", { className: "dc-status-text", children: truncatedExpected })] })), truncatedActual && (_jsxs("span", { className: "dc-status-searched", children: [_jsx("span", { className: "dc-status-label", children: "Found" }), _jsx("span", { className: "dc-status-text", children: truncatedActual })] }))] }));
|
|
112
114
|
}
|
|
@@ -116,7 +118,7 @@ const StatusTooltipContent = ({ citation, status, foundCitation, isExpanded, onT
|
|
|
116
118
|
* Full-size image overlay component.
|
|
117
119
|
* Uses portal to render at document body level.
|
|
118
120
|
*/
|
|
119
|
-
const ImageOverlay = ({ src, alt, onClose }) => {
|
|
121
|
+
const ImageOverlay = ({ src, alt, onClose, }) => {
|
|
120
122
|
const handleBackdropClick = useCallback((e) => {
|
|
121
123
|
if (e.target === e.currentTarget) {
|
|
122
124
|
onClose();
|
|
@@ -159,7 +161,7 @@ const DefaultPopoverContent = ({ foundCitation, status, onImageClick, }) => {
|
|
|
159
161
|
if (!hasSnippet && !statusLabel) {
|
|
160
162
|
return null;
|
|
161
163
|
}
|
|
162
|
-
return (_jsxs(_Fragment, { children: [statusLabel && _jsx("span", { className: classNames("dc-popover-status", statusClass), children: statusLabel }), hasSnippet && _jsxs("span", { className: "dc-popover-snippet", children: ["\"", foundCitation.matchSnippet, "\""] }), pageNumber && pageNumber > 0 && _jsxs("span", { className: "dc-popover-page", children: ["Page ", pageNumber] })] }));
|
|
164
|
+
return (_jsxs(_Fragment, { children: [statusLabel && (_jsx("span", { className: classNames("dc-popover-status", statusClass), children: statusLabel })), hasSnippet && (_jsxs("span", { className: "dc-popover-snippet", children: ["\"", foundCitation.matchSnippet, "\""] })), pageNumber && pageNumber > 0 && (_jsxs("span", { className: "dc-popover-page", children: ["Page ", pageNumber] }))] }));
|
|
163
165
|
};
|
|
164
166
|
// =============================================================================
|
|
165
167
|
// MAIN COMPONENT
|
|
@@ -195,14 +197,15 @@ export const CitationComponent = forwardRef(({ citation, children, className, di
|
|
|
195
197
|
const handleTogglePhrases = useCallback((e) => {
|
|
196
198
|
e?.preventDefault();
|
|
197
199
|
e?.stopPropagation();
|
|
198
|
-
setIsPhrasesExpanded(prev => !prev);
|
|
200
|
+
setIsPhrasesExpanded((prev) => !prev);
|
|
199
201
|
}, []);
|
|
200
202
|
// Handle click outside to close expanded tooltip
|
|
201
203
|
useEffect(() => {
|
|
202
204
|
if (!isTooltipExpanded)
|
|
203
205
|
return;
|
|
204
206
|
const handleClickOutside = (event) => {
|
|
205
|
-
if (wrapperRef.current &&
|
|
207
|
+
if (wrapperRef.current &&
|
|
208
|
+
!wrapperRef.current.contains(event.target)) {
|
|
206
209
|
setIsTooltipExpanded(false);
|
|
207
210
|
}
|
|
208
211
|
};
|
|
@@ -249,8 +252,8 @@ export const CitationComponent = forwardRef(({ citation, children, className, di
|
|
|
249
252
|
}
|
|
250
253
|
else {
|
|
251
254
|
// No image - toggle phrases expansion for miss/partial tooltips
|
|
252
|
-
setIsTooltipExpanded(prev => !prev);
|
|
253
|
-
setIsPhrasesExpanded(prev => !prev);
|
|
255
|
+
setIsTooltipExpanded((prev) => !prev);
|
|
256
|
+
setIsPhrasesExpanded((prev) => !prev);
|
|
254
257
|
}
|
|
255
258
|
eventHandlers?.onClick?.(citation, citationKey, e);
|
|
256
259
|
}, [
|
|
@@ -271,7 +274,10 @@ export const CitationComponent = forwardRef(({ citation, children, className, di
|
|
|
271
274
|
}
|
|
272
275
|
// For text/minimal/brackets, show the value or fullPhrase
|
|
273
276
|
return getCitationDisplayText(citation, {
|
|
274
|
-
displayCitationValue: variant === "text" ||
|
|
277
|
+
displayCitationValue: variant === "text" ||
|
|
278
|
+
variant === "minimal" ||
|
|
279
|
+
variant === "brackets" ||
|
|
280
|
+
displayCitationValue,
|
|
275
281
|
fallbackDisplay,
|
|
276
282
|
});
|
|
277
283
|
}, [citation, variant, displayCitationValue, fallbackDisplay]);
|
|
@@ -292,8 +298,11 @@ export const CitationComponent = forwardRef(({ citation, children, className, di
|
|
|
292
298
|
}
|
|
293
299
|
}, [eventHandlers, citation, citationKey, isMobile]);
|
|
294
300
|
// Early return for miss with fallback display
|
|
295
|
-
if (fallbackDisplay !== null &&
|
|
296
|
-
|
|
301
|
+
if (fallbackDisplay !== null &&
|
|
302
|
+
fallbackDisplay !== undefined &&
|
|
303
|
+
displayCitationValue &&
|
|
304
|
+
isMiss) {
|
|
305
|
+
return (_jsx("span", { className: classNames("dc-citation-fallback", className), children: fallbackDisplay }));
|
|
297
306
|
}
|
|
298
307
|
// Render the appropriate indicator based on match quality
|
|
299
308
|
const renderStatusIndicator = () => {
|
|
@@ -323,12 +332,14 @@ export const CitationComponent = forwardRef(({ citation, children, className, di
|
|
|
323
332
|
status,
|
|
324
333
|
citationKey,
|
|
325
334
|
displayText,
|
|
326
|
-
isMergedDisplay: variant === "text" ||
|
|
335
|
+
isMergedDisplay: variant === "text" ||
|
|
336
|
+
variant === "brackets" ||
|
|
337
|
+
displayCitationValue,
|
|
327
338
|
});
|
|
328
339
|
}
|
|
329
340
|
// Indicator-only variant - just the checkmark/warning
|
|
330
341
|
if (variant === "indicator") {
|
|
331
|
-
return _jsx("span", { className: "dc-citation-text", children: renderStatusIndicator() });
|
|
342
|
+
return (_jsx("span", { className: "dc-citation-text", children: renderStatusIndicator() }));
|
|
332
343
|
}
|
|
333
344
|
// Text variant - no special styling, shows value with indicator
|
|
334
345
|
if (variant === "text") {
|
|
@@ -347,16 +358,23 @@ export const CitationComponent = forwardRef(({ citation, children, className, di
|
|
|
347
358
|
};
|
|
348
359
|
// Determine if popover should be shown
|
|
349
360
|
const isPopoverHidden = popoverPosition === "hidden";
|
|
350
|
-
const shouldShowPopover = !isPopoverHidden &&
|
|
361
|
+
const shouldShowPopover = !isPopoverHidden &&
|
|
362
|
+
foundCitation &&
|
|
363
|
+
(foundCitation.verificationImageBase64 || foundCitation.matchSnippet);
|
|
351
364
|
// Determine if status tooltip should be shown (miss/partial without full verification)
|
|
352
365
|
const shouldShowStatusTooltip = !isPopoverHidden && (isMiss || isPartialMatch) && !shouldShowPopover;
|
|
353
366
|
// Popover content - determine position class (only "top" or "bottom" add classes)
|
|
354
367
|
const popoverPositionClass = popoverPosition === "bottom" ? "dc-popover--bottom" : "";
|
|
355
|
-
const popoverContent = shouldShowPopover ? (_jsx("span", { className: classNames("dc-popover", popoverPositionClass), children: renderPopoverContent ? (renderPopoverContent({
|
|
368
|
+
const popoverContent = shouldShowPopover ? (_jsx("span", { className: classNames("dc-popover", popoverPositionClass), children: renderPopoverContent ? (renderPopoverContent({
|
|
369
|
+
citation,
|
|
370
|
+
foundCitation: foundCitation ?? null,
|
|
371
|
+
status,
|
|
372
|
+
})) : (_jsx(DefaultPopoverContent, { citation: citation, foundCitation: foundCitation ?? null, status: status, onImageClick: handleImageClick })) })) : null;
|
|
356
373
|
// Status tooltip for miss/partial explanations
|
|
357
374
|
const statusTooltipContent = shouldShowStatusTooltip ? (_jsx(StatusTooltipContent, { citation: citation, status: status, foundCitation: foundCitation ?? null, isExpanded: isPhrasesExpanded, onToggleExpand: handleTogglePhrases })) : null;
|
|
358
|
-
const citationTrigger = (_jsx("span", { ref: node => {
|
|
359
|
-
containerRef.current =
|
|
375
|
+
const citationTrigger = (_jsx("span", { ref: (node) => {
|
|
376
|
+
containerRef.current =
|
|
377
|
+
node;
|
|
360
378
|
if (typeof ref === "function") {
|
|
361
379
|
ref(node);
|
|
362
380
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { type ReactNode } from "react";
|
|
2
2
|
import type { CitationStatus } from "../types/citation.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { Verification } from "../types/verification.js";
|
|
4
4
|
import type { SearchState } from "../types/search.js";
|
|
5
5
|
import type { BaseCitationProps, CitationVariant as CitationVariantType, CitationEventHandlers } from "./types.js";
|
|
6
6
|
/**
|
|
@@ -8,7 +8,7 @@ import type { BaseCitationProps, CitationVariant as CitationVariantType, Citatio
|
|
|
8
8
|
*/
|
|
9
9
|
export interface CitationVariantProps extends BaseCitationProps {
|
|
10
10
|
/** Found citation highlight location data */
|
|
11
|
-
foundCitation?:
|
|
11
|
+
foundCitation?: Verification | null;
|
|
12
12
|
/** Current search state for the citation */
|
|
13
13
|
searchState?: SearchState | null;
|
|
14
14
|
/** Event handlers */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { memo, useMemo, useCallback, forwardRef } from "react";
|
|
2
|
+
import { memo, useMemo, useCallback, forwardRef, } from "react";
|
|
3
3
|
import { getCitationStatus } from "../parsing/parseCitation.js";
|
|
4
4
|
import { generateCitationKey, generateCitationInstanceId, getCitationDisplayText, getCitationValueText, classNames, } from "./utils.js";
|
|
5
5
|
const TWO_DOTS_THINKING_CONTENT = "..";
|
|
@@ -67,7 +67,8 @@ export const ChipCitation = forwardRef(({ citation, children, className, display
|
|
|
67
67
|
: isPending
|
|
68
68
|
? "citation-chip--pending"
|
|
69
69
|
: "";
|
|
70
|
-
return (_jsxs(_Fragment, { children: [children, _jsxs("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "chip", className: classNames("citation-chip", sizeClasses[size], statusClass, className), onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: e => e.stopPropagation(), "aria-label": displayText ? `Citation: ${displayText}` : undefined, children: [showIcon &&
|
|
70
|
+
return (_jsxs(_Fragment, { children: [children, _jsxs("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "chip", className: classNames("citation-chip", sizeClasses[size], statusClass, className), onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: (e) => e.stopPropagation(), "aria-label": displayText ? `Citation: ${displayText}` : undefined, children: [showIcon &&
|
|
71
|
+
(icon || _jsx("span", { className: "citation-chip__icon", children: "\uD83D\uDCC4" })), valueText && !displayCitationValue && (_jsx("span", { className: "citation-chip__value", children: valueText })), _jsx("span", { className: "citation-chip__text", children: displayText }), isPartialMatch && renderPartialIndicator(status), isVerified && !isPartialMatch && renderVerifiedIndicator(status), isPending && (_jsx("span", { className: "citation-chip__pending", children: pendingContent }))] })] }));
|
|
71
72
|
});
|
|
72
73
|
ChipCitation.displayName = "ChipCitation";
|
|
73
74
|
/**
|
|
@@ -108,7 +109,7 @@ export const SuperscriptCitation = forwardRef(({ citation, children, className,
|
|
|
108
109
|
: isPending
|
|
109
110
|
? "citation-superscript--pending"
|
|
110
111
|
: "";
|
|
111
|
-
return (_jsxs(_Fragment, { children: [children, _jsxs("sup", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "superscript", className: classNames("citation-superscript", statusClass, className), onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: e => e.stopPropagation(), "aria-label": `Citation ${displayText}`, children: [showBrackets && "[", displayText, isPartialMatch && renderPartialIndicator(status), isVerified && !isPartialMatch && renderVerifiedIndicator(status), isPending && pendingContent, showBrackets && "]"] })] }));
|
|
112
|
+
return (_jsxs(_Fragment, { children: [children, _jsxs("sup", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "superscript", className: classNames("citation-superscript", statusClass, className), onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: (e) => e.stopPropagation(), "aria-label": `Citation ${displayText}`, children: [showBrackets && "[", displayText, isPartialMatch && renderPartialIndicator(status), isVerified && !isPartialMatch && renderVerifiedIndicator(status), isPending && pendingContent, showBrackets && "]"] })] }));
|
|
112
113
|
});
|
|
113
114
|
SuperscriptCitation.displayName = "SuperscriptCitation";
|
|
114
115
|
const FOOTNOTE_SYMBOLS = ["*", "†", "‡", "§", "‖", "¶"];
|
|
@@ -159,7 +160,7 @@ export const FootnoteCitation = forwardRef(({ citation, children, className, fal
|
|
|
159
160
|
: isPending
|
|
160
161
|
? "citation-footnote--pending"
|
|
161
162
|
: "";
|
|
162
|
-
return (_jsxs(_Fragment, { children: [children, _jsxs("sup", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "footnote", className: classNames("citation-footnote", statusClass, className), onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: e => e.stopPropagation(), "aria-label": `Footnote ${displaySymbol}`, children: [displaySymbol, isPartialMatch && renderPartialIndicator(status), isVerified && !isPartialMatch && renderVerifiedIndicator(status), isPending && pendingContent] })] }));
|
|
163
|
+
return (_jsxs(_Fragment, { children: [children, _jsxs("sup", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "footnote", className: classNames("citation-footnote", statusClass, className), onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: (e) => e.stopPropagation(), "aria-label": `Footnote ${displaySymbol}`, children: [displaySymbol, isPartialMatch && renderPartialIndicator(status), isVerified && !isPartialMatch && renderVerifiedIndicator(status), isPending && pendingContent] })] }));
|
|
163
164
|
});
|
|
164
165
|
FootnoteCitation.displayName = "FootnoteCitation";
|
|
165
166
|
/**
|
|
@@ -202,7 +203,7 @@ fallbackDisplay, foundCitation, eventHandlers, preventTooltips = false, pendingC
|
|
|
202
203
|
? "citation-inline--pending"
|
|
203
204
|
: "";
|
|
204
205
|
const underlineClass = `citation-inline--underline-${underlineStyle}`;
|
|
205
|
-
return (_jsxs(_Fragment, { children: [children, _jsxs("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "inline", className: classNames("citation-inline", underlineClass, statusClass, className), onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: e => e.stopPropagation(), "aria-label": `Citation: ${displayText}`, children: [displayText, isPartialMatch && renderPartialIndicator(status), isVerified && !isPartialMatch && renderVerifiedIndicator(status), isPending && _jsx("span", { className: "citation-inline__pending", children: pendingContent })] })] }));
|
|
206
|
+
return (_jsxs(_Fragment, { children: [children, _jsxs("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "inline", className: classNames("citation-inline", underlineClass, statusClass, className), onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: (e) => e.stopPropagation(), "aria-label": `Citation: ${displayText}`, children: [displayText, isPartialMatch && renderPartialIndicator(status), isVerified && !isPartialMatch && renderVerifiedIndicator(status), isPending && (_jsx("span", { className: "citation-inline__pending", children: pendingContent }))] })] }));
|
|
206
207
|
});
|
|
207
208
|
InlineCitation.displayName = "InlineCitation";
|
|
208
209
|
/**
|
|
@@ -243,7 +244,7 @@ export const MinimalCitation = forwardRef(({ citation, children, className, disp
|
|
|
243
244
|
: isPending
|
|
244
245
|
? "citation-minimal--pending"
|
|
245
246
|
: "";
|
|
246
|
-
return (_jsxs(_Fragment, { children: [children, _jsxs("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "minimal", className: classNames("citation-minimal", statusClass, className), onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: e => e.stopPropagation(), "aria-label": `Citation ${displayText}`, children: [displayText, showStatusIndicator && (_jsxs(_Fragment, { children: [isPartialMatch && renderPartialIndicator(status), isVerified && !isPartialMatch && renderVerifiedIndicator(status), isPending && pendingContent] }))] })] }));
|
|
247
|
+
return (_jsxs(_Fragment, { children: [children, _jsxs("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "minimal", className: classNames("citation-minimal", statusClass, className), onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: (e) => e.stopPropagation(), "aria-label": `Citation ${displayText}`, children: [displayText, showStatusIndicator && (_jsxs(_Fragment, { children: [isPartialMatch && renderPartialIndicator(status), isVerified && !isPartialMatch && renderVerifiedIndicator(status), isPending && pendingContent] }))] })] }));
|
|
247
248
|
});
|
|
248
249
|
MinimalCitation.displayName = "MinimalCitation";
|
|
249
250
|
/**
|
|
@@ -259,7 +260,7 @@ export const CitationVariantFactory = forwardRef(({ variant = "bracket", chipPro
|
|
|
259
260
|
case "chip":
|
|
260
261
|
return _jsx(ChipCitation, { ref: ref, ...props, ...chipProps });
|
|
261
262
|
case "superscript":
|
|
262
|
-
return _jsx(SuperscriptCitation, { ref: ref, ...props, ...superscriptProps });
|
|
263
|
+
return (_jsx(SuperscriptCitation, { ref: ref, ...props, ...superscriptProps }));
|
|
263
264
|
case "footnote":
|
|
264
265
|
return _jsx(FootnoteCitation, { ref: ref, ...props, ...footnoteProps });
|
|
265
266
|
case "inline":
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import React, { type ReactNode, type HTMLAttributes, type MouseEvent, type TouchEvent } from "react";
|
|
6
6
|
import type { Citation as CitationType, CitationStatus } from "../types/citation.js";
|
|
7
|
-
import type {
|
|
7
|
+
import type { Verification } from "../types/verification.js";
|
|
8
8
|
import type { SearchState } from "../types/search.js";
|
|
9
9
|
interface CitationContextValue {
|
|
10
10
|
citation: CitationType;
|
|
11
11
|
citationKey: string;
|
|
12
12
|
citationInstanceId: string;
|
|
13
13
|
status: CitationStatus;
|
|
14
|
-
foundCitation:
|
|
14
|
+
foundCitation: Verification | null;
|
|
15
15
|
searchState: SearchState | null;
|
|
16
16
|
config: {
|
|
17
17
|
displayCitationValue: boolean;
|
|
@@ -25,7 +25,7 @@ export declare function useCitationContext(): CitationContextValue;
|
|
|
25
25
|
export declare function useCitationContextSafe(): CitationContextValue | null;
|
|
26
26
|
export interface CitationRootProps {
|
|
27
27
|
citation: CitationType;
|
|
28
|
-
foundCitation?:
|
|
28
|
+
foundCitation?: Verification | null;
|
|
29
29
|
searchState?: SearchState | null;
|
|
30
30
|
children: ReactNode;
|
|
31
31
|
displayCitationValue?: boolean;
|
package/lib/react/primitives.js
CHANGED
|
@@ -5,7 +5,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
5
5
|
*/
|
|
6
6
|
import { createContext, useContext, useMemo, useCallback, forwardRef, } from "react";
|
|
7
7
|
import { getCitationStatus } from "../parsing/parseCitation.js";
|
|
8
|
-
import { generateCitationKey, generateCitationInstanceId, classNames } from "./utils.js";
|
|
8
|
+
import { generateCitationKey, generateCitationInstanceId, classNames, } from "./utils.js";
|
|
9
9
|
const CitationContext = createContext(null);
|
|
10
10
|
/** Access citation context. Must be used within Citation.Root. */
|
|
11
11
|
export function useCitationContext() {
|
|
@@ -83,7 +83,9 @@ export const CitationTrigger = forwardRef(({ children, className, onCitationClic
|
|
|
83
83
|
onCitationTouchEnd?.(citation, citationKey, e);
|
|
84
84
|
}
|
|
85
85
|
}, [onTouchEnd, isMobile, onCitationTouchEnd, citation, citationKey]);
|
|
86
|
-
const statusClasses = classNames(status.isVerified &&
|
|
86
|
+
const statusClasses = classNames(status.isVerified &&
|
|
87
|
+
!status.isPartialMatch &&
|
|
88
|
+
"citation-trigger--verified", status.isPartialMatch && "citation-trigger--partial", status.isMiss && "citation-trigger--miss", status.isPending && "citation-trigger--pending");
|
|
87
89
|
return (_jsx("span", { ref: ref, role: "button", tabIndex: 0, className: classNames("citation-trigger", statusClasses, className), onClick: handleClick, onMouseDown: handleMouseDown, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onTouchEndCapture: isMobile ? handleTouchEnd : undefined, ...props, children: children }));
|
|
88
90
|
});
|
|
89
91
|
CitationTrigger.displayName = "Citation.Trigger";
|
|
@@ -99,7 +101,10 @@ export const CitationNumber = forwardRef(({ className, number, ...props }, ref)
|
|
|
99
101
|
if (number !== undefined)
|
|
100
102
|
return String(number);
|
|
101
103
|
if (config.displayCitationValue) {
|
|
102
|
-
return citation.value ||
|
|
104
|
+
return (citation.value ||
|
|
105
|
+
citation.citationNumber?.toString() ||
|
|
106
|
+
config.fallbackDisplay ||
|
|
107
|
+
"");
|
|
103
108
|
}
|
|
104
109
|
return citation.citationNumber?.toString() || "";
|
|
105
110
|
}, [number, citation, config]);
|
package/lib/react/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Citation, CitationStatus } from "../types/citation.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Verification } from "../types/verification.js";
|
|
3
3
|
import type { SearchState } from "../types/search.js";
|
|
4
4
|
/**
|
|
5
5
|
* Available citation display variants.
|
|
@@ -130,7 +130,7 @@ export interface CitationContentProps extends BaseCitationProps {
|
|
|
130
130
|
/** Unique instance ID for this citation render */
|
|
131
131
|
citationInstanceId: string;
|
|
132
132
|
/** Found citation highlight data */
|
|
133
|
-
foundCitation:
|
|
133
|
+
foundCitation: Verification | null | undefined;
|
|
134
134
|
/** Current search state */
|
|
135
135
|
searchState: SearchState | undefined | null;
|
|
136
136
|
/** Actual page number where citation was found */
|
|
@@ -186,7 +186,7 @@ export interface CitationEventHandlers {
|
|
|
186
186
|
export interface CitationTooltipProps {
|
|
187
187
|
children: React.ReactNode;
|
|
188
188
|
citation: Citation;
|
|
189
|
-
|
|
189
|
+
verification?: Verification | null;
|
|
190
190
|
searchState?: SearchState | null;
|
|
191
191
|
shouldShowTooltip: boolean;
|
|
192
192
|
}
|
package/lib/react/utils.js
CHANGED
|
@@ -13,7 +13,6 @@ export function generateCitationKey(citation) {
|
|
|
13
13
|
citation.lineIds?.join(",") || "",
|
|
14
14
|
citation.timestamps?.startTime || "",
|
|
15
15
|
citation.timestamps?.endTime || "",
|
|
16
|
-
citation.fragmentContext || "",
|
|
17
16
|
];
|
|
18
17
|
return sha1Hash(keyParts.join("|")).slice(0, 16);
|
|
19
18
|
}
|
|
@@ -31,7 +30,10 @@ export function generateCitationInstanceId(citationKey) {
|
|
|
31
30
|
export function getCitationDisplayText(citation, options = {}) {
|
|
32
31
|
const { displayCitationValue = false, fallbackDisplay } = options;
|
|
33
32
|
if (displayCitationValue) {
|
|
34
|
-
return citation.value ||
|
|
33
|
+
return (citation.value ||
|
|
34
|
+
citation.citationNumber?.toString() ||
|
|
35
|
+
fallbackDisplay ||
|
|
36
|
+
"");
|
|
35
37
|
}
|
|
36
38
|
return citation.citationNumber?.toString() || "";
|
|
37
39
|
}
|
package/lib/types/citation.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { type ScreenBox } from "./boxes.js";
|
|
2
|
-
import { type
|
|
2
|
+
import { type Verification } from "./verification.js";
|
|
3
3
|
export type OutputImageFormat = "jpeg" | "png" | "avif" | undefined | null;
|
|
4
4
|
export declare const DEFAULT_OUTPUT_IMAGE_FORMAT: "avif";
|
|
5
5
|
export interface VerifyCitationResponse {
|
|
6
|
-
|
|
7
|
-
[key: string]:
|
|
6
|
+
verifications: {
|
|
7
|
+
[key: string]: Verification;
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
10
|
export interface VerifyCitationRequest {
|
|
@@ -21,17 +21,15 @@ export interface Citation {
|
|
|
21
21
|
keySpan?: string | null;
|
|
22
22
|
value?: string | null;
|
|
23
23
|
startPageKey?: string | null;
|
|
24
|
-
pageNumber?: number | null;
|
|
25
24
|
lineIds?: number[] | null;
|
|
26
25
|
reasoning?: string | null;
|
|
27
26
|
selection?: ScreenBox | null;
|
|
28
27
|
citationNumber?: number;
|
|
28
|
+
pageNumber?: number | null;
|
|
29
29
|
timestamps?: {
|
|
30
30
|
endTime?: string;
|
|
31
31
|
startTime?: string;
|
|
32
32
|
};
|
|
33
|
-
fragmentContext?: string | null;
|
|
34
|
-
rawCitationMd?: string;
|
|
35
33
|
beforeCite?: string;
|
|
36
34
|
}
|
|
37
35
|
export interface CitationStatus {
|
package/lib/types/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export type { Citation, CitationStatus, VerifyCitationRequest, VerifyCitationResponse, OutputImageFormat, } from "./citation.js";
|
|
7
7
|
export { DEFAULT_OUTPUT_IMAGE_FORMAT } from "./citation.js";
|
|
8
|
-
export type {
|
|
9
|
-
export {
|
|
8
|
+
export type { Verification } from "./verification.js";
|
|
9
|
+
export { NOT_FOUND_VERIFICATION_INDEX, PENDING_VERIFICATION_INDEX, BLANK_VERIFICATION, deterministicIdFromVerification, } from "./verification.js";
|
|
10
10
|
export type { SearchState, SearchStatus } from "./search.js";
|
|
11
11
|
export type { ScreenBox, PdfSpaceItem, IVertex } from "./boxes.js";
|
package/lib/types/index.js
CHANGED
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* @packageDocumentation
|
|
5
5
|
*/
|
|
6
6
|
export { DEFAULT_OUTPUT_IMAGE_FORMAT } from "./citation.js";
|
|
7
|
-
export {
|
|
7
|
+
export { NOT_FOUND_VERIFICATION_INDEX, PENDING_VERIFICATION_INDEX, BLANK_VERIFICATION, deterministicIdFromVerification, } from "./verification.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { type Citation } from "./citation.js";
|
|
2
2
|
import { type SearchState } from "./search.js";
|
|
3
3
|
import { type PdfSpaceItem } from "./boxes.js";
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
6
|
-
export declare const
|
|
7
|
-
export declare function
|
|
8
|
-
export interface
|
|
4
|
+
export declare const NOT_FOUND_VERIFICATION_INDEX = -1;
|
|
5
|
+
export declare const PENDING_VERIFICATION_INDEX = -2;
|
|
6
|
+
export declare const BLANK_VERIFICATION: Verification;
|
|
7
|
+
export declare function deterministicIdFromVerification(verification: Verification): string;
|
|
8
|
+
export interface Verification {
|
|
9
9
|
regex?: RegExp | null;
|
|
10
10
|
lowerCaseSearchTerm: string | null;
|
|
11
11
|
label?: string | null;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { sha1Hash } from "../utils/sha.js";
|
|
2
|
+
export const NOT_FOUND_VERIFICATION_INDEX = -1;
|
|
3
|
+
export const PENDING_VERIFICATION_INDEX = -2;
|
|
4
|
+
export const BLANK_VERIFICATION = {
|
|
5
|
+
pageNumber: NOT_FOUND_VERIFICATION_INDEX,
|
|
6
|
+
regex: null,
|
|
7
|
+
lowerCaseSearchTerm: null,
|
|
8
|
+
attachmentId: null,
|
|
9
|
+
matchSnippet: null,
|
|
10
|
+
source: null,
|
|
11
|
+
citation: {
|
|
12
|
+
fileId: undefined,
|
|
13
|
+
startPageKey: null,
|
|
14
|
+
fullPhrase: null,
|
|
15
|
+
keySpan: null,
|
|
16
|
+
lineIds: null,
|
|
17
|
+
reasoning: null,
|
|
18
|
+
pageNumber: NOT_FOUND_VERIFICATION_INDEX,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
export function deterministicIdFromVerification(verification) {
|
|
22
|
+
return sha1Hash(`${verification.lowerCaseSearchTerm}-${verification.attachmentId}-${verification.pageNumber}-${verification.hitIndexWithinPage}-${verification.matchSnippet}-${verification?.hitIndexWithinPage}`);
|
|
23
|
+
}
|
package/package.json
CHANGED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { sha1Hash } from "../utils/sha.js";
|
|
2
|
-
export const NOT_FOUND_HIGHLIGHT_INDEX = -1;
|
|
3
|
-
export const PENDING_HIGHLIGHT_INDEX = -2;
|
|
4
|
-
export const BLANK_HIGHLIGHT_LOCATION = {
|
|
5
|
-
pageNumber: NOT_FOUND_HIGHLIGHT_INDEX,
|
|
6
|
-
regex: null,
|
|
7
|
-
lowerCaseSearchTerm: null,
|
|
8
|
-
attachmentId: null,
|
|
9
|
-
matchSnippet: null,
|
|
10
|
-
source: null,
|
|
11
|
-
citation: {
|
|
12
|
-
startPageKey: null,
|
|
13
|
-
lineIds: null,
|
|
14
|
-
pageNumber: NOT_FOUND_HIGHLIGHT_INDEX,
|
|
15
|
-
fileId: undefined,
|
|
16
|
-
fullPhrase: null,
|
|
17
|
-
value: null,
|
|
18
|
-
},
|
|
19
|
-
};
|
|
20
|
-
export function deterministicIdFromHighlightLocation(highlightLocation) {
|
|
21
|
-
return sha1Hash(`${highlightLocation.lowerCaseSearchTerm}-${highlightLocation.attachmentId}-${highlightLocation.pageNumber}-${highlightLocation.hitIndexWithinPage}-${highlightLocation.matchSnippet}-${highlightLocation?.hitIndexWithinPage}`);
|
|
22
|
-
}
|