@deepcitation/deepcitation-js 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -1197
- package/lib/client/DeepCitation.d.ts +204 -0
- package/lib/client/DeepCitation.js +473 -0
- package/lib/client/index.d.ts +2 -0
- package/lib/client/index.js +1 -0
- package/lib/client/types.d.ts +157 -0
- package/lib/client/types.js +1 -0
- package/lib/index.d.ts +25 -0
- package/lib/index.js +22 -0
- package/lib/parsing/normalizeCitation.d.ts +5 -0
- package/lib/parsing/normalizeCitation.js +182 -0
- package/lib/parsing/parseCitation.d.ts +79 -0
- package/lib/parsing/parseCitation.js +371 -0
- package/lib/parsing/parseWorkAround.d.ts +2 -0
- package/lib/parsing/parseWorkAround.js +73 -0
- package/lib/prompts/citationPrompts.d.ts +133 -0
- package/lib/prompts/citationPrompts.js +152 -0
- package/lib/prompts/index.d.ts +3 -0
- package/lib/prompts/index.js +3 -0
- package/lib/prompts/promptCompression.d.ts +14 -0
- package/lib/prompts/promptCompression.js +109 -0
- package/lib/prompts/types.d.ts +4 -0
- package/lib/prompts/types.js +1 -0
- package/lib/react/CitationComponent.d.ts +134 -0
- package/lib/react/CitationComponent.js +376 -0
- package/lib/react/CitationVariants.d.ts +135 -0
- package/lib/react/CitationVariants.js +283 -0
- package/lib/react/DiffDisplay.d.ts +10 -0
- package/lib/react/DiffDisplay.js +33 -0
- package/lib/react/UrlCitationComponent.d.ts +83 -0
- package/lib/react/UrlCitationComponent.js +224 -0
- package/lib/react/VerificationTabs.d.ts +10 -0
- package/lib/react/VerificationTabs.js +36 -0
- package/lib/react/icons.d.ts +8 -0
- package/lib/react/icons.js +9 -0
- package/lib/react/index.d.ts +16 -0
- package/lib/react/index.js +18 -0
- package/lib/react/primitives.d.ts +104 -0
- package/lib/react/primitives.js +190 -0
- package/lib/react/types.d.ts +192 -0
- package/lib/react/types.js +1 -0
- package/lib/react/useSmartDiff.d.ts +16 -0
- package/lib/react/useSmartDiff.js +64 -0
- package/lib/react/utils.d.ts +34 -0
- package/lib/react/utils.js +59 -0
- package/lib/types/boxes.d.ts +11 -0
- package/lib/types/boxes.js +1 -0
- package/lib/types/citation.d.ts +44 -0
- package/lib/types/citation.js +2 -0
- package/lib/types/foundHighlight.d.ts +23 -0
- package/lib/types/foundHighlight.js +22 -0
- package/lib/types/index.d.ts +11 -0
- package/lib/types/index.js +7 -0
- package/lib/types/search.d.ts +30 -0
- package/lib/types/search.js +1 -0
- package/lib/utils/sha.d.ts +10 -0
- package/lib/utils/sha.js +108 -0
- package/package.json +5 -2
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { useSmartDiff } from "./useSmartDiff.js";
|
|
4
|
+
import { classNames } from "./utils.js";
|
|
5
|
+
import { CheckIcon } from "./icons.js";
|
|
6
|
+
// Sub-component: The individual tab button
|
|
7
|
+
const TabButton = ({ isActive, onClick, label }) => (_jsx("button", { onClick: e => {
|
|
8
|
+
e.stopPropagation(); // Prevent tooltip from closing or dragging
|
|
9
|
+
onClick();
|
|
10
|
+
}, className: classNames("dc-tab-button", isActive ? "dc-tab-button--active" : ""), type: "button", children: label }));
|
|
11
|
+
export const VerificationTabs = ({ expected, actual, label, renderCopyButton, emptyText = "No text found", }) => {
|
|
12
|
+
const { diffResult, isHighVariance, hasDiff } = useSmartDiff(expected, actual);
|
|
13
|
+
const [activeTab, setActiveTab] = useState("diff");
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (isHighVariance) {
|
|
16
|
+
setActiveTab("found");
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
setActiveTab("diff");
|
|
20
|
+
}
|
|
21
|
+
}, [isHighVariance, expected, actual]);
|
|
22
|
+
const renderFoundContent = () => (_jsx("div", { className: "dc-tab-content dc-tab-content--found", children: actual ? (_jsxs("div", { className: "dc-tab-text-wrapper", children: [renderCopyButton && _jsx("div", { className: "dc-copy-button-wrapper", children: renderCopyButton(actual, "found") }), _jsx("div", { className: "dc-tab-text", children: actual })] })) : (_jsx("span", { className: "dc-tab-empty", children: emptyText })) }));
|
|
23
|
+
const isExactMatch = !hasDiff && Boolean(actual) && Boolean(expected);
|
|
24
|
+
if (isExactMatch) {
|
|
25
|
+
return (_jsxs("div", { className: "dc-verification-tabs dc-verification-tabs--exact", children: [label && _jsx("div", { className: "dc-verification-label", children: label }), _jsxs("div", { className: "dc-exact-match-badge", children: [_jsx(CheckIcon, {}), _jsx("span", { children: "Exact match" })] }), _jsx("div", { className: "dc-exact-match-content", children: renderFoundContent() })] }));
|
|
26
|
+
}
|
|
27
|
+
return (_jsxs("div", { className: "dc-verification-tabs", children: [label && _jsx("div", { className: "dc-verification-label", children: label }), _jsx("div", { className: "dc-tabs-container", children: _jsxs("div", { className: "dc-tabs-nav", children: [_jsx(TabButton, { label: "Expected", isActive: activeTab === "expected", onClick: () => setActiveTab("expected") }), _jsx(TabButton, { label: "Diff", isActive: activeTab === "diff", onClick: () => setActiveTab("diff") }), _jsx(TabButton, { label: "Found", isActive: activeTab === "found", onClick: () => setActiveTab("found") })] }) }), _jsxs("div", { className: "dc-tabs-content", children: [activeTab === "found" && renderFoundContent(), activeTab === "expected" && (_jsx("div", { className: "dc-tab-content dc-tab-content--expected", children: _jsxs("div", { className: "dc-tab-text-wrapper", children: [renderCopyButton && (_jsx("div", { className: "dc-copy-button-wrapper", children: renderCopyButton(expected, "expected") })), _jsx("div", { className: "dc-tab-text", children: expected })] }) })), activeTab === "diff" && (_jsx("div", { className: "dc-tab-content dc-tab-content--diff", children: !hasDiff ? (_jsxs("div", { className: "dc-exact-match-indicator", children: [_jsx(CheckIcon, {}), _jsx("span", { children: "Exact Match" })] })) : (_jsx("div", { className: "dc-diff-result", children: diffResult.map((block, i) => (_jsx("div", { className: classNames("dc-diff-block", block.type === "added" ? "dc-diff-block--added" : "", block.type === "removed" ? "dc-diff-block--removed" : ""), children: block.parts.map((part, j) => {
|
|
28
|
+
if (part.removed) {
|
|
29
|
+
return (_jsx("span", { className: "dc-diff-part dc-diff-part--removed", title: "Expected but not found", children: part.value }, j));
|
|
30
|
+
}
|
|
31
|
+
if (part.added) {
|
|
32
|
+
return (_jsx("span", { className: "dc-diff-part dc-diff-part--added", title: "Actually found in source", children: part.value }, j));
|
|
33
|
+
}
|
|
34
|
+
return (_jsx("span", { className: "dc-diff-part dc-diff-part--unchanged", children: part.value }, j));
|
|
35
|
+
}) }, i))) })) }))] })] }));
|
|
36
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Check icon SVG (no dependencies)
|
|
4
|
+
*/
|
|
5
|
+
export const CheckIcon = () => (_jsx("svg", { className: "dc-check-icon", viewBox: "0 0 256 256", fill: "currentColor", "aria-hidden": "true", children: _jsx("path", { d: "M229.66,66.34 L96,200 L34.34,138.34 L51,121.66 L96,166.69 L213,50 Z", stroke: "currentColor", strokeWidth: "12" }) }));
|
|
6
|
+
/**
|
|
7
|
+
* Warning icon SVG (no dependencies)
|
|
8
|
+
*/
|
|
9
|
+
export const WarningIcon = () => (_jsx("svg", { className: "dc-status-icon", viewBox: "0 0 256 256", fill: "currentColor", "aria-hidden": "true", children: _jsx("path", { d: "M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM120,104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm8,88a12,12,0,1,1,12-12A12,12,0,0,1,128,192Z" }) }));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepCitation React Utilities
|
|
3
|
+
*
|
|
4
|
+
* Note: UI components have been moved to a shadcn-style copy-paste pattern.
|
|
5
|
+
* See the documentation at https://deepcitation.com/docs/components for
|
|
6
|
+
* ready-to-use React components.
|
|
7
|
+
*
|
|
8
|
+
* This module exports utilities and types that are useful for building
|
|
9
|
+
* your own citation components.
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
export type { CitationContentProps, CitationRenderProps, CitationTooltipProps, CitationStyles, CitationStateClasses, CitationCursorClasses, CitationEventHandlers, CitationVariant as CitationVariantType, UrlFetchStatus, UrlCitationMeta, UrlCitationProps, } from "./types.js";
|
|
14
|
+
export { extractDomain, isBlockedStatus, isErrorStatus, isVerifiedStatus } from "./UrlCitationComponent.js";
|
|
15
|
+
export { generateCitationKey, generateCitationInstanceId, getCitationDisplayText, getCitationValueText, classNames, CITATION_X_PADDING, CITATION_Y_PADDING, } from "./utils.js";
|
|
16
|
+
export { CitationComponent, MemoizedCitationComponent, type CitationVariant, type CitationComponentProps, } from "./CitationComponent.js";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepCitation React Utilities
|
|
3
|
+
*
|
|
4
|
+
* Note: UI components have been moved to a shadcn-style copy-paste pattern.
|
|
5
|
+
* See the documentation at https://deepcitation.com/docs/components for
|
|
6
|
+
* ready-to-use React components.
|
|
7
|
+
*
|
|
8
|
+
* This module exports utilities and types that are useful for building
|
|
9
|
+
* your own citation components.
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
// URL Utilities - For handling URL citation metadata
|
|
14
|
+
export { extractDomain, isBlockedStatus, isErrorStatus, isVerifiedStatus } from "./UrlCitationComponent.js";
|
|
15
|
+
// Utilities - For generating citation keys and display text
|
|
16
|
+
export { generateCitationKey, generateCitationInstanceId, getCitationDisplayText, getCitationValueText, classNames, CITATION_X_PADDING, CITATION_Y_PADDING, } from "./utils.js";
|
|
17
|
+
// Components
|
|
18
|
+
export { CitationComponent, MemoizedCitationComponent, } from "./CitationComponent.js";
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Citation Primitives - Composable building blocks for citation components
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
import React, { type ReactNode, type HTMLAttributes, type MouseEvent, type TouchEvent } from "react";
|
|
6
|
+
import type { Citation as CitationType, CitationStatus } from "../types/citation.js";
|
|
7
|
+
import type { FoundHighlightLocation } from "../types/foundHighlight.js";
|
|
8
|
+
import type { SearchState } from "../types/search.js";
|
|
9
|
+
interface CitationContextValue {
|
|
10
|
+
citation: CitationType;
|
|
11
|
+
citationKey: string;
|
|
12
|
+
citationInstanceId: string;
|
|
13
|
+
status: CitationStatus;
|
|
14
|
+
foundCitation: FoundHighlightLocation | null;
|
|
15
|
+
searchState: SearchState | null;
|
|
16
|
+
config: {
|
|
17
|
+
displayCitationValue: boolean;
|
|
18
|
+
fallbackDisplay: string | null;
|
|
19
|
+
pendingContent: ReactNode;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** Access citation context. Must be used within Citation.Root. */
|
|
23
|
+
export declare function useCitationContext(): CitationContextValue;
|
|
24
|
+
/** Safely access citation context (returns null if not in context). */
|
|
25
|
+
export declare function useCitationContextSafe(): CitationContextValue | null;
|
|
26
|
+
export interface CitationRootProps {
|
|
27
|
+
citation: CitationType;
|
|
28
|
+
foundCitation?: FoundHighlightLocation | null;
|
|
29
|
+
searchState?: SearchState | null;
|
|
30
|
+
children: ReactNode;
|
|
31
|
+
displayCitationValue?: boolean;
|
|
32
|
+
fallbackDisplay?: string | null;
|
|
33
|
+
pendingContent?: ReactNode;
|
|
34
|
+
}
|
|
35
|
+
/** Root component that provides citation context to all child primitives. */
|
|
36
|
+
export declare const CitationRoot: React.ForwardRefExoticComponent<CitationRootProps & React.HTMLAttributes<HTMLSpanElement> & React.RefAttributes<HTMLSpanElement>>;
|
|
37
|
+
export interface CitationTriggerProps extends HTMLAttributes<HTMLSpanElement> {
|
|
38
|
+
onCitationClick?: (citation: CitationType, citationKey: string, event: MouseEvent) => void;
|
|
39
|
+
onCitationMouseEnter?: (citation: CitationType, citationKey: string) => void;
|
|
40
|
+
onCitationMouseLeave?: (citation: CitationType, citationKey: string) => void;
|
|
41
|
+
onCitationTouchEnd?: (citation: CitationType, citationKey: string, event: TouchEvent) => void;
|
|
42
|
+
isMobile?: boolean;
|
|
43
|
+
disableHover?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/** Interactive trigger component for the citation. */
|
|
46
|
+
export declare const CitationTrigger: React.ForwardRefExoticComponent<CitationTriggerProps & React.RefAttributes<HTMLSpanElement>>;
|
|
47
|
+
export interface CitationBracketProps extends HTMLAttributes<HTMLSpanElement> {
|
|
48
|
+
open?: string;
|
|
49
|
+
close?: string;
|
|
50
|
+
}
|
|
51
|
+
/** Bracket wrapper component for citation content. */
|
|
52
|
+
export declare const CitationBracket: React.ForwardRefExoticComponent<CitationBracketProps & React.RefAttributes<HTMLSpanElement>>;
|
|
53
|
+
export interface CitationNumberProps extends HTMLAttributes<HTMLSpanElement> {
|
|
54
|
+
number?: string | number;
|
|
55
|
+
}
|
|
56
|
+
/** Displays the citation number. */
|
|
57
|
+
export declare const CitationNumber: React.ForwardRefExoticComponent<CitationNumberProps & React.RefAttributes<HTMLSpanElement>>;
|
|
58
|
+
export interface CitationValueProps extends HTMLAttributes<HTMLSpanElement> {
|
|
59
|
+
value?: string;
|
|
60
|
+
separator?: string;
|
|
61
|
+
}
|
|
62
|
+
/** Displays the citation value (summary text). */
|
|
63
|
+
export declare const CitationValue: React.ForwardRefExoticComponent<CitationValueProps & React.RefAttributes<HTMLSpanElement>>;
|
|
64
|
+
export interface CitationIndicatorProps extends HTMLAttributes<HTMLSpanElement> {
|
|
65
|
+
verifiedIndicator?: ReactNode;
|
|
66
|
+
partialIndicator?: ReactNode;
|
|
67
|
+
missIndicator?: ReactNode;
|
|
68
|
+
pendingIndicator?: ReactNode;
|
|
69
|
+
showFor?: Array<"verified" | "partial" | "miss" | "pending">;
|
|
70
|
+
}
|
|
71
|
+
/** Displays a status indicator based on citation verification state. */
|
|
72
|
+
export declare const CitationIndicator: React.ForwardRefExoticComponent<CitationIndicatorProps & React.RefAttributes<HTMLSpanElement>>;
|
|
73
|
+
export interface CitationStatusProps {
|
|
74
|
+
children: (status: CitationStatus) => ReactNode;
|
|
75
|
+
}
|
|
76
|
+
/** Render prop component for accessing citation status. */
|
|
77
|
+
export declare function CitationStatusComponent({ children }: CitationStatusProps): import("react/jsx-runtime").JSX.Element;
|
|
78
|
+
export declare namespace CitationStatusComponent {
|
|
79
|
+
var displayName: string;
|
|
80
|
+
}
|
|
81
|
+
export interface CitationPhraseProps extends HTMLAttributes<HTMLSpanElement> {
|
|
82
|
+
maxLength?: number;
|
|
83
|
+
truncationSuffix?: string;
|
|
84
|
+
}
|
|
85
|
+
/** Displays the citation's full phrase with optional truncation. */
|
|
86
|
+
export declare const CitationPhrase: React.ForwardRefExoticComponent<CitationPhraseProps & React.RefAttributes<HTMLSpanElement>>;
|
|
87
|
+
export interface CitationPageProps extends HTMLAttributes<HTMLSpanElement> {
|
|
88
|
+
prefix?: string;
|
|
89
|
+
}
|
|
90
|
+
/** Displays the citation's page number. */
|
|
91
|
+
export declare const CitationPage: React.ForwardRefExoticComponent<CitationPageProps & React.RefAttributes<HTMLSpanElement>>;
|
|
92
|
+
/** Citation primitives namespace for composable citation components. */
|
|
93
|
+
export declare const Citation: {
|
|
94
|
+
readonly Root: React.ForwardRefExoticComponent<CitationRootProps & React.HTMLAttributes<HTMLSpanElement> & React.RefAttributes<HTMLSpanElement>>;
|
|
95
|
+
readonly Trigger: React.ForwardRefExoticComponent<CitationTriggerProps & React.RefAttributes<HTMLSpanElement>>;
|
|
96
|
+
readonly Bracket: React.ForwardRefExoticComponent<CitationBracketProps & React.RefAttributes<HTMLSpanElement>>;
|
|
97
|
+
readonly Number: React.ForwardRefExoticComponent<CitationNumberProps & React.RefAttributes<HTMLSpanElement>>;
|
|
98
|
+
readonly Value: React.ForwardRefExoticComponent<CitationValueProps & React.RefAttributes<HTMLSpanElement>>;
|
|
99
|
+
readonly Indicator: React.ForwardRefExoticComponent<CitationIndicatorProps & React.RefAttributes<HTMLSpanElement>>;
|
|
100
|
+
readonly Status: typeof CitationStatusComponent;
|
|
101
|
+
readonly Phrase: React.ForwardRefExoticComponent<CitationPhraseProps & React.RefAttributes<HTMLSpanElement>>;
|
|
102
|
+
readonly Page: React.ForwardRefExoticComponent<CitationPageProps & React.RefAttributes<HTMLSpanElement>>;
|
|
103
|
+
};
|
|
104
|
+
export {};
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Citation Primitives - Composable building blocks for citation components
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
import { createContext, useContext, useMemo, useCallback, forwardRef, } from "react";
|
|
7
|
+
import { getCitationStatus } from "../parsing/parseCitation.js";
|
|
8
|
+
import { generateCitationKey, generateCitationInstanceId, classNames } from "./utils.js";
|
|
9
|
+
const CitationContext = createContext(null);
|
|
10
|
+
/** Access citation context. Must be used within Citation.Root. */
|
|
11
|
+
export function useCitationContext() {
|
|
12
|
+
const context = useContext(CitationContext);
|
|
13
|
+
if (!context) {
|
|
14
|
+
throw new Error("Citation components must be used within a Citation.Root");
|
|
15
|
+
}
|
|
16
|
+
return context;
|
|
17
|
+
}
|
|
18
|
+
/** Safely access citation context (returns null if not in context). */
|
|
19
|
+
export function useCitationContextSafe() {
|
|
20
|
+
return useContext(CitationContext);
|
|
21
|
+
}
|
|
22
|
+
/** Root component that provides citation context to all child primitives. */
|
|
23
|
+
export const CitationRoot = forwardRef(({ citation, foundCitation = null, searchState = null, children, displayCitationValue = false, fallbackDisplay = null, pendingContent = "..", className, ...props }, ref) => {
|
|
24
|
+
const citationKey = useMemo(() => generateCitationKey(citation), [citation]);
|
|
25
|
+
const citationInstanceId = useMemo(() => generateCitationInstanceId(citationKey), [citationKey]);
|
|
26
|
+
const status = getCitationStatus(foundCitation);
|
|
27
|
+
const contextValue = useMemo(() => ({
|
|
28
|
+
citation,
|
|
29
|
+
citationKey,
|
|
30
|
+
citationInstanceId,
|
|
31
|
+
status,
|
|
32
|
+
foundCitation,
|
|
33
|
+
searchState,
|
|
34
|
+
config: {
|
|
35
|
+
displayCitationValue,
|
|
36
|
+
fallbackDisplay,
|
|
37
|
+
pendingContent,
|
|
38
|
+
},
|
|
39
|
+
}), [
|
|
40
|
+
citation,
|
|
41
|
+
citationKey,
|
|
42
|
+
citationInstanceId,
|
|
43
|
+
status,
|
|
44
|
+
foundCitation,
|
|
45
|
+
searchState,
|
|
46
|
+
displayCitationValue,
|
|
47
|
+
fallbackDisplay,
|
|
48
|
+
pendingContent,
|
|
49
|
+
]);
|
|
50
|
+
return (_jsx(CitationContext.Provider, { value: contextValue, children: _jsx("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, className: classNames("citation-root", className), ...props, children: children }) }));
|
|
51
|
+
});
|
|
52
|
+
CitationRoot.displayName = "Citation.Root";
|
|
53
|
+
/** Interactive trigger component for the citation. */
|
|
54
|
+
export const CitationTrigger = forwardRef(({ children, className, onCitationClick, onCitationMouseEnter, onCitationMouseLeave, onCitationTouchEnd, isMobile = false, disableHover = false, onClick, onMouseEnter, onMouseLeave, onMouseDown, onTouchEnd, ...props }, ref) => {
|
|
55
|
+
const { citation, citationKey, status } = useCitationContext();
|
|
56
|
+
const handleClick = useCallback((e) => {
|
|
57
|
+
e.stopPropagation();
|
|
58
|
+
onClick?.(e);
|
|
59
|
+
}, [onClick]);
|
|
60
|
+
const handleMouseDown = useCallback((e) => {
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
e.stopPropagation();
|
|
63
|
+
onMouseDown?.(e);
|
|
64
|
+
onCitationClick?.(citation, citationKey, e);
|
|
65
|
+
}, [onMouseDown, onCitationClick, citation, citationKey]);
|
|
66
|
+
const handleMouseEnter = useCallback((e) => {
|
|
67
|
+
onMouseEnter?.(e);
|
|
68
|
+
if (!disableHover) {
|
|
69
|
+
onCitationMouseEnter?.(citation, citationKey);
|
|
70
|
+
}
|
|
71
|
+
}, [onMouseEnter, disableHover, onCitationMouseEnter, citation, citationKey]);
|
|
72
|
+
const handleMouseLeave = useCallback((e) => {
|
|
73
|
+
onMouseLeave?.(e);
|
|
74
|
+
if (!disableHover) {
|
|
75
|
+
onCitationMouseLeave?.(citation, citationKey);
|
|
76
|
+
}
|
|
77
|
+
}, [onMouseLeave, disableHover, onCitationMouseLeave, citation, citationKey]);
|
|
78
|
+
const handleTouchEnd = useCallback((e) => {
|
|
79
|
+
onTouchEnd?.(e);
|
|
80
|
+
if (isMobile) {
|
|
81
|
+
e.preventDefault();
|
|
82
|
+
e.stopPropagation();
|
|
83
|
+
onCitationTouchEnd?.(citation, citationKey, e);
|
|
84
|
+
}
|
|
85
|
+
}, [onTouchEnd, isMobile, onCitationTouchEnd, citation, citationKey]);
|
|
86
|
+
const statusClasses = classNames(status.isVerified && !status.isPartialMatch && "citation-trigger--verified", status.isPartialMatch && "citation-trigger--partial", status.isMiss && "citation-trigger--miss", status.isPending && "citation-trigger--pending");
|
|
87
|
+
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
|
+
});
|
|
89
|
+
CitationTrigger.displayName = "Citation.Trigger";
|
|
90
|
+
/** Bracket wrapper component for citation content. */
|
|
91
|
+
export const CitationBracket = forwardRef(({ children, className, open = "[", close = "]", ...props }, ref) => {
|
|
92
|
+
return (_jsxs("span", { ref: ref, className: classNames("citation-bracket", className), "aria-hidden": "true", ...props, children: [_jsx("span", { className: "citation-bracket__open", children: open }), _jsx("span", { className: "citation-bracket__content", children: children }), _jsx("span", { className: "citation-bracket__close", children: close })] }));
|
|
93
|
+
});
|
|
94
|
+
CitationBracket.displayName = "Citation.Bracket";
|
|
95
|
+
/** Displays the citation number. */
|
|
96
|
+
export const CitationNumber = forwardRef(({ className, number, ...props }, ref) => {
|
|
97
|
+
const { citation, config, status } = useCitationContext();
|
|
98
|
+
const displayNumber = useMemo(() => {
|
|
99
|
+
if (number !== undefined)
|
|
100
|
+
return String(number);
|
|
101
|
+
if (config.displayCitationValue) {
|
|
102
|
+
return citation.value || citation.citationNumber?.toString() || config.fallbackDisplay || "";
|
|
103
|
+
}
|
|
104
|
+
return citation.citationNumber?.toString() || "";
|
|
105
|
+
}, [number, citation, config]);
|
|
106
|
+
if (status.isPending) {
|
|
107
|
+
return (_jsx("span", { ref: ref, className: classNames("citation-number citation-number--pending", className), ...props, children: config.pendingContent }));
|
|
108
|
+
}
|
|
109
|
+
return (_jsx("span", { ref: ref, className: classNames("citation-number", className), ...props, children: displayNumber }));
|
|
110
|
+
});
|
|
111
|
+
CitationNumber.displayName = "Citation.Number";
|
|
112
|
+
/** Displays the citation value (summary text). */
|
|
113
|
+
export const CitationValue = forwardRef(({ className, value, separator = " ", ...props }, ref) => {
|
|
114
|
+
const { citation, config } = useCitationContext();
|
|
115
|
+
const displayValue = useMemo(() => {
|
|
116
|
+
if (value !== undefined)
|
|
117
|
+
return value;
|
|
118
|
+
if (config.displayCitationValue)
|
|
119
|
+
return "";
|
|
120
|
+
return citation.value || "";
|
|
121
|
+
}, [value, citation, config]);
|
|
122
|
+
if (!displayValue)
|
|
123
|
+
return null;
|
|
124
|
+
return (_jsxs("span", { ref: ref, className: classNames("citation-value", className), ...props, children: [displayValue, separator] }));
|
|
125
|
+
});
|
|
126
|
+
CitationValue.displayName = "Citation.Value";
|
|
127
|
+
/** Displays a status indicator based on citation verification state. */
|
|
128
|
+
export const CitationIndicator = forwardRef(({ className, verifiedIndicator = "✓", partialIndicator = "*", missIndicator = null, pendingIndicator = null, showFor, ...props }, ref) => {
|
|
129
|
+
const { status } = useCitationContext();
|
|
130
|
+
const shouldShow = useCallback((state) => {
|
|
131
|
+
if (!showFor)
|
|
132
|
+
return true;
|
|
133
|
+
return showFor.includes(state);
|
|
134
|
+
}, [showFor]);
|
|
135
|
+
if (status.isPartialMatch && shouldShow("partial")) {
|
|
136
|
+
return (_jsx("span", { ref: ref, className: classNames("citation-indicator citation-indicator--partial", className), "aria-label": "Partial match", ...props, children: partialIndicator }));
|
|
137
|
+
}
|
|
138
|
+
if (status.isVerified && !status.isPartialMatch && shouldShow("verified")) {
|
|
139
|
+
return (_jsx("span", { ref: ref, className: classNames("citation-indicator citation-indicator--verified", className), "aria-label": "Verified", ...props, children: verifiedIndicator }));
|
|
140
|
+
}
|
|
141
|
+
if (status.isMiss && shouldShow("miss") && missIndicator) {
|
|
142
|
+
return (_jsx("span", { ref: ref, className: classNames("citation-indicator citation-indicator--miss", className), "aria-label": "Not found", ...props, children: missIndicator }));
|
|
143
|
+
}
|
|
144
|
+
if (status.isPending && shouldShow("pending") && pendingIndicator) {
|
|
145
|
+
return (_jsx("span", { ref: ref, className: classNames("citation-indicator citation-indicator--pending", className), "aria-label": "Pending", ...props, children: pendingIndicator }));
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
});
|
|
149
|
+
CitationIndicator.displayName = "Citation.Indicator";
|
|
150
|
+
/** Render prop component for accessing citation status. */
|
|
151
|
+
export function CitationStatusComponent({ children }) {
|
|
152
|
+
const { status } = useCitationContext();
|
|
153
|
+
return _jsx(_Fragment, { children: children(status) });
|
|
154
|
+
}
|
|
155
|
+
CitationStatusComponent.displayName = "Citation.Status";
|
|
156
|
+
/** Displays the citation's full phrase with optional truncation. */
|
|
157
|
+
export const CitationPhrase = forwardRef(({ className, maxLength, truncationSuffix = "...", ...props }, ref) => {
|
|
158
|
+
const { citation } = useCitationContext();
|
|
159
|
+
const displayPhrase = useMemo(() => {
|
|
160
|
+
const phrase = citation.fullPhrase || "";
|
|
161
|
+
if (!maxLength || phrase.length <= maxLength)
|
|
162
|
+
return phrase;
|
|
163
|
+
return phrase.slice(0, maxLength) + truncationSuffix;
|
|
164
|
+
}, [citation.fullPhrase, maxLength, truncationSuffix]);
|
|
165
|
+
if (!displayPhrase)
|
|
166
|
+
return null;
|
|
167
|
+
return (_jsx("span", { ref: ref, className: classNames("citation-phrase", className), ...props, children: displayPhrase }));
|
|
168
|
+
});
|
|
169
|
+
CitationPhrase.displayName = "Citation.Phrase";
|
|
170
|
+
/** Displays the citation's page number. */
|
|
171
|
+
export const CitationPage = forwardRef(({ className, prefix = "", ...props }, ref) => {
|
|
172
|
+
const { citation } = useCitationContext();
|
|
173
|
+
if (citation.pageNumber === undefined || citation.pageNumber === null) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
return (_jsxs("span", { ref: ref, className: classNames("citation-page", className), ...props, children: [prefix, citation.pageNumber] }));
|
|
177
|
+
});
|
|
178
|
+
CitationPage.displayName = "Citation.Page";
|
|
179
|
+
/** Citation primitives namespace for composable citation components. */
|
|
180
|
+
export const Citation = {
|
|
181
|
+
Root: CitationRoot,
|
|
182
|
+
Trigger: CitationTrigger,
|
|
183
|
+
Bracket: CitationBracket,
|
|
184
|
+
Number: CitationNumber,
|
|
185
|
+
Value: CitationValue,
|
|
186
|
+
Indicator: CitationIndicator,
|
|
187
|
+
Status: CitationStatusComponent,
|
|
188
|
+
Phrase: CitationPhrase,
|
|
189
|
+
Page: CitationPage,
|
|
190
|
+
};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import type { Citation, CitationStatus } from "../types/citation.js";
|
|
2
|
+
import type { FoundHighlightLocation } from "../types/foundHighlight.js";
|
|
3
|
+
import type { SearchState } from "../types/search.js";
|
|
4
|
+
/**
|
|
5
|
+
* Available citation display variants.
|
|
6
|
+
*
|
|
7
|
+
* - `brackets`: Shows value/number in brackets with blue text styling (default)
|
|
8
|
+
* - `numeric`: Shows citation number with indicator, no brackets
|
|
9
|
+
* - `text`: Shows the value, no text styling, no truncate, shows indicator
|
|
10
|
+
* - `minimal`: No brackets, just display text with indicator
|
|
11
|
+
* - `indicator`: Only the status indicator (checkmark/warning), no text
|
|
12
|
+
*/
|
|
13
|
+
export type CitationVariant = "brackets" | "numeric" | "text" | "minimal" | "indicator";
|
|
14
|
+
/**
|
|
15
|
+
* URL fetch status for URL citations.
|
|
16
|
+
*/
|
|
17
|
+
export type UrlFetchStatus = "verified" | "partial" | "pending" | "blocked_antibot" | "blocked_login" | "blocked_paywall" | "blocked_geo" | "blocked_rate_limit" | "error_timeout" | "error_not_found" | "error_server" | "error_network" | "unknown";
|
|
18
|
+
/**
|
|
19
|
+
* URL citation metadata.
|
|
20
|
+
*/
|
|
21
|
+
export interface UrlCitationMeta {
|
|
22
|
+
/** The full URL */
|
|
23
|
+
url: string;
|
|
24
|
+
/** Display domain (e.g., "example.com") */
|
|
25
|
+
domain?: string;
|
|
26
|
+
/** Page title if fetched */
|
|
27
|
+
title?: string;
|
|
28
|
+
/** Fetch/verification status */
|
|
29
|
+
fetchStatus: UrlFetchStatus;
|
|
30
|
+
/** When the URL was last verified */
|
|
31
|
+
verifiedAt?: Date | string;
|
|
32
|
+
/** HTTP status code if available */
|
|
33
|
+
httpStatus?: number;
|
|
34
|
+
/** Error message if applicable */
|
|
35
|
+
errorMessage?: string;
|
|
36
|
+
/** Favicon URL if available */
|
|
37
|
+
faviconUrl?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Style configuration for the citation component.
|
|
41
|
+
* All properties are optional class name strings.
|
|
42
|
+
*/
|
|
43
|
+
export interface CitationStyles {
|
|
44
|
+
/** Container wrapper class */
|
|
45
|
+
container?: string;
|
|
46
|
+
/** Citation number bracket wrapper */
|
|
47
|
+
bracketWrapper?: string;
|
|
48
|
+
/** Inner bracket content */
|
|
49
|
+
bracketContent?: string;
|
|
50
|
+
/** Citation text/number itself */
|
|
51
|
+
citationText?: string;
|
|
52
|
+
/** Verified status indicator */
|
|
53
|
+
verifiedIcon?: string;
|
|
54
|
+
/** Partial match indicator */
|
|
55
|
+
partialIcon?: string;
|
|
56
|
+
/** Pending/loading state */
|
|
57
|
+
pendingText?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* State classes applied based on citation verification status
|
|
61
|
+
*/
|
|
62
|
+
export interface CitationStateClasses {
|
|
63
|
+
/** Applied when citation is verified (found in document) */
|
|
64
|
+
verified?: string;
|
|
65
|
+
/** Applied when citation is a miss (not found) */
|
|
66
|
+
miss?: string;
|
|
67
|
+
/** Applied when citation is a partial match */
|
|
68
|
+
partial?: string;
|
|
69
|
+
/** Applied when citation verification is pending */
|
|
70
|
+
pending?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Cursor classes for different zoom states
|
|
74
|
+
*/
|
|
75
|
+
export interface CitationCursorClasses {
|
|
76
|
+
zoomIn?: string;
|
|
77
|
+
zoomOut?: string;
|
|
78
|
+
pointer?: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Props for the base CitationComponent
|
|
82
|
+
*/
|
|
83
|
+
export interface BaseCitationProps {
|
|
84
|
+
/** The citation data to display */
|
|
85
|
+
citation: Citation;
|
|
86
|
+
/** Child content to render before the citation bracket */
|
|
87
|
+
children?: React.ReactNode;
|
|
88
|
+
/** Additional class name for the container */
|
|
89
|
+
className?: string;
|
|
90
|
+
/** Class name for controlling inner content width */
|
|
91
|
+
innerWidthClassName?: string;
|
|
92
|
+
/** When true, displays value/citationNumber merged in the bracket */
|
|
93
|
+
displayCitationValue?: boolean;
|
|
94
|
+
/** Fallback display text when citation value is empty */
|
|
95
|
+
fallbackDisplay?: string | null;
|
|
96
|
+
/** Display variant for the citation */
|
|
97
|
+
variant?: CitationVariant;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Props for URL citation component
|
|
101
|
+
*/
|
|
102
|
+
export interface UrlCitationProps extends Omit<BaseCitationProps, "citation"> {
|
|
103
|
+
/** URL metadata including fetch status */
|
|
104
|
+
urlMeta: UrlCitationMeta;
|
|
105
|
+
/** The citation data (optional, will be derived from urlMeta if not provided) */
|
|
106
|
+
citation?: Citation;
|
|
107
|
+
/** Whether to show the full URL on hover */
|
|
108
|
+
showFullUrlOnHover?: boolean;
|
|
109
|
+
/** Whether to show favicon */
|
|
110
|
+
showFavicon?: boolean;
|
|
111
|
+
/** Whether to show the page title instead of domain */
|
|
112
|
+
showTitle?: boolean;
|
|
113
|
+
/** Maximum characters for truncated display */
|
|
114
|
+
maxDisplayLength?: number;
|
|
115
|
+
/** Custom render for the blocked status indicator */
|
|
116
|
+
renderBlockedIndicator?: (status: UrlFetchStatus, errorMessage?: string) => React.ReactNode;
|
|
117
|
+
/** Click handler for the URL */
|
|
118
|
+
onUrlClick?: (url: string, event: React.MouseEvent) => void;
|
|
119
|
+
/** Event handlers for citation interactions */
|
|
120
|
+
eventHandlers?: CitationEventHandlers;
|
|
121
|
+
/** Whether tooltips should be prevented */
|
|
122
|
+
preventTooltips?: boolean;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Extended props for the citation content renderer
|
|
126
|
+
*/
|
|
127
|
+
export interface CitationContentProps extends BaseCitationProps {
|
|
128
|
+
/** Unique key for this citation */
|
|
129
|
+
citationKey: string;
|
|
130
|
+
/** Unique instance ID for this citation render */
|
|
131
|
+
citationInstanceId: string;
|
|
132
|
+
/** Found citation highlight data */
|
|
133
|
+
foundCitation: FoundHighlightLocation | null | undefined;
|
|
134
|
+
/** Current search state */
|
|
135
|
+
searchState: SearchState | undefined | null;
|
|
136
|
+
/** Actual page number where citation was found */
|
|
137
|
+
actualPageNumber?: number | null;
|
|
138
|
+
/** Page number from citation data */
|
|
139
|
+
citationPageNumber?: number | null;
|
|
140
|
+
/** Unique highlight ID */
|
|
141
|
+
highlightId?: string;
|
|
142
|
+
/** Citation verification status */
|
|
143
|
+
status: CitationStatus;
|
|
144
|
+
/** Whether tooltips should be suppressed */
|
|
145
|
+
preventTooltips?: boolean;
|
|
146
|
+
/** Whether on mobile device */
|
|
147
|
+
isMobile?: boolean;
|
|
148
|
+
/** Style configuration */
|
|
149
|
+
styles?: CitationStyles;
|
|
150
|
+
/** State-based classes */
|
|
151
|
+
stateClasses?: CitationStateClasses;
|
|
152
|
+
/** Cursor classes */
|
|
153
|
+
cursorClasses?: CitationCursorClasses;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Render props for custom citation rendering
|
|
157
|
+
*/
|
|
158
|
+
export interface CitationRenderProps {
|
|
159
|
+
/** The citation data */
|
|
160
|
+
citation: Citation;
|
|
161
|
+
/** Citation verification status */
|
|
162
|
+
status: CitationStatus;
|
|
163
|
+
/** The citation key */
|
|
164
|
+
citationKey: string;
|
|
165
|
+
/** Display text for the citation */
|
|
166
|
+
displayText: string;
|
|
167
|
+
/** Whether this is a merged value display */
|
|
168
|
+
isMergedDisplay: boolean;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Event handlers for citation interactions
|
|
172
|
+
*/
|
|
173
|
+
export interface CitationEventHandlers {
|
|
174
|
+
/** Called when mouse enters citation */
|
|
175
|
+
onMouseEnter?: (citation: Citation, citationKey: string) => void;
|
|
176
|
+
/** Called when mouse leaves citation */
|
|
177
|
+
onMouseLeave?: (citation: Citation, citationKey: string) => void;
|
|
178
|
+
/** Called when citation is clicked */
|
|
179
|
+
onClick?: (citation: Citation, citationKey: string, event: React.MouseEvent | React.TouchEvent) => void;
|
|
180
|
+
/** Called on touch end (mobile) */
|
|
181
|
+
onTouchEnd?: (citation: Citation, citationKey: string, event: React.TouchEvent) => void;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Props for the tooltip wrapper component
|
|
185
|
+
*/
|
|
186
|
+
export interface CitationTooltipProps {
|
|
187
|
+
children: React.ReactNode;
|
|
188
|
+
citation: Citation;
|
|
189
|
+
foundHighlight?: FoundHighlightLocation | null;
|
|
190
|
+
searchState?: SearchState | null;
|
|
191
|
+
shouldShowTooltip: boolean;
|
|
192
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type DiffBlockType = "modified" | "added" | "removed" | "unchanged";
|
|
2
|
+
export interface DiffPart {
|
|
3
|
+
value: string;
|
|
4
|
+
added?: boolean;
|
|
5
|
+
removed?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface DiffBlock {
|
|
8
|
+
type: DiffBlockType;
|
|
9
|
+
parts: DiffPart[];
|
|
10
|
+
}
|
|
11
|
+
export declare const useSmartDiff: (expected?: string, actual?: string) => {
|
|
12
|
+
diffResult: DiffBlock[];
|
|
13
|
+
hasDiff: boolean;
|
|
14
|
+
similarity: number;
|
|
15
|
+
isHighVariance: boolean;
|
|
16
|
+
};
|