@nucleux/citation 0.1.1
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/LICENSE +21 -0
- package/README.md +26 -0
- package/dist/index.cjs +109 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +43 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +85 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nucleux
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# @nucleux/citation
|
|
2
|
+
|
|
3
|
+
Citation — inline source chips and a grounded sources list for AI answers — Nucleux agentic UI for React.
|
|
4
|
+
|
|
5
|
+
Part of **[Nucleux](https://github.com/intelligaia-open-labs/nucleux)** — agentic UI components for React. Install a single component, or the full kit via [`@nucleux/react`](https://www.npmjs.com/package/@nucleux/react).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @nucleux/citation @nucleux/tokens
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`react` / `react-dom` are peer dependencies.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Citation } from "@nucleux/citation";
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Requires the theme once in your app: `import "@nucleux/tokens/styles.css";`
|
|
22
|
+
and the Tailwind preset from `@nucleux/tokens/preset`.
|
|
23
|
+
|
|
24
|
+
## License
|
|
25
|
+
|
|
26
|
+
MIT © Nucleux
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var utils = require('@nucleux/utils');
|
|
6
|
+
var lucideReact = require('lucide-react');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
|
|
9
|
+
function _interopNamespace(e) {
|
|
10
|
+
if (e && e.__esModule) return e;
|
|
11
|
+
var n = Object.create(null);
|
|
12
|
+
if (e) {
|
|
13
|
+
Object.keys(e).forEach(function (k) {
|
|
14
|
+
if (k !== 'default') {
|
|
15
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return e[k]; }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
n.default = e;
|
|
24
|
+
return Object.freeze(n);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
28
|
+
|
|
29
|
+
// src/index.tsx
|
|
30
|
+
var Citation = React__namespace.forwardRef(
|
|
31
|
+
({ index, label, className, children, type = "button", ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
32
|
+
"button",
|
|
33
|
+
{
|
|
34
|
+
ref,
|
|
35
|
+
type,
|
|
36
|
+
className: utils.cn(
|
|
37
|
+
"inline-flex h-5 min-w-5 items-center justify-center gap-1 rounded-full border border-border bg-muted px-1.5 align-middle text-[0.6875rem] font-medium leading-none text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
38
|
+
className
|
|
39
|
+
),
|
|
40
|
+
...props,
|
|
41
|
+
children: children ?? label ?? index
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
);
|
|
45
|
+
Citation.displayName = "Citation";
|
|
46
|
+
var SourceItem = React__namespace.forwardRef(
|
|
47
|
+
({ index, icon, title, meta, href, actionLabel = "Open", onOpen, className, ...props }, ref) => {
|
|
48
|
+
const action = href ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
49
|
+
"a",
|
|
50
|
+
{
|
|
51
|
+
href,
|
|
52
|
+
className: "inline-flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-info transition-colors hover:bg-info/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
53
|
+
children: [
|
|
54
|
+
actionLabel,
|
|
55
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "size-3.5", "aria-hidden": "true" })
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
59
|
+
"button",
|
|
60
|
+
{
|
|
61
|
+
type: "button",
|
|
62
|
+
onClick: onOpen,
|
|
63
|
+
className: "inline-flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-info transition-colors hover:bg-info/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
64
|
+
children: [
|
|
65
|
+
actionLabel,
|
|
66
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "size-3.5", "aria-hidden": "true" })
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
71
|
+
"li",
|
|
72
|
+
{
|
|
73
|
+
ref,
|
|
74
|
+
className: utils.cn("flex items-center gap-3 rounded-lg border border-border bg-background p-3", className),
|
|
75
|
+
...props,
|
|
76
|
+
children: [
|
|
77
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex size-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground", children: index != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold", children: index }) : icon ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-4", "aria-hidden": "true" }) }),
|
|
78
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
79
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-medium text-foreground", children: title }),
|
|
80
|
+
meta && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs text-muted-foreground", children: meta })
|
|
81
|
+
] }),
|
|
82
|
+
action
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
SourceItem.displayName = "SourceItem";
|
|
89
|
+
var SourceList = React__namespace.forwardRef(
|
|
90
|
+
({ heading, className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
91
|
+
"div",
|
|
92
|
+
{
|
|
93
|
+
ref,
|
|
94
|
+
className: utils.cn("flex flex-col gap-2 rounded-xl border border-border bg-muted/30 p-3", className),
|
|
95
|
+
...props,
|
|
96
|
+
children: [
|
|
97
|
+
heading && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-1 text-xs font-medium uppercase tracking-wide text-muted-foreground", children: heading }),
|
|
98
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-2", children })
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
);
|
|
103
|
+
SourceList.displayName = "SourceList";
|
|
104
|
+
|
|
105
|
+
exports.Citation = Citation;
|
|
106
|
+
exports.SourceItem = SourceItem;
|
|
107
|
+
exports.SourceList = SourceList;
|
|
108
|
+
//# sourceMappingURL=index.cjs.map
|
|
109
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"names":["React","jsx","cn","jsxs","ExternalLink","FileText"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@nucleux/utils\";\nimport { FileText, ExternalLink } from \"lucide-react\";\n\nexport interface CitationProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"title\"> {\n /** Source index shown in the chip, e.g. `4`. Ignored if `children` is given. */\n index?: number;\n /** Text label instead of a number, e.g. `\"wikipedia.com\"`. */\n label?: React.ReactNode;\n}\n\n/**\n * An inline citation chip embedded in an AI answer — a compact numbered or\n * domain marker that attributes a claim to a source.\n * Source: Figma \"Explainability / Inline source chip\".\n */\nexport const Citation = React.forwardRef<HTMLButtonElement, CitationProps>(\n ({ index, label, className, children, type = \"button\", ...props }, ref) => (\n <button\n ref={ref}\n type={type}\n className={cn(\n \"inline-flex h-5 min-w-5 items-center justify-center gap-1 rounded-full border border-border bg-muted px-1.5 align-middle text-[0.6875rem] font-medium leading-none text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n className,\n )}\n {...props}\n >\n {children ?? label ?? index}\n </button>\n ),\n);\nCitation.displayName = \"Citation\";\n\nexport interface SourceItemProps\n extends Omit<React.LiHTMLAttributes<HTMLLIElement>, \"title\"> {\n /** Optional leading index, e.g. `1`. */\n index?: number;\n /** Icon shown in the leading slot. Defaults to a document icon. */\n icon?: React.ReactNode;\n /** Source title, e.g. a filename. */\n title: React.ReactNode;\n /** Metadata line, e.g. `\"Source · PDF · Section 4.1\"`. */\n meta?: React.ReactNode;\n /** If set, the open affordance becomes a link to this href. */\n href?: string;\n /** Label for the open affordance. Defaults to `\"Open\"`. */\n actionLabel?: React.ReactNode;\n /** Called when the open affordance is activated (button mode). */\n onOpen?: () => void;\n}\n\n/** A single row in a {@link SourceList}: icon, title, metadata and an open action. */\nexport const SourceItem = React.forwardRef<HTMLLIElement, SourceItemProps>(\n ({ index, icon, title, meta, href, actionLabel = \"Open\", onOpen, className, ...props }, ref) => {\n const action = href ? (\n <a\n href={href}\n className=\"inline-flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-info transition-colors hover:bg-info/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {actionLabel}\n <ExternalLink className=\"size-3.5\" aria-hidden=\"true\" />\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"inline-flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-info transition-colors hover:bg-info/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {actionLabel}\n <ExternalLink className=\"size-3.5\" aria-hidden=\"true\" />\n </button>\n );\n return (\n <li\n ref={ref}\n className={cn(\"flex items-center gap-3 rounded-lg border border-border bg-background p-3\", className)}\n {...props}\n >\n <span className=\"inline-flex size-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground\">\n {index != null ? (\n <span className=\"text-xs font-semibold\">{index}</span>\n ) : (\n icon ?? <FileText className=\"size-4\" aria-hidden=\"true\" />\n )}\n </span>\n <span className=\"flex min-w-0 flex-1 flex-col\">\n <span className=\"truncate text-sm font-medium text-foreground\">{title}</span>\n {meta && <span className=\"truncate text-xs text-muted-foreground\">{meta}</span>}\n </span>\n {action}\n </li>\n );\n },\n);\nSourceItem.displayName = \"SourceItem\";\n\nexport interface SourceListProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Heading above the list, e.g. `\"3 sources · 1 missing policy\"`. */\n heading?: React.ReactNode;\n}\n\n/**\n * A grounded sources block: the knowledge sources an AI answer drew on, each an\n * openable {@link SourceItem}. Surfaces the retrieval set behind a response.\n */\nexport const SourceList = React.forwardRef<HTMLDivElement, SourceListProps>(\n ({ heading, className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"flex flex-col gap-2 rounded-xl border border-border bg-muted/30 p-3\", className)}\n {...props}\n >\n {heading && (\n <p className=\"px-1 text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {heading}\n </p>\n )}\n <ul className=\"flex flex-col gap-2\">{children}</ul>\n </div>\n ),\n);\nSourceList.displayName = \"SourceList\";\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface CitationProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "title"> {
|
|
4
|
+
/** Source index shown in the chip, e.g. `4`. Ignored if `children` is given. */
|
|
5
|
+
index?: number;
|
|
6
|
+
/** Text label instead of a number, e.g. `"wikipedia.com"`. */
|
|
7
|
+
label?: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* An inline citation chip embedded in an AI answer — a compact numbered or
|
|
11
|
+
* domain marker that attributes a claim to a source.
|
|
12
|
+
* Source: Figma "Explainability / Inline source chip".
|
|
13
|
+
*/
|
|
14
|
+
declare const Citation: React.ForwardRefExoticComponent<CitationProps & React.RefAttributes<HTMLButtonElement>>;
|
|
15
|
+
interface SourceItemProps extends Omit<React.LiHTMLAttributes<HTMLLIElement>, "title"> {
|
|
16
|
+
/** Optional leading index, e.g. `1`. */
|
|
17
|
+
index?: number;
|
|
18
|
+
/** Icon shown in the leading slot. Defaults to a document icon. */
|
|
19
|
+
icon?: React.ReactNode;
|
|
20
|
+
/** Source title, e.g. a filename. */
|
|
21
|
+
title: React.ReactNode;
|
|
22
|
+
/** Metadata line, e.g. `"Source · PDF · Section 4.1"`. */
|
|
23
|
+
meta?: React.ReactNode;
|
|
24
|
+
/** If set, the open affordance becomes a link to this href. */
|
|
25
|
+
href?: string;
|
|
26
|
+
/** Label for the open affordance. Defaults to `"Open"`. */
|
|
27
|
+
actionLabel?: React.ReactNode;
|
|
28
|
+
/** Called when the open affordance is activated (button mode). */
|
|
29
|
+
onOpen?: () => void;
|
|
30
|
+
}
|
|
31
|
+
/** A single row in a {@link SourceList}: icon, title, metadata and an open action. */
|
|
32
|
+
declare const SourceItem: React.ForwardRefExoticComponent<SourceItemProps & React.RefAttributes<HTMLLIElement>>;
|
|
33
|
+
interface SourceListProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
34
|
+
/** Heading above the list, e.g. `"3 sources · 1 missing policy"`. */
|
|
35
|
+
heading?: React.ReactNode;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A grounded sources block: the knowledge sources an AI answer drew on, each an
|
|
39
|
+
* openable {@link SourceItem}. Surfaces the retrieval set behind a response.
|
|
40
|
+
*/
|
|
41
|
+
declare const SourceList: React.ForwardRefExoticComponent<SourceListProps & React.RefAttributes<HTMLDivElement>>;
|
|
42
|
+
|
|
43
|
+
export { Citation, type CitationProps, SourceItem, type SourceItemProps, SourceList, type SourceListProps };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface CitationProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "title"> {
|
|
4
|
+
/** Source index shown in the chip, e.g. `4`. Ignored if `children` is given. */
|
|
5
|
+
index?: number;
|
|
6
|
+
/** Text label instead of a number, e.g. `"wikipedia.com"`. */
|
|
7
|
+
label?: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* An inline citation chip embedded in an AI answer — a compact numbered or
|
|
11
|
+
* domain marker that attributes a claim to a source.
|
|
12
|
+
* Source: Figma "Explainability / Inline source chip".
|
|
13
|
+
*/
|
|
14
|
+
declare const Citation: React.ForwardRefExoticComponent<CitationProps & React.RefAttributes<HTMLButtonElement>>;
|
|
15
|
+
interface SourceItemProps extends Omit<React.LiHTMLAttributes<HTMLLIElement>, "title"> {
|
|
16
|
+
/** Optional leading index, e.g. `1`. */
|
|
17
|
+
index?: number;
|
|
18
|
+
/** Icon shown in the leading slot. Defaults to a document icon. */
|
|
19
|
+
icon?: React.ReactNode;
|
|
20
|
+
/** Source title, e.g. a filename. */
|
|
21
|
+
title: React.ReactNode;
|
|
22
|
+
/** Metadata line, e.g. `"Source · PDF · Section 4.1"`. */
|
|
23
|
+
meta?: React.ReactNode;
|
|
24
|
+
/** If set, the open affordance becomes a link to this href. */
|
|
25
|
+
href?: string;
|
|
26
|
+
/** Label for the open affordance. Defaults to `"Open"`. */
|
|
27
|
+
actionLabel?: React.ReactNode;
|
|
28
|
+
/** Called when the open affordance is activated (button mode). */
|
|
29
|
+
onOpen?: () => void;
|
|
30
|
+
}
|
|
31
|
+
/** A single row in a {@link SourceList}: icon, title, metadata and an open action. */
|
|
32
|
+
declare const SourceItem: React.ForwardRefExoticComponent<SourceItemProps & React.RefAttributes<HTMLLIElement>>;
|
|
33
|
+
interface SourceListProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
34
|
+
/** Heading above the list, e.g. `"3 sources · 1 missing policy"`. */
|
|
35
|
+
heading?: React.ReactNode;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A grounded sources block: the knowledge sources an AI answer drew on, each an
|
|
39
|
+
* openable {@link SourceItem}. Surfaces the retrieval set behind a response.
|
|
40
|
+
*/
|
|
41
|
+
declare const SourceList: React.ForwardRefExoticComponent<SourceListProps & React.RefAttributes<HTMLDivElement>>;
|
|
42
|
+
|
|
43
|
+
export { Citation, type CitationProps, SourceItem, type SourceItemProps, SourceList, type SourceListProps };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { cn } from '@nucleux/utils';
|
|
4
|
+
import { FileText, ExternalLink } from 'lucide-react';
|
|
5
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
// src/index.tsx
|
|
8
|
+
var Citation = React.forwardRef(
|
|
9
|
+
({ index, label, className, children, type = "button", ...props }, ref) => /* @__PURE__ */ jsx(
|
|
10
|
+
"button",
|
|
11
|
+
{
|
|
12
|
+
ref,
|
|
13
|
+
type,
|
|
14
|
+
className: cn(
|
|
15
|
+
"inline-flex h-5 min-w-5 items-center justify-center gap-1 rounded-full border border-border bg-muted px-1.5 align-middle text-[0.6875rem] font-medium leading-none text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
16
|
+
className
|
|
17
|
+
),
|
|
18
|
+
...props,
|
|
19
|
+
children: children ?? label ?? index
|
|
20
|
+
}
|
|
21
|
+
)
|
|
22
|
+
);
|
|
23
|
+
Citation.displayName = "Citation";
|
|
24
|
+
var SourceItem = React.forwardRef(
|
|
25
|
+
({ index, icon, title, meta, href, actionLabel = "Open", onOpen, className, ...props }, ref) => {
|
|
26
|
+
const action = href ? /* @__PURE__ */ jsxs(
|
|
27
|
+
"a",
|
|
28
|
+
{
|
|
29
|
+
href,
|
|
30
|
+
className: "inline-flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-info transition-colors hover:bg-info/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
31
|
+
children: [
|
|
32
|
+
actionLabel,
|
|
33
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "size-3.5", "aria-hidden": "true" })
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
) : /* @__PURE__ */ jsxs(
|
|
37
|
+
"button",
|
|
38
|
+
{
|
|
39
|
+
type: "button",
|
|
40
|
+
onClick: onOpen,
|
|
41
|
+
className: "inline-flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-info transition-colors hover:bg-info/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
42
|
+
children: [
|
|
43
|
+
actionLabel,
|
|
44
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "size-3.5", "aria-hidden": "true" })
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
return /* @__PURE__ */ jsxs(
|
|
49
|
+
"li",
|
|
50
|
+
{
|
|
51
|
+
ref,
|
|
52
|
+
className: cn("flex items-center gap-3 rounded-lg border border-border bg-background p-3", className),
|
|
53
|
+
...props,
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ jsx("span", { className: "inline-flex size-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground", children: index != null ? /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold", children: index }) : icon ?? /* @__PURE__ */ jsx(FileText, { className: "size-4", "aria-hidden": "true" }) }),
|
|
56
|
+
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
57
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium text-foreground", children: title }),
|
|
58
|
+
meta && /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: meta })
|
|
59
|
+
] }),
|
|
60
|
+
action
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
SourceItem.displayName = "SourceItem";
|
|
67
|
+
var SourceList = React.forwardRef(
|
|
68
|
+
({ heading, className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
69
|
+
"div",
|
|
70
|
+
{
|
|
71
|
+
ref,
|
|
72
|
+
className: cn("flex flex-col gap-2 rounded-xl border border-border bg-muted/30 p-3", className),
|
|
73
|
+
...props,
|
|
74
|
+
children: [
|
|
75
|
+
heading && /* @__PURE__ */ jsx("p", { className: "px-1 text-xs font-medium uppercase tracking-wide text-muted-foreground", children: heading }),
|
|
76
|
+
/* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-2", children })
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
);
|
|
81
|
+
SourceList.displayName = "SourceList";
|
|
82
|
+
|
|
83
|
+
export { Citation, SourceItem, SourceList };
|
|
84
|
+
//# sourceMappingURL=index.js.map
|
|
85
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@nucleux/utils\";\nimport { FileText, ExternalLink } from \"lucide-react\";\n\nexport interface CitationProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"title\"> {\n /** Source index shown in the chip, e.g. `4`. Ignored if `children` is given. */\n index?: number;\n /** Text label instead of a number, e.g. `\"wikipedia.com\"`. */\n label?: React.ReactNode;\n}\n\n/**\n * An inline citation chip embedded in an AI answer — a compact numbered or\n * domain marker that attributes a claim to a source.\n * Source: Figma \"Explainability / Inline source chip\".\n */\nexport const Citation = React.forwardRef<HTMLButtonElement, CitationProps>(\n ({ index, label, className, children, type = \"button\", ...props }, ref) => (\n <button\n ref={ref}\n type={type}\n className={cn(\n \"inline-flex h-5 min-w-5 items-center justify-center gap-1 rounded-full border border-border bg-muted px-1.5 align-middle text-[0.6875rem] font-medium leading-none text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n className,\n )}\n {...props}\n >\n {children ?? label ?? index}\n </button>\n ),\n);\nCitation.displayName = \"Citation\";\n\nexport interface SourceItemProps\n extends Omit<React.LiHTMLAttributes<HTMLLIElement>, \"title\"> {\n /** Optional leading index, e.g. `1`. */\n index?: number;\n /** Icon shown in the leading slot. Defaults to a document icon. */\n icon?: React.ReactNode;\n /** Source title, e.g. a filename. */\n title: React.ReactNode;\n /** Metadata line, e.g. `\"Source · PDF · Section 4.1\"`. */\n meta?: React.ReactNode;\n /** If set, the open affordance becomes a link to this href. */\n href?: string;\n /** Label for the open affordance. Defaults to `\"Open\"`. */\n actionLabel?: React.ReactNode;\n /** Called when the open affordance is activated (button mode). */\n onOpen?: () => void;\n}\n\n/** A single row in a {@link SourceList}: icon, title, metadata and an open action. */\nexport const SourceItem = React.forwardRef<HTMLLIElement, SourceItemProps>(\n ({ index, icon, title, meta, href, actionLabel = \"Open\", onOpen, className, ...props }, ref) => {\n const action = href ? (\n <a\n href={href}\n className=\"inline-flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-info transition-colors hover:bg-info/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {actionLabel}\n <ExternalLink className=\"size-3.5\" aria-hidden=\"true\" />\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"inline-flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-info transition-colors hover:bg-info/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {actionLabel}\n <ExternalLink className=\"size-3.5\" aria-hidden=\"true\" />\n </button>\n );\n return (\n <li\n ref={ref}\n className={cn(\"flex items-center gap-3 rounded-lg border border-border bg-background p-3\", className)}\n {...props}\n >\n <span className=\"inline-flex size-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground\">\n {index != null ? (\n <span className=\"text-xs font-semibold\">{index}</span>\n ) : (\n icon ?? <FileText className=\"size-4\" aria-hidden=\"true\" />\n )}\n </span>\n <span className=\"flex min-w-0 flex-1 flex-col\">\n <span className=\"truncate text-sm font-medium text-foreground\">{title}</span>\n {meta && <span className=\"truncate text-xs text-muted-foreground\">{meta}</span>}\n </span>\n {action}\n </li>\n );\n },\n);\nSourceItem.displayName = \"SourceItem\";\n\nexport interface SourceListProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Heading above the list, e.g. `\"3 sources · 1 missing policy\"`. */\n heading?: React.ReactNode;\n}\n\n/**\n * A grounded sources block: the knowledge sources an AI answer drew on, each an\n * openable {@link SourceItem}. Surfaces the retrieval set behind a response.\n */\nexport const SourceList = React.forwardRef<HTMLDivElement, SourceListProps>(\n ({ heading, className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"flex flex-col gap-2 rounded-xl border border-border bg-muted/30 p-3\", className)}\n {...props}\n >\n {heading && (\n <p className=\"px-1 text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {heading}\n </p>\n )}\n <ul className=\"flex flex-col gap-2\">{children}</ul>\n </div>\n ),\n);\nSourceList.displayName = \"SourceList\";\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nucleux/citation",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"description": "Citation — inline source chips and a grounded sources list for AI answers — Nucleux agentic UI for React.",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"nucleux",
|
|
9
|
+
"react",
|
|
10
|
+
"ui",
|
|
11
|
+
"components",
|
|
12
|
+
"agentic",
|
|
13
|
+
"ai",
|
|
14
|
+
"tailwind",
|
|
15
|
+
"citation"
|
|
16
|
+
],
|
|
17
|
+
"main": "./dist/index.cjs",
|
|
18
|
+
"module": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
|
+
"require": "./dist/index.cjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"react": ">=18",
|
|
33
|
+
"react-dom": ">=18"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"lucide-react": "^0.469.0",
|
|
37
|
+
"@nucleux/utils": "0.1.1"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"tsup": "^8.3.5",
|
|
41
|
+
"typescript": "^5.7.2",
|
|
42
|
+
"@types/react": "^18.3.18",
|
|
43
|
+
"react": "^18.3.1"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/intelligaia-open-labs/nucleux.git",
|
|
52
|
+
"directory": "packages/citation"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://github.com/intelligaia-open-labs/nucleux#readme",
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsup"
|
|
57
|
+
}
|
|
58
|
+
}
|