@deepcitation/deepcitation-js 1.1.25 → 1.1.27

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.
@@ -1,8 +1,8 @@
1
1
  import React from "react";
2
2
  import { type CitationStatus } from "../types/citation.js";
3
3
  import type { Verification } from "../types/verification.js";
4
- import type { BaseCitationProps, CitationBehaviorConfig, CitationEventHandlers, CitationRenderProps, CitationVariant } from "./types.js";
5
- export type { CitationVariant } from "./types.js";
4
+ import type { BaseCitationProps, CitationBehaviorConfig, CitationContent, CitationEventHandlers, CitationRenderProps, CitationVariant } from "./types.js";
5
+ export type { CitationVariant, CitationContent } from "./types.js";
6
6
  /**
7
7
  * Props for the CitationComponent.
8
8
  *
@@ -44,15 +44,28 @@ export interface CitationComponentProps extends BaseCitationProps {
44
44
  /** Verification result from the DeepCitation API */
45
45
  verification?: Verification | null;
46
46
  /**
47
- * Display variant for the citation.
48
- * - `brackets`: [keySpan✓] with styling (default)
49
- * - `text`: keySpaninherits parent styling
50
- * - `minimal`: text with indicator, no brackets
51
- * - `indicator`: only the status indicator
47
+ * Visual style variant for the citation.
48
+ * - `chip`: Pill/badge style with background color
49
+ * - `brackets`: [text] with square brackets (default)
50
+ * - `text`: Plain text, inherits parent styling
51
+ * - `superscript`: Small raised text like footnotes¹
52
+ * - `minimal`: Compact text with indicator, truncated
52
53
  */
53
54
  variant?: CitationVariant;
54
- /** Hide square brackets (only for brackets variant) */
55
- hideBrackets?: boolean;
55
+ /**
56
+ * What content to display in the citation.
57
+ * - `keySpan`: Descriptive text (e.g., "Revenue Growth")
58
+ * - `number`: Citation number (e.g., "1", "2", "3")
59
+ * - `indicator`: Only the status icon, no text
60
+ *
61
+ * Defaults based on variant:
62
+ * - `chip` → `keySpan`
63
+ * - `brackets` → `number`
64
+ * - `text` → `keySpan`
65
+ * - `superscript` → `number`
66
+ * - `minimal` → `number`
67
+ */
68
+ content?: CitationContent;
56
69
  /** Event handlers for citation interactions */
57
70
  eventHandlers?: CitationEventHandlers;
58
71
  /**
@@ -3,8 +3,40 @@ import { forwardRef, memo, useCallback, useEffect, useMemo, useState, } from "re
3
3
  import { createPortal } from "react-dom";
4
4
  import { CheckIcon, SpinnerIcon, WarningIcon } from "./icons.js";
5
5
  import { Popover, PopoverContent, PopoverTrigger } from "./Popover.js";
6
- import { cn, generateCitationInstanceId, generateCitationKey, getCitationDisplayText, } from "./utils.js";
6
+ import { cn, generateCitationInstanceId, generateCitationKey, } from "./utils.js";
7
7
  import { useSmartDiff } from "./useSmartDiff.js";
8
+ /**
9
+ * Get the default content type based on variant.
10
+ */
11
+ function getDefaultContent(variant) {
12
+ switch (variant) {
13
+ case "chip":
14
+ case "text":
15
+ return "keySpan";
16
+ case "brackets":
17
+ case "superscript":
18
+ case "minimal":
19
+ default:
20
+ return "number";
21
+ }
22
+ }
23
+ /**
24
+ * Get display text based on content type and citation data.
25
+ * Returns "1" as fallback if no citation number is available.
26
+ */
27
+ function getDisplayText(citation, content, fallbackDisplay) {
28
+ if (content === "indicator") {
29
+ return "";
30
+ }
31
+ if (content === "keySpan") {
32
+ return (citation.keySpan?.toString() ||
33
+ citation.citationNumber?.toString() ||
34
+ fallbackDisplay ||
35
+ "1");
36
+ }
37
+ // content === "number"
38
+ return citation.citationNumber?.toString() || "1";
39
+ }
8
40
  function getStatusLabel(status) {
9
41
  if (status.isVerified && !status.isPartialMatch)
10
42
  return "Verified";
@@ -171,7 +203,13 @@ function DiffDetails({ citation, verification, status, }) {
171
203
  * Use `behaviorConfig.onClick` to completely replace the click behavior,
172
204
  * or `eventHandlers.onClick` to add side effects (which disables defaults).
173
205
  */
174
- export const CitationComponent = forwardRef(({ citation, children, className, hideKeySpan = false, hideBrackets = false, fallbackDisplay, verification, variant = "brackets", eventHandlers, behaviorConfig, isMobile = false, renderIndicator, renderContent, popoverPosition = "top", renderPopoverContent, }, ref) => {
206
+ export const CitationComponent = forwardRef(({ citation, children, className, fallbackDisplay, verification, variant = "brackets", content: contentProp, eventHandlers, behaviorConfig, isMobile = false, renderIndicator, renderContent, popoverPosition = "top", renderPopoverContent, }, ref) => {
207
+ // Resolve content: explicit content prop or default for variant
208
+ const resolvedContent = useMemo(() => {
209
+ if (contentProp)
210
+ return contentProp;
211
+ return getDefaultContent(variant);
212
+ }, [contentProp, variant]);
175
213
  const [isHovering, setIsHovering] = useState(false);
176
214
  const [expandedImageSrc, setExpandedImageSrc] = useState(null);
177
215
  const citationKey = useMemo(() => generateCitationKey(citation), [citation]);
@@ -180,11 +218,8 @@ export const CitationComponent = forwardRef(({ citation, children, className, hi
180
218
  const status = useMemo(() => getStatusFromVerification(verification), [verification]);
181
219
  const { isMiss, isPartialMatch, isVerified, isPending } = status;
182
220
  const displayText = useMemo(() => {
183
- return getCitationDisplayText(citation, {
184
- hideKeySpan: variant !== "text" && variant !== "minimal" && hideKeySpan,
185
- fallbackDisplay,
186
- });
187
- }, [citation, variant, hideKeySpan, fallbackDisplay]);
221
+ return getDisplayText(citation, resolvedContent, fallbackDisplay);
222
+ }, [citation, resolvedContent, fallbackDisplay]);
188
223
  // Behavior context for custom handlers
189
224
  const getBehaviorContext = useCallback(() => ({
190
225
  citation,
@@ -276,10 +311,10 @@ export const CitationComponent = forwardRef(({ citation, children, className, hi
276
311
  eventHandlers?.onTouchEnd?.(citation, citationKey, e);
277
312
  }
278
313
  }, [eventHandlers, citation, citationKey, isMobile]);
279
- // Early return for miss with fallback display
314
+ // Early return for miss with fallback display (only when showing keySpan)
280
315
  if (fallbackDisplay !== null &&
281
316
  fallbackDisplay !== undefined &&
282
- !hideKeySpan &&
317
+ resolvedContent === "keySpan" &&
283
318
  isMiss) {
284
319
  return (_jsx("span", { className: cn("text-gray-400 dark:text-gray-500", className), children: fallbackDisplay }));
285
320
  }
@@ -316,20 +351,33 @@ export const CitationComponent = forwardRef(({ citation, children, className, hi
316
351
  status,
317
352
  citationKey,
318
353
  displayText,
319
- isMergedDisplay: variant === "text" || variant === "brackets" || !hideKeySpan,
354
+ isMergedDisplay: resolvedContent === "keySpan",
320
355
  });
321
356
  }
322
- if (variant === "indicator") {
357
+ // Content type: indicator only
358
+ if (resolvedContent === "indicator") {
323
359
  return _jsx("span", { children: renderStatusIndicator() });
324
360
  }
361
+ // Variant: chip (pill/badge style)
362
+ if (variant === "chip") {
363
+ const chipStatusClasses = cn(isVerified && !isPartialMatch && "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400", isPartialMatch && "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400", isMiss && "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400 line-through", isPending && "bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400", !isVerified && !isMiss && !isPending && "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400");
364
+ return (_jsxs("span", { className: cn("inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-sm font-medium", chipStatusClasses), children: [_jsx("span", { className: "max-w-60 overflow-hidden text-ellipsis whitespace-nowrap", children: displayText }), renderStatusIndicator()] }));
365
+ }
366
+ // Variant: superscript (footnote style)
367
+ if (variant === "superscript") {
368
+ const supStatusClasses = cn(isVerified && !isPartialMatch && "text-green-600 dark:text-green-500", isPartialMatch && "text-amber-600 dark:text-amber-500", isMiss && "text-red-500 dark:text-red-400 line-through", isPending && "text-gray-400 dark:text-gray-500", !isVerified && !isMiss && !isPending && "text-blue-600 dark:text-blue-400");
369
+ return (_jsxs("sup", { className: cn("text-xs font-medium transition-colors hover:underline", supStatusClasses), children: ["[", displayText, renderStatusIndicator(), "]"] }));
370
+ }
371
+ // Variant: text (inherits parent styling)
325
372
  if (variant === "text") {
326
373
  return (_jsxs("span", { className: statusClasses, children: [displayText, renderStatusIndicator()] }));
327
374
  }
375
+ // Variant: minimal (compact with truncation)
328
376
  if (variant === "minimal") {
329
377
  return (_jsxs("span", { className: cn("max-w-80 overflow-hidden text-ellipsis", statusClasses), children: [displayText, renderStatusIndicator()] }));
330
378
  }
331
- // brackets variant (default)
332
- return (_jsxs("span", { className: cn("inline-flex items-baseline gap-0.5 whitespace-nowrap", "font-mono text-xs leading-tight", "text-gray-500 dark:text-gray-400", "transition-colors"), "aria-hidden": "true", children: [!hideBrackets && "[", _jsxs("span", { className: cn("max-w-80 overflow-hidden text-ellipsis", statusClasses), children: [displayText, renderStatusIndicator()] }), !hideBrackets && "]"] }));
379
+ // Variant: brackets (default)
380
+ return (_jsxs("span", { className: cn("inline-flex items-baseline gap-0.5 whitespace-nowrap", "font-mono text-xs leading-tight", "text-gray-500 dark:text-gray-400", "transition-colors"), "aria-hidden": "true", children: ["[", _jsxs("span", { className: cn("max-w-80 overflow-hidden text-ellipsis", statusClasses), children: [displayText, renderStatusIndicator()] }), "]"] }));
333
381
  };
334
382
  // Popover visibility
335
383
  const isPopoverHidden = popoverPosition === "hidden";
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { memo, useMemo, useCallback, forwardRef, } from "react";
3
3
  import { getCitationStatus } from "../parsing/parseCitation.js";
4
- import { generateCitationKey, generateCitationInstanceId, getCitationDisplayText, getCitationKeySpanText, classNames, } from "./utils.js";
4
+ import { generateCitationKey, generateCitationInstanceId, getCitationDisplayText, getCitationNumber, classNames, } from "./utils.js";
5
5
  const TWO_DOTS_THINKING_CONTENT = "..";
6
6
  /**
7
7
  * Hook to get common citation data.
@@ -17,11 +17,11 @@ function useCitationData(citation, verification) {
17
17
  /**
18
18
  * Default verified indicator (checkmark)
19
19
  */
20
- const DefaultVerifiedIndicator = () => (_jsx("span", { className: "citation-verified-icon", "aria-hidden": "true", children: "\u2713" }));
20
+ const DefaultVerifiedIndicator = () => (_jsx("span", { className: "text-green-600 dark:text-green-500 ml-0.5", "aria-hidden": "true", children: "\u2713" }));
21
21
  /**
22
22
  * Default partial match indicator (asterisk)
23
23
  */
24
- const DefaultPartialIndicator = () => (_jsx("span", { className: "citation-partial-icon", "aria-hidden": "true", children: "*" }));
24
+ const DefaultPartialIndicator = () => (_jsx("span", { className: "text-amber-600 dark:text-amber-500 ml-0.5", "aria-hidden": "true", children: "*" }));
25
25
  /**
26
26
  * Chip/Badge style citation component.
27
27
  * Displays citation as a rounded pill/badge.
@@ -31,16 +31,11 @@ const DefaultPartialIndicator = () => (_jsx("span", { className: "citation-parti
31
31
  * <ChipCitation citation={citation} verification={found} size="md" />
32
32
  * ```
33
33
  */
34
- export const ChipCitation = forwardRef(({ citation, children, className, hideKeySpan = false, fallbackDisplay, verification, eventHandlers, isMobile = false, preventTooltips = false, pendingContent = TWO_DOTS_THINKING_CONTENT, renderVerifiedIndicator = () => _jsx(DefaultVerifiedIndicator, {}), renderPartialIndicator = () => _jsx(DefaultPartialIndicator, {}), size = "md", showIcon = false, icon, }, ref) => {
34
+ export const ChipCitation = forwardRef(({ citation, children, className, fallbackDisplay, verification, eventHandlers, isMobile = false, preventTooltips = false, pendingContent = TWO_DOTS_THINKING_CONTENT, renderVerifiedIndicator = () => _jsx(DefaultVerifiedIndicator, {}), renderPartialIndicator = () => _jsx(DefaultPartialIndicator, {}), size = "md", showIcon = false, icon, }, ref) => {
35
35
  const { citationKey, citationInstanceId, status } = useCitationData(citation, verification);
36
36
  const { isVerified, isMiss, isPartialMatch, isPending } = status;
37
- const displayText = useMemo(() => getCitationDisplayText(citation, {
38
- hideKeySpan,
39
- fallbackDisplay,
40
- }), [citation, hideKeySpan, fallbackDisplay]);
41
- const keySpanText = useMemo(() => getCitationKeySpanText(citation, {
42
- hideKeySpan,
43
- }), [citation, hideKeySpan]);
37
+ // ChipCitation shows keySpan by default
38
+ const displayText = useMemo(() => getCitationDisplayText(citation, { fallbackDisplay }), [citation, fallbackDisplay]);
44
39
  const handleClick = useCallback((e) => {
45
40
  e.preventDefault();
46
41
  e.stopPropagation();
@@ -53,22 +48,22 @@ export const ChipCitation = forwardRef(({ citation, children, className, hideKey
53
48
  eventHandlers?.onMouseLeave?.(citation, citationKey);
54
49
  }, [eventHandlers, citation, citationKey]);
55
50
  const sizeClasses = {
56
- sm: "citation-chip--sm",
57
- md: "citation-chip--md",
58
- lg: "citation-chip--lg",
51
+ sm: "text-xs px-1.5 py-px",
52
+ md: "text-sm px-2 py-0.5",
53
+ lg: "text-base px-3 py-1",
59
54
  };
60
55
  // Check partial first since isVerified is true when isPartialMatch is true
61
56
  const statusClass = isPartialMatch
62
- ? "citation-chip--partial"
57
+ ? "bg-amber-100 text-amber-600 dark:bg-amber-900/30 dark:text-amber-500"
63
58
  : isMiss
64
- ? "citation-chip--miss"
59
+ ? "bg-red-100 text-red-600 dark:bg-red-900/30 dark:text-red-400 line-through"
65
60
  : isVerified
66
- ? "citation-chip--verified"
61
+ ? "bg-green-100 text-green-600 dark:bg-green-900/30 dark:text-green-500"
67
62
  : isPending
68
- ? "citation-chip--pending"
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 &&
71
- (icon || _jsx("span", { className: "citation-chip__icon", children: "\uD83D\uDCC4" })), _jsx("span", { className: "citation-chip__text", children: displayText }), isPartialMatch && renderPartialIndicator(status), isVerified && !isPartialMatch && renderVerifiedIndicator(status), isPending && (_jsx("span", { className: "citation-chip__pending", children: pendingContent }))] })] }));
63
+ ? "bg-gray-100 text-gray-500 dark:bg-gray-800 dark:text-gray-400"
64
+ : "bg-blue-100 text-blue-600 dark:bg-blue-900/30 dark:text-blue-400";
65
+ return (_jsxs(_Fragment, { children: [children, _jsxs("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "chip", className: classNames("inline-flex items-center gap-1 rounded-full font-medium cursor-pointer transition-colors hover:brightness-95", 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 &&
66
+ (icon || _jsx("span", { className: "text-[0.9em]", children: "\uD83D\uDCC4" })), _jsx("span", { className: "font-medium", children: displayText }), isPartialMatch && renderPartialIndicator(status), isVerified && !isPartialMatch && renderVerifiedIndicator(status), isPending && (_jsx("span", { className: "opacity-70", children: pendingContent }))] })] }));
72
67
  });
73
68
  ChipCitation.displayName = "ChipCitation";
74
69
  /**
@@ -81,13 +76,11 @@ ChipCitation.displayName = "ChipCitation";
81
76
  * // Renders: Text content¹
82
77
  * ```
83
78
  */
84
- export const SuperscriptCitation = forwardRef(({ citation, children, className, hideKeySpan = false, fallbackDisplay, verification, eventHandlers, isMobile = false, preventTooltips = false, pendingContent = TWO_DOTS_THINKING_CONTENT, renderVerifiedIndicator = () => _jsx(DefaultVerifiedIndicator, {}), renderPartialIndicator = () => _jsx(DefaultPartialIndicator, {}), hideBrackets = false, }, ref) => {
79
+ export const SuperscriptCitation = forwardRef(({ citation, children, className, fallbackDisplay, verification, eventHandlers, isMobile = false, preventTooltips = false, pendingContent = TWO_DOTS_THINKING_CONTENT, renderVerifiedIndicator = () => _jsx(DefaultVerifiedIndicator, {}), renderPartialIndicator = () => _jsx(DefaultPartialIndicator, {}), hideBrackets = false, }, ref) => {
85
80
  const { citationKey, citationInstanceId, status } = useCitationData(citation, verification);
86
81
  const { isVerified, isMiss, isPartialMatch, isPending } = status;
87
- const displayText = useMemo(() => getCitationDisplayText(citation, {
88
- hideKeySpan,
89
- fallbackDisplay,
90
- }), [citation, hideKeySpan, fallbackDisplay]);
82
+ // SuperscriptCitation shows number by default
83
+ const displayText = useMemo(() => getCitationNumber(citation), [citation]);
91
84
  const handleClick = useCallback((e) => {
92
85
  e.preventDefault();
93
86
  e.stopPropagation();
@@ -101,15 +94,15 @@ export const SuperscriptCitation = forwardRef(({ citation, children, className,
101
94
  }, [eventHandlers, citation, citationKey]);
102
95
  // Check partial first since isVerified is true when isPartialMatch is true
103
96
  const statusClass = isPartialMatch
104
- ? "citation-superscript--partial"
97
+ ? "text-amber-600 dark:text-amber-500"
105
98
  : isMiss
106
- ? "citation-superscript--miss"
99
+ ? "text-red-500 dark:text-red-400 line-through"
107
100
  : isVerified
108
- ? "citation-superscript--verified"
101
+ ? "text-green-600 dark:text-green-500"
109
102
  : isPending
110
- ? "citation-superscript--pending"
111
- : "";
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: [!hideBrackets && "[", displayText, isPartialMatch && renderPartialIndicator(status), isVerified && !isPartialMatch && renderVerifiedIndicator(status), isPending && pendingContent, !hideBrackets && "]"] })] }));
103
+ ? "text-gray-400 dark:text-gray-500"
104
+ : "text-blue-600 dark:text-blue-400";
105
+ return (_jsxs(_Fragment, { children: [children, _jsxs("sup", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "superscript", className: classNames("text-xs cursor-pointer font-medium transition-colors hover:underline", statusClass, className), onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: (e) => e.stopPropagation(), "aria-label": `Citation ${displayText}`, children: [!hideBrackets && "[", displayText, isPartialMatch && renderPartialIndicator(status), isVerified && !isPartialMatch && renderVerifiedIndicator(status), isPending && pendingContent, !hideBrackets && "]"] })] }));
113
106
  });
114
107
  SuperscriptCitation.displayName = "SuperscriptCitation";
115
108
  const FOOTNOTE_SYMBOLS = ["*", "†", "‡", "§", "‖", "¶"];
@@ -152,15 +145,15 @@ export const FootnoteCitation = forwardRef(({ citation, children, className, fal
152
145
  }, [eventHandlers, citation, citationKey]);
153
146
  // Check partial first since isVerified is true when isPartialMatch is true
154
147
  const statusClass = isPartialMatch
155
- ? "citation-footnote--partial"
148
+ ? "text-amber-600 dark:text-amber-500"
156
149
  : isMiss
157
- ? "citation-footnote--miss"
150
+ ? "text-red-500 dark:text-red-400 line-through"
158
151
  : isVerified
159
- ? "citation-footnote--verified"
152
+ ? "text-green-600 dark:text-green-500"
160
153
  : isPending
161
- ? "citation-footnote--pending"
162
- : "";
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] })] }));
154
+ ? "text-gray-400 dark:text-gray-500"
155
+ : "text-gray-500 hover:text-blue-600 dark:text-gray-400 dark:hover:text-blue-400";
156
+ return (_jsxs(_Fragment, { children: [children, _jsxs("sup", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "footnote", className: classNames("text-xs cursor-pointer font-normal transition-colors", 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] })] }));
164
157
  });
165
158
  FootnoteCitation.displayName = "FootnoteCitation";
166
159
  /**
@@ -173,14 +166,11 @@ FootnoteCitation.displayName = "FootnoteCitation";
173
166
  * // Renders: "quoted text" with subtle underline
174
167
  * ```
175
168
  */
176
- export const InlineCitation = forwardRef(({ citation, children, className, hideKeySpan = false, // Default to showing keySpan for inline
177
- fallbackDisplay, verification, eventHandlers, preventTooltips = false, pendingContent = TWO_DOTS_THINKING_CONTENT, renderVerifiedIndicator = () => _jsx(DefaultVerifiedIndicator, {}), renderPartialIndicator = () => _jsx(DefaultPartialIndicator, {}), underlineStyle = "dotted", }, ref) => {
169
+ export const InlineCitation = forwardRef(({ citation, children, className, fallbackDisplay, verification, eventHandlers, preventTooltips = false, pendingContent = TWO_DOTS_THINKING_CONTENT, renderVerifiedIndicator = () => _jsx(DefaultVerifiedIndicator, {}), renderPartialIndicator = () => _jsx(DefaultPartialIndicator, {}), underlineStyle = "dotted", }, ref) => {
178
170
  const { citationKey, citationInstanceId, status } = useCitationData(citation, verification);
179
171
  const { isVerified, isMiss, isPartialMatch, isPending } = status;
180
- const displayText = useMemo(() => getCitationDisplayText(citation, {
181
- hideKeySpan,
182
- fallbackDisplay,
183
- }), [citation, hideKeySpan, fallbackDisplay]);
172
+ // InlineCitation shows keySpan by default
173
+ const displayText = useMemo(() => getCitationDisplayText(citation, { fallbackDisplay }), [citation, fallbackDisplay]);
184
174
  const handleClick = useCallback((e) => {
185
175
  e.preventDefault();
186
176
  e.stopPropagation();
@@ -194,16 +184,21 @@ fallbackDisplay, verification, eventHandlers, preventTooltips = false, pendingCo
194
184
  }, [eventHandlers, citation, citationKey]);
195
185
  // Check partial first since isVerified is true when isPartialMatch is true
196
186
  const statusClass = isPartialMatch
197
- ? "citation-inline--partial"
187
+ ? "text-amber-600 dark:text-amber-500"
198
188
  : isMiss
199
- ? "citation-inline--miss"
189
+ ? "text-red-500 dark:text-red-400 line-through"
200
190
  : isVerified
201
- ? "citation-inline--verified"
191
+ ? "text-green-600 dark:text-green-500"
202
192
  : isPending
203
- ? "citation-inline--pending"
193
+ ? "text-gray-400 dark:text-gray-500"
204
194
  : "";
205
- const underlineClass = `citation-inline--underline-${underlineStyle}`;
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 }))] })] }));
195
+ const underlineClasses = {
196
+ solid: "border-b border-current",
197
+ dotted: "border-b border-dotted border-current",
198
+ dashed: "border-b border-dashed border-current",
199
+ none: "",
200
+ };
201
+ return (_jsxs(_Fragment, { children: [children, _jsxs("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "inline", className: classNames("cursor-pointer transition-colors hover:bg-blue-500/5", underlineClasses[underlineStyle], 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: "opacity-70 ml-1", children: pendingContent }))] })] }));
207
202
  });
208
203
  InlineCitation.displayName = "InlineCitation";
209
204
  /**
@@ -216,13 +211,11 @@ InlineCitation.displayName = "InlineCitation";
216
211
  * // Renders: 1
217
212
  * ```
218
213
  */
219
- export const MinimalCitation = forwardRef(({ citation, children, className, hideKeySpan = false, fallbackDisplay, verification, eventHandlers, preventTooltips = false, pendingContent = TWO_DOTS_THINKING_CONTENT, renderVerifiedIndicator = () => _jsx(DefaultVerifiedIndicator, {}), renderPartialIndicator = () => _jsx(DefaultPartialIndicator, {}), showStatusIndicator = true, }, ref) => {
214
+ export const MinimalCitation = forwardRef(({ citation, children, className, fallbackDisplay, verification, eventHandlers, preventTooltips = false, pendingContent = TWO_DOTS_THINKING_CONTENT, renderVerifiedIndicator = () => _jsx(DefaultVerifiedIndicator, {}), renderPartialIndicator = () => _jsx(DefaultPartialIndicator, {}), showStatusIndicator = true, }, ref) => {
220
215
  const { citationKey, citationInstanceId, status } = useCitationData(citation, verification);
221
216
  const { isVerified, isMiss, isPartialMatch, isPending } = status;
222
- const displayText = useMemo(() => getCitationDisplayText(citation, {
223
- hideKeySpan,
224
- fallbackDisplay,
225
- }), [citation, hideKeySpan, fallbackDisplay]);
217
+ // MinimalCitation shows number by default
218
+ const displayText = useMemo(() => getCitationNumber(citation), [citation]);
226
219
  const handleClick = useCallback((e) => {
227
220
  e.preventDefault();
228
221
  e.stopPropagation();
@@ -236,15 +229,15 @@ export const MinimalCitation = forwardRef(({ citation, children, className, hide
236
229
  }, [eventHandlers, citation, citationKey]);
237
230
  // Check partial first since isVerified is true when isPartialMatch is true
238
231
  const statusClass = isPartialMatch
239
- ? "citation-minimal--partial"
232
+ ? "text-amber-600 dark:text-amber-500"
240
233
  : isMiss
241
- ? "citation-minimal--miss"
234
+ ? "text-red-500 dark:text-red-400 line-through"
242
235
  : isVerified
243
- ? "citation-minimal--verified"
236
+ ? "text-green-600 dark:text-green-500"
244
237
  : isPending
245
- ? "citation-minimal--pending"
246
- : "";
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] }))] })] }));
238
+ ? "text-gray-400 dark:text-gray-500"
239
+ : "text-blue-600 dark:text-blue-400";
240
+ return (_jsxs(_Fragment, { children: [children, _jsxs("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-variant": "minimal", className: classNames("cursor-pointer transition-colors hover:underline", 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] }))] })] }));
248
241
  });
249
242
  MinimalCitation.displayName = "MinimalCitation";
250
243
  /**
@@ -39,19 +39,19 @@ function getUrlPath(url) {
39
39
  * Status indicator icons for URL fetch states.
40
40
  */
41
41
  const STATUS_ICONS = {
42
- verified: { icon: "✓", label: "Verified", className: "url-citation--verified" },
43
- partial: { icon: "~", label: "Partial match", className: "url-citation--partial" },
44
- pending: { icon: "…", label: "Verifying", className: "url-citation--pending" },
45
- blocked_antibot: { icon: "🛡", label: "Blocked by anti-bot", className: "url-citation--blocked" },
46
- blocked_login: { icon: "🔒", label: "Login required", className: "url-citation--blocked" },
47
- blocked_paywall: { icon: "💳", label: "Paywall", className: "url-citation--blocked" },
48
- blocked_geo: { icon: "🌍", label: "Geo-restricted", className: "url-citation--blocked" },
49
- blocked_rate_limit: { icon: "⏱", label: "Rate limited", className: "url-citation--blocked" },
50
- error_timeout: { icon: "⏰", label: "Timed out", className: "url-citation--error" },
51
- error_not_found: { icon: "404", label: "Not found", className: "url-citation--error" },
52
- error_server: { icon: "⚠", label: "Server error", className: "url-citation--error" },
53
- error_network: { icon: "⚡", label: "Network error", className: "url-citation--error" },
54
- unknown: { icon: "?", label: "Unknown status", className: "url-citation--unknown" },
42
+ verified: { icon: "✓", label: "Verified", className: "text-green-600 dark:text-green-500" },
43
+ partial: { icon: "~", label: "Partial match", className: "text-amber-600 dark:text-amber-500" },
44
+ pending: { icon: "…", label: "Verifying", className: "text-gray-400 dark:text-gray-500" },
45
+ blocked_antibot: { icon: "🛡", label: "Blocked by anti-bot", className: "text-amber-600 dark:text-amber-500" },
46
+ blocked_login: { icon: "🔒", label: "Login required", className: "text-amber-600 dark:text-amber-500" },
47
+ blocked_paywall: { icon: "💳", label: "Paywall", className: "text-amber-600 dark:text-amber-500" },
48
+ blocked_geo: { icon: "🌍", label: "Geo-restricted", className: "text-amber-600 dark:text-amber-500" },
49
+ blocked_rate_limit: { icon: "⏱", label: "Rate limited", className: "text-amber-600 dark:text-amber-500" },
50
+ error_timeout: { icon: "⏰", label: "Timed out", className: "text-red-500 dark:text-red-400" },
51
+ error_not_found: { icon: "404", label: "Not found", className: "text-red-500 dark:text-red-400" },
52
+ error_server: { icon: "⚠", label: "Server error", className: "text-red-500 dark:text-red-400" },
53
+ error_network: { icon: "⚡", label: "Network error", className: "text-red-500 dark:text-red-400" },
54
+ unknown: { icon: "?", label: "Unknown status", className: "text-gray-400 dark:text-gray-500" },
55
55
  };
56
56
  /**
57
57
  * Checks if status is a blocked status.
@@ -76,7 +76,7 @@ export function isVerifiedStatus(status) {
76
76
  */
77
77
  const DefaultBlockedIndicator = ({ status, errorMessage }) => {
78
78
  const statusInfo = STATUS_ICONS[status];
79
- return (_jsx("span", { className: classNames("url-citation__blocked-indicator", statusInfo.className), title: errorMessage || statusInfo.label, "aria-label": statusInfo.label, children: _jsx("span", { className: "url-citation__blocked-icon", "aria-hidden": "true", children: statusInfo.icon }) }));
79
+ return (_jsx("span", { className: classNames("inline-flex items-center gap-1", statusInfo.className), title: errorMessage || statusInfo.label, "aria-label": statusInfo.label, children: _jsx("span", { className: "text-[0.9em]", "aria-hidden": "true", children: statusInfo.icon }) }));
80
80
  };
81
81
  /**
82
82
  * Default favicon component.
@@ -84,7 +84,7 @@ const DefaultBlockedIndicator = ({ status, errorMessage }) => {
84
84
  const DefaultFavicon = ({ url, faviconUrl }) => {
85
85
  const domain = extractDomain(url);
86
86
  const src = faviconUrl || `https://www.google.com/s2/favicons?domain=${domain}&sz=16`;
87
- return (_jsx("img", { src: src, alt: "", className: "url-citation__favicon", width: 14, height: 14, loading: "lazy", onError: e => {
87
+ return (_jsx("img", { src: src, alt: "", className: "w-3.5 h-3.5 rounded-sm", width: 14, height: 14, loading: "lazy", onError: e => {
88
88
  // Hide broken favicon images
89
89
  e.target.style.display = "none";
90
90
  } }));
@@ -167,29 +167,29 @@ showFullUrlOnHover = true, showFavicon = true, showTitle = false, maxDisplayLeng
167
167
  return _jsx(DefaultBlockedIndicator, { status: fetchStatus, errorMessage: errorMessage });
168
168
  }
169
169
  if (isVerified) {
170
- return (_jsx("span", { className: "url-citation__verified-icon", "aria-hidden": "true", title: "Verified", children: "\u2713" }));
170
+ return (_jsx("span", { className: "text-[0.85em] text-green-600 dark:text-green-500", "aria-hidden": "true", title: "Verified", children: "\u2713" }));
171
171
  }
172
172
  if (isPartial) {
173
- return (_jsx("span", { className: "url-citation__partial-icon", "aria-hidden": "true", title: "Partial match", children: "~" }));
173
+ return (_jsx("span", { className: "text-[0.85em] text-amber-600 dark:text-amber-500", "aria-hidden": "true", title: "Partial match", children: "~" }));
174
174
  }
175
175
  if (isPending) {
176
- return (_jsx("span", { className: "url-citation__pending", "aria-hidden": "true", children: "\u2026" }));
176
+ return (_jsx("span", { className: "opacity-70", "aria-hidden": "true", children: "\u2026" }));
177
177
  }
178
178
  return null;
179
179
  };
180
180
  // Choose variant-specific rendering
181
181
  if (variant === "chip") {
182
- return (_jsxs(_Fragment, { children: [children, _jsxs("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-url": url, "data-fetch-status": fetchStatus, className: classNames("url-citation", "url-citation--chip", statusInfo.className, className), title: showFullUrlOnHover ? url : undefined, onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: e => e.stopPropagation(), role: "link", "aria-label": `Link to ${domain}: ${statusInfo.label}`, children: [showFavicon && _jsx(DefaultFavicon, { url: url, faviconUrl: faviconUrl }), _jsx("span", { className: "url-citation__domain", children: displayText }), renderStatusIndicator()] })] }));
182
+ return (_jsxs(_Fragment, { children: [children, _jsxs("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-url": url, "data-fetch-status": fetchStatus, "data-variant": "chip", className: classNames("inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-sm cursor-pointer transition-colors no-underline", "bg-blue-100 dark:bg-blue-900/30", statusInfo.className, className), title: showFullUrlOnHover ? url : undefined, onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: e => e.stopPropagation(), role: "link", "aria-label": `Link to ${domain}: ${statusInfo.label}`, children: [showFavicon && _jsx(DefaultFavicon, { url: url, faviconUrl: faviconUrl }), _jsx("span", { className: "max-w-[200px] overflow-hidden text-ellipsis whitespace-nowrap", children: displayText }), renderStatusIndicator()] })] }));
183
183
  }
184
184
  // Inline variant
185
185
  if (variant === "inline") {
186
- return (_jsxs(_Fragment, { children: [children, _jsxs("a", { ref: ref, href: url, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-fetch-status": fetchStatus, className: classNames("url-citation", "url-citation--inline", statusInfo.className, className), title: showFullUrlOnHover ? url : undefined, onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onClick: e => {
186
+ return (_jsxs(_Fragment, { children: [children, _jsxs("a", { ref: ref, href: url, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-fetch-status": fetchStatus, "data-variant": "inline", className: classNames("inline-flex items-center gap-1 cursor-pointer transition-colors no-underline border-b border-dotted border-current", statusInfo.className, className), title: showFullUrlOnHover ? url : undefined, onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onClick: e => {
187
187
  e.preventDefault();
188
188
  handleClick(e);
189
- }, target: "_blank", rel: "noopener noreferrer", "aria-label": `Link to ${domain}: ${statusInfo.label}`, children: [showFavicon && _jsx(DefaultFavicon, { url: url, faviconUrl: faviconUrl }), _jsx("span", { className: "url-citation__text", children: displayText }), renderStatusIndicator()] })] }));
189
+ }, target: "_blank", rel: "noopener noreferrer", "aria-label": `Link to ${domain}: ${statusInfo.label}`, children: [showFavicon && _jsx(DefaultFavicon, { url: url, faviconUrl: faviconUrl }), _jsx("span", { children: displayText }), renderStatusIndicator()] })] }));
190
190
  }
191
191
  // Bracket variant (default for non-URL citations)
192
- return (_jsxs(_Fragment, { children: [children, _jsxs("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-url": url, "data-fetch-status": fetchStatus, className: classNames("url-citation", "url-citation--bracket", statusInfo.className, className), title: showFullUrlOnHover ? url : undefined, onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: e => e.stopPropagation(), role: "link", "aria-label": `Link to ${domain}: ${statusInfo.label}`, children: ["[", showFavicon && _jsx(DefaultFavicon, { url: url, faviconUrl: faviconUrl }), _jsx("span", { className: "url-citation__domain", children: displayText }), renderStatusIndicator(), "]"] })] }));
192
+ return (_jsxs(_Fragment, { children: [children, _jsxs("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, "data-url": url, "data-fetch-status": fetchStatus, "data-variant": "bracket", className: classNames("cursor-pointer transition-colors", statusInfo.className, className), title: showFullUrlOnHover ? url : undefined, onMouseEnter: preventTooltips ? undefined : handleMouseEnter, onMouseLeave: preventTooltips ? undefined : handleMouseLeave, onMouseDown: handleClick, onClick: e => e.stopPropagation(), role: "link", "aria-label": `Link to ${domain}: ${statusInfo.label}`, children: ["[", showFavicon && _jsx(DefaultFavicon, { url: url, faviconUrl: faviconUrl }), _jsx("span", { className: "max-w-[200px] overflow-hidden text-ellipsis whitespace-nowrap", children: displayText }), renderStatusIndicator(), "]"] })] }));
193
193
  });
194
194
  UrlCitationComponent.displayName = "UrlCitationComponent";
195
195
  /**
@@ -1,11 +1,21 @@
1
+ /**
2
+ * DeepCitation icon SVG (no dependencies)
3
+ */
4
+ export declare const DeepCitationIcon: ({ className }: {
5
+ className?: string;
6
+ }) => import("react/jsx-runtime").JSX.Element;
1
7
  /**
2
8
  * Check icon SVG (no dependencies)
3
9
  */
4
- export declare const CheckIcon: () => import("react/jsx-runtime").JSX.Element;
10
+ export declare const CheckIcon: ({ className }: {
11
+ className?: string;
12
+ }) => import("react/jsx-runtime").JSX.Element;
5
13
  /**
6
14
  * Warning icon SVG (no dependencies)
7
15
  */
8
- export declare const WarningIcon: () => import("react/jsx-runtime").JSX.Element;
16
+ export declare const WarningIcon: ({ className }: {
17
+ className?: string;
18
+ }) => import("react/jsx-runtime").JSX.Element;
9
19
  /** Spinner component for loading/pending state */
10
20
  export declare const SpinnerIcon: ({ className }: {
11
21
  className?: string;
@@ -1,12 +1,16 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn } from "./utils.js";
3
+ /**
4
+ * DeepCitation icon SVG (no dependencies)
5
+ */
6
+ export const DeepCitationIcon = ({ className }) => (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "square", shapeRendering: "crispEdges", className: className, children: [_jsx("path", { d: "M7 3 L3 3 L3 21 L7 21" }), _jsx("path", { d: "M17 3 L21 3 L21 21 L17 21" })] }));
3
7
  /**
4
8
  * Check icon SVG (no dependencies)
5
9
  */
6
- 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" }) }));
10
+ export const CheckIcon = ({ className }) => (_jsx("svg", { className: cn("w-[0.7em] h-[0.7em]", className), 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" }) }));
7
11
  /**
8
12
  * Warning icon SVG (no dependencies)
9
13
  */
10
- 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" }) }));
14
+ export const WarningIcon = ({ className }) => (_jsx("svg", { className: cn("w-[0.7em] h-[0.7em]", className), 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" }) }));
11
15
  /** Spinner component for loading/pending state */
12
- export const SpinnerIcon = ({ className }) => (_jsxs("svg", { className: cn("animate-spin", className), xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", width: "12", height: "12", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }));
16
+ export const SpinnerIcon = ({ className }) => (_jsxs("svg", { className: cn("w-[0.7em] h-[0.7em] animate-spin", className), xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }));
@@ -10,7 +10,8 @@
10
10
  *
11
11
  * @packageDocumentation
12
12
  */
13
- export type { CitationContentProps, CitationRenderProps, CitationTooltipProps, CitationStyles, CitationStateClasses, CitationCursorClasses, CitationEventHandlers, CitationVariant as CitationVariantType, UrlFetchStatus, UrlCitationMeta, UrlCitationProps, CitationBehaviorConfig, CitationBehaviorContext, CitationBehaviorActions, CitationClickBehavior, CitationHoverBehavior, } from "./types.js";
13
+ export type { CitationContentProps, CitationRenderProps, CitationTooltipProps, CitationStyles, CitationStateClasses, CitationCursorClasses, CitationEventHandlers, CitationVariant as CitationVariantType, CitationContent, UrlFetchStatus, UrlCitationMeta, UrlCitationProps, UrlCitationVariant, CitationBehaviorConfig, CitationBehaviorContext, CitationBehaviorActions, CitationClickBehavior, CitationHoverBehavior, } from "./types.js";
14
14
  export { extractDomain, isBlockedStatus, isErrorStatus, isVerifiedStatus, } from "./UrlCitationComponent.js";
15
- export { generateCitationKey, generateCitationInstanceId, getCitationDisplayText, getCitationKeySpanText, classNames, CITATION_X_PADDING, CITATION_Y_PADDING, } from "./utils.js";
15
+ export { generateCitationKey, generateCitationInstanceId, getCitationDisplayText, getCitationNumber, getCitationKeySpanText, classNames, CITATION_X_PADDING, CITATION_Y_PADDING, } from "./utils.js";
16
16
  export { CitationComponent, MemoizedCitationComponent, type CitationVariant, type CitationComponentProps, } from "./CitationComponent.js";
17
+ export { DeepCitationIcon, CheckIcon, SpinnerIcon, WarningIcon, } from "./icons.js";
@@ -13,6 +13,8 @@
13
13
  // URL Utilities - For handling URL citation metadata
14
14
  export { extractDomain, isBlockedStatus, isErrorStatus, isVerifiedStatus, } from "./UrlCitationComponent.js";
15
15
  // Utilities - For generating citation keys and display text
16
- export { generateCitationKey, generateCitationInstanceId, getCitationDisplayText, getCitationKeySpanText, classNames, CITATION_X_PADDING, CITATION_Y_PADDING, } from "./utils.js";
16
+ export { generateCitationKey, generateCitationInstanceId, getCitationDisplayText, getCitationNumber, getCitationKeySpanText, classNames, CITATION_X_PADDING, CITATION_Y_PADDING, } from "./utils.js";
17
17
  // Components
18
18
  export { CitationComponent, MemoizedCitationComponent, } from "./CitationComponent.js";
19
+ // Icons
20
+ export { DeepCitationIcon, CheckIcon, SpinnerIcon, WarningIcon, } from "./icons.js";
@@ -12,7 +12,6 @@ interface CitationContextValue {
12
12
  status: CitationStatus;
13
13
  verification: Verification | null;
14
14
  config: {
15
- hideKeySpan: boolean;
16
15
  fallbackDisplay: string | null;
17
16
  pendingContent: ReactNode;
18
17
  };
@@ -25,7 +24,6 @@ export interface CitationRootProps {
25
24
  citation: CitationType;
26
25
  verification?: Verification | null;
27
26
  children: ReactNode;
28
- hideKeySpan?: boolean;
29
27
  fallbackDisplay?: string | null;
30
28
  pendingContent?: ReactNode;
31
29
  }
@@ -20,7 +20,7 @@ export function useCitationContextSafe() {
20
20
  return useContext(CitationContext);
21
21
  }
22
22
  /** Root component that provides citation context to all child primitives. */
23
- export const CitationRoot = forwardRef(({ citation, verification = null, children, hideKeySpan = false, fallbackDisplay = null, pendingContent = "..", className, ...props }, ref) => {
23
+ export const CitationRoot = forwardRef(({ citation, verification = null, children, fallbackDisplay = null, pendingContent = "..", className, ...props }, ref) => {
24
24
  const citationKey = useMemo(() => generateCitationKey(citation), [citation]);
25
25
  const citationInstanceId = useMemo(() => generateCitationInstanceId(citationKey), [citationKey]);
26
26
  const status = getCitationStatus(verification);
@@ -31,7 +31,6 @@ export const CitationRoot = forwardRef(({ citation, verification = null, childre
31
31
  status,
32
32
  verification,
33
33
  config: {
34
- hideKeySpan,
35
34
  fallbackDisplay,
36
35
  pendingContent,
37
36
  },
@@ -41,11 +40,10 @@ export const CitationRoot = forwardRef(({ citation, verification = null, childre
41
40
  citationInstanceId,
42
41
  status,
43
42
  verification,
44
- hideKeySpan,
45
43
  fallbackDisplay,
46
44
  pendingContent,
47
45
  ]);
48
- 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 }) }));
46
+ return (_jsx(CitationContext.Provider, { value: contextValue, children: _jsx("span", { ref: ref, "data-citation-id": citationKey, "data-citation-instance": citationInstanceId, className: classNames("inline", className), ...props, children: children }) }));
49
47
  });
50
48
  CitationRoot.displayName = "Citation.Root";
51
49
  /** Interactive trigger component for the citation. */
@@ -83,13 +81,13 @@ export const CitationTrigger = forwardRef(({ children, className, onCitationClic
83
81
  }, [onTouchEnd, isMobile, onCitationTouchEnd, citation, citationKey]);
84
82
  const statusClasses = classNames(status.isVerified &&
85
83
  !status.isPartialMatch &&
86
- "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 }));
84
+ "text-green-600 dark:text-green-500", status.isPartialMatch && "text-amber-600 dark:text-amber-500", status.isMiss && "text-red-500 dark:text-red-400 line-through", status.isPending && "text-gray-400 dark:text-gray-500");
85
+ return (_jsx("span", { ref: ref, role: "button", tabIndex: 0, className: classNames("cursor-pointer transition-colors focus-visible:outline-2 focus-visible:outline-blue-500 focus-visible:outline-offset-2 focus-visible:rounded-sm", statusClasses, className), onClick: handleClick, onMouseDown: handleMouseDown, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onTouchEndCapture: isMobile ? handleTouchEnd : undefined, ...props, children: children }));
88
86
  });
89
87
  CitationTrigger.displayName = "Citation.Trigger";
90
88
  /** Bracket wrapper component for citation content. */
91
89
  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 })] }));
90
+ return (_jsxs("span", { ref: ref, className: classNames("inline", className), "aria-hidden": "true", ...props, children: [_jsx("span", { className: "inline", children: open }), _jsx("span", { className: "inline", children: children }), _jsx("span", { className: "inline", children: close })] }));
93
91
  });
94
92
  CitationBracket.displayName = "Citation.Bracket";
95
93
  /** Displays the citation number. */
@@ -98,33 +96,28 @@ export const CitationNumber = forwardRef(({ className, number, ...props }, ref)
98
96
  const displayNumber = useMemo(() => {
99
97
  if (number !== undefined)
100
98
  return String(number);
101
- if (!config.hideKeySpan) {
102
- return (citation.keySpan?.toString() ||
103
- citation.citationNumber?.toString() ||
104
- config.fallbackDisplay ||
105
- "");
106
- }
107
- return citation.citationNumber?.toString() || "";
99
+ return (citation.keySpan?.toString() ||
100
+ citation.citationNumber?.toString() ||
101
+ config.fallbackDisplay ||
102
+ "1");
108
103
  }, [number, citation, config]);
109
104
  if (status.isPending) {
110
- return (_jsx("span", { ref: ref, className: classNames("citation-number citation-number--pending", className), ...props, children: config.pendingContent }));
105
+ return (_jsx("span", { ref: ref, className: classNames("font-medium opacity-60", className), ...props, children: config.pendingContent }));
111
106
  }
112
- return (_jsx("span", { ref: ref, className: classNames("citation-number", className), ...props, children: displayNumber }));
107
+ return (_jsx("span", { ref: ref, className: classNames("font-medium", className), ...props, children: displayNumber }));
113
108
  });
114
109
  CitationNumber.displayName = "Citation.Number";
115
110
  /** Displays the citation keySpan (summary text). */
116
111
  export const CitationKeySpan = forwardRef(({ className, keySpan, separator = " ", ...props }, ref) => {
117
- const { citation, config } = useCitationContext();
112
+ const { citation } = useCitationContext();
118
113
  const displayKeySpan = useMemo(() => {
119
114
  if (keySpan !== undefined)
120
115
  return keySpan;
121
- if (config.hideKeySpan)
122
- return "";
123
116
  return citation.keySpan?.toString() || "";
124
- }, [keySpan, citation, config]);
117
+ }, [keySpan, citation]);
125
118
  if (!displayKeySpan)
126
119
  return null;
127
- return (_jsxs("span", { ref: ref, className: classNames("citation-key-span", className), ...props, children: [displayKeySpan, separator] }));
120
+ return (_jsxs("span", { ref: ref, className: classNames("italic", className), ...props, children: [displayKeySpan, separator] }));
128
121
  });
129
122
  CitationKeySpan.displayName = "Citation.KeySpan";
130
123
  /** Displays a status indicator based on citation verification state. */
@@ -135,17 +128,18 @@ export const CitationIndicator = forwardRef(({ className, verifiedIndicator = "
135
128
  return true;
136
129
  return showFor.includes(state);
137
130
  }, [showFor]);
131
+ const baseClasses = "inline ml-0.5 text-[0.85em]";
138
132
  if (status.isPartialMatch && shouldShow("partial")) {
139
- return (_jsx("span", { ref: ref, className: classNames("citation-indicator citation-indicator--partial", className), "aria-label": "Partial match", ...props, children: partialIndicator }));
133
+ return (_jsx("span", { ref: ref, className: classNames(baseClasses, "text-amber-600 dark:text-amber-500", className), "aria-label": "Partial match", ...props, children: partialIndicator }));
140
134
  }
141
135
  if (status.isVerified && !status.isPartialMatch && shouldShow("verified")) {
142
- return (_jsx("span", { ref: ref, className: classNames("citation-indicator citation-indicator--verified", className), "aria-label": "Verified", ...props, children: verifiedIndicator }));
136
+ return (_jsx("span", { ref: ref, className: classNames(baseClasses, "text-green-600 dark:text-green-500", className), "aria-label": "Verified", ...props, children: verifiedIndicator }));
143
137
  }
144
138
  if (status.isMiss && shouldShow("miss") && missIndicator) {
145
- return (_jsx("span", { ref: ref, className: classNames("citation-indicator citation-indicator--miss", className), "aria-label": "Not found", ...props, children: missIndicator }));
139
+ return (_jsx("span", { ref: ref, className: classNames(baseClasses, "text-red-500 dark:text-red-400", className), "aria-label": "Not found", ...props, children: missIndicator }));
146
140
  }
147
141
  if (status.isPending && shouldShow("pending") && pendingIndicator) {
148
- return (_jsx("span", { ref: ref, className: classNames("citation-indicator citation-indicator--pending", className), "aria-label": "Pending", ...props, children: pendingIndicator }));
142
+ return (_jsx("span", { ref: ref, className: classNames(baseClasses, "text-gray-400 dark:text-gray-500", className), "aria-label": "Pending", ...props, children: pendingIndicator }));
149
143
  }
150
144
  return null;
151
145
  });
@@ -167,7 +161,7 @@ export const CitationPhrase = forwardRef(({ className, maxLength, truncationSuff
167
161
  }, [citation.fullPhrase, maxLength, truncationSuffix]);
168
162
  if (!displayPhrase)
169
163
  return null;
170
- return (_jsx("span", { ref: ref, className: classNames("citation-phrase", className), ...props, children: displayPhrase }));
164
+ return (_jsx("span", { ref: ref, className: classNames("italic", className), ...props, children: displayPhrase }));
171
165
  });
172
166
  CitationPhrase.displayName = "Citation.Phrase";
173
167
  /** Displays the citation's page number. */
@@ -176,7 +170,7 @@ export const CitationPage = forwardRef(({ className, prefix = "", ...props }, re
176
170
  if (citation.pageNumber === undefined || citation.pageNumber === null) {
177
171
  return null;
178
172
  }
179
- return (_jsxs("span", { ref: ref, className: classNames("citation-page", className), ...props, children: [prefix, citation.pageNumber] }));
173
+ return (_jsxs("span", { ref: ref, className: classNames("text-xs text-gray-400 dark:text-gray-500", className), ...props, children: [prefix, citation.pageNumber] }));
180
174
  });
181
175
  CitationPage.displayName = "Citation.Page";
182
176
  /** Citation primitives namespace for composable citation components. */
@@ -2,16 +2,34 @@ import type { Citation, CitationStatus } from "../types/citation.js";
2
2
  import type { Verification } from "../types/verification.js";
3
3
  import type { SearchStatus } from "../types/search.js";
4
4
  /**
5
- * Available citation display variants.
5
+ * Visual style variants for citations.
6
6
  *
7
- * - `brackets`: Shows keySpan/number in brackets with blue text styling (default).
8
- * Use hideKeySpan=true for numeric-only display.
9
- * Use hideBrackets=true to hide the square brackets.
10
- * - `text`: Shows the keySpan, inherits parent text styling, no truncation, shows indicator
11
- * - `minimal`: No brackets, just display text with indicator
12
- * - `indicator`: Only the status indicator (checkmark/warning), no text
7
+ * | Variant | Description |
8
+ * |---------------|------------------------------------------------|
9
+ * | `chip` | Pill/badge style with background color |
10
+ * | `brackets` | [text✓] with square brackets (default) |
11
+ * | `text` | Plain text, inherits parent styling |
12
+ * | `superscript` | Small raised text like footnotes¹ |
13
+ * | `minimal` | Compact text with indicator, truncated |
13
14
  */
14
- export type CitationVariant = "brackets" | "text" | "minimal" | "indicator";
15
+ export type CitationVariant = "chip" | "brackets" | "text" | "superscript" | "minimal";
16
+ /**
17
+ * Content to display in the citation.
18
+ *
19
+ * | Content | Description |
20
+ * |---------------|------------------------------------------------|
21
+ * | `keySpan` | Descriptive text (e.g., "Revenue Growth") |
22
+ * | `number` | Citation number (e.g., "1", "2", "3") |
23
+ * | `indicator` | Only the status icon (✓/⚠), no text |
24
+ *
25
+ * Default content per variant:
26
+ * - `chip` → `keySpan`
27
+ * - `brackets` → `number`
28
+ * - `text` → `keySpan`
29
+ * - `superscript` → `number`
30
+ * - `minimal` → `number`
31
+ */
32
+ export type CitationContent = "keySpan" | "number" | "indicator";
15
33
  /**
16
34
  * URL fetch status for URL citations.
17
35
  */
@@ -91,19 +109,33 @@ export interface BaseCitationProps {
91
109
  /** Class name for controlling inner content width */
92
110
  innerWidthClassName?: string;
93
111
  /**
94
- * When true, hides keySpan and displays citation number only. When false, displays keySpan text.
95
- * @default false
112
+ * Visual style variant for the citation.
113
+ * @default "brackets"
114
+ */
115
+ variant?: CitationVariant;
116
+ /**
117
+ * What content to display in the citation.
118
+ * If not specified, defaults based on variant:
119
+ * - `chip` → `keySpan`
120
+ * - `brackets` → `number`
121
+ * - `text` → `keySpan`
122
+ * - `superscript` → `number`
123
+ * - `minimal` → `number`
96
124
  */
97
- hideKeySpan?: boolean;
125
+ content?: CitationContent;
98
126
  /** Fallback display text when citation keySpan is empty */
99
127
  fallbackDisplay?: string | null;
100
- /** Display variant for the citation */
101
- variant?: CitationVariant;
102
128
  }
129
+ /**
130
+ * Visual style variants for URL citations.
131
+ */
132
+ export type UrlCitationVariant = "chip" | "inline" | "bracket";
103
133
  /**
104
134
  * Props for URL citation component
105
135
  */
106
- export interface UrlCitationProps extends Omit<BaseCitationProps, "citation"> {
136
+ export interface UrlCitationProps extends Omit<BaseCitationProps, "citation" | "variant"> {
137
+ /** Visual style variant for the URL citation */
138
+ variant?: UrlCitationVariant;
107
139
  /** URL metadata including fetch status */
108
140
  urlMeta: UrlCitationMeta;
109
141
  /** The citation data (optional, will be derived from urlMeta if not provided) */
@@ -19,18 +19,19 @@ export declare function generateVerificationKey(verification: Verification): str
19
19
  */
20
20
  export declare function generateCitationInstanceId(citationKey: string): string;
21
21
  /**
22
- * Gets the display text for a citation based on configuration.
22
+ * Gets the display text for a citation (keySpan with fallback to number).
23
23
  */
24
24
  export declare function getCitationDisplayText(citation: Citation, options?: {
25
- hideKeySpan?: boolean;
26
25
  fallbackDisplay?: string | null;
27
26
  }): string;
28
27
  /**
29
- * Gets the keySpan text to display before the citation bracket.
28
+ * Gets the citation number as a string.
30
29
  */
31
- export declare function getCitationKeySpanText(citation: Citation, options?: {
32
- hideKeySpan?: boolean;
33
- }): string;
30
+ export declare function getCitationNumber(citation: Citation): string;
31
+ /**
32
+ * Gets the keySpan text from a citation.
33
+ */
34
+ export declare function getCitationKeySpanText(citation: Citation): string;
34
35
  /**
35
36
  * Joins class names, filtering out falsy values.
36
37
  * This is a minimal implementation for the base component.
@@ -53,26 +53,25 @@ export function generateCitationInstanceId(citationKey) {
53
53
  return `${citationKey}-${randomSuffix}`;
54
54
  }
55
55
  /**
56
- * Gets the display text for a citation based on configuration.
56
+ * Gets the display text for a citation (keySpan with fallback to number).
57
57
  */
58
58
  export function getCitationDisplayText(citation, options = {}) {
59
- const { hideKeySpan = false, fallbackDisplay } = options;
60
- if (!hideKeySpan) {
61
- return (citation.keySpan?.toString() ||
62
- citation.citationNumber?.toString() ||
63
- fallbackDisplay ||
64
- "");
65
- }
66
- return citation.citationNumber?.toString() || "";
59
+ const { fallbackDisplay } = options;
60
+ return (citation.keySpan?.toString() ||
61
+ citation.citationNumber?.toString() ||
62
+ fallbackDisplay ||
63
+ "1");
67
64
  }
68
65
  /**
69
- * Gets the keySpan text to display before the citation bracket.
66
+ * Gets the citation number as a string.
70
67
  */
71
- export function getCitationKeySpanText(citation, options = {}) {
72
- const { hideKeySpan = false } = options;
73
- if (!hideKeySpan) {
74
- return "";
75
- }
68
+ export function getCitationNumber(citation) {
69
+ return citation.citationNumber?.toString() || "1";
70
+ }
71
+ /**
72
+ * Gets the keySpan text from a citation.
73
+ */
74
+ export function getCitationKeySpanText(citation) {
76
75
  return citation.keySpan?.toString() || "";
77
76
  }
78
77
  /**
package/package.json CHANGED
@@ -1,15 +1,18 @@
1
1
  {
2
2
  "name": "@deepcitation/deepcitation-js",
3
- "version": "1.1.25",
3
+ "version": "1.1.27",
4
4
  "description": "DeepCitation JavaScript SDK for deterministic AI citation verification",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "license": "MIT",
8
8
  "author": "DeepCitation <opensource@deepcitation.com>",
9
+ "homepage": "https://deepcitation.com",
10
+ "bugs": {
11
+ "url": "https://github.com/deepcitation/deepcitation-js/issues"
12
+ },
9
13
  "repository": {
10
14
  "type": "git",
11
- "url": "git+https://github.com/deepcitation/deepcitation-js.git",
12
- "directory": "packages/deepcitation"
15
+ "url": "git+https://github.com/deepcitation/deepcitation-js.git"
13
16
  },
14
17
  "main": "./lib/index.js",
15
18
  "types": "./lib/index.d.ts",
@@ -76,10 +79,24 @@
76
79
  "import": "./lib/index.js",
77
80
  "require": "./lib/index.js"
78
81
  },
82
+ "./client": {
83
+ "types": "./lib/client/index.d.ts",
84
+ "import": "./lib/client/index.js",
85
+ "require": "./lib/client/index.js"
86
+ },
87
+ "./prompts": {
88
+ "types": "./lib/prompts/index.d.ts",
89
+ "import": "./lib/prompts/index.js",
90
+ "require": "./lib/prompts/index.js"
91
+ },
79
92
  "./react": {
80
93
  "types": "./lib/react/index.d.ts",
81
94
  "import": "./lib/react/index.js",
82
95
  "require": "./lib/react/index.js"
96
+ },
97
+ "./types": {
98
+ "types": "./lib/types/index.d.ts",
99
+ "import": "./lib/types/index.js"
83
100
  }
84
101
  },
85
102
  "keywords": [