@nucleux/md3-knowledge-base 0.0.0-stage → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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 CHANGED
@@ -1,3 +1,46 @@
1
- # Temporary Holding Version
1
+ # @nucleux/md3-knowledge-base
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Material 3 Knowledge Base — persistent, named sources the agent grounds in, with readiness and provenance — 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
+ This is the Material 3 twin of [`@nucleux/knowledge-base`](../knowledge-base) and **shares its API**: the props types are re-exported from it, so switching families is a change of import only.
8
+
9
+ ## Exports
10
+
11
+ - **`Md3KnowledgeBase`** — pick the bases the agent grounds in: a card of checkable list rows (default) or a wrap of filter chips with document counts (`variant="chips"`). Readiness is a word on each row (Ready, Processing, Needs refresh, Couldn't process) led by a ring (not usable yet) or a filled disc (usable); a failed row is outlined in error with Retry on the row (`onRefresh`); `onAdd` adds an "Add a base" control.
12
+ - **`Md3KnowledgeBaseSources`** — the documents (and sections) an answer read; while `reading`, a pulsing tonal band says so, politely announced.
13
+ - **`Md3KnowledgeBaseCoverage`** — a tonal label: "Well-covered · 14 matches", "Partly covered", "Thin coverage".
14
+ - Types: `Md3KnowledgeBaseProps`, `Md3KnowledgeBaseSourcesProps`, `Md3KnowledgeBaseCoverageProps`, `Md3KnowledgeBaseVariant`, `Md3KnowledgeBaseCoverageLevel`, `Md3KnowledgeSourceStatus`, `KnowledgeSource`, `KnowledgeBaseSourceRef`
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ pnpm add @nucleux/md3-knowledge-base @nucleux/tokens
20
+ ```
21
+
22
+ `react` / `react-dom` are peer dependencies.
23
+
24
+ ## Usage
25
+
26
+ ```tsx
27
+ import { Md3KnowledgeBase, Md3KnowledgeBaseSources, Md3KnowledgeBaseCoverage } from "@nucleux/md3-knowledge-base";
28
+
29
+ <Md3KnowledgeBase
30
+ heading="Active knowledge"
31
+ onRefresh={(id) => reindex(id)}
32
+ sources={[
33
+ { id: "crm", name: "CRM records", status: "ready", count: 18240 },
34
+ { id: "msa", name: "MSA Template.pdf", status: "error", meta: "Password-protected" },
35
+ ]}
36
+ />
37
+ <Md3KnowledgeBaseSources baseName="Sales playbook" sources={[{ id: "1", name: "Renewal Playbook v3", section: "§4.1" }]} />
38
+ <Md3KnowledgeBaseCoverage level="high" matches={14} />
39
+ ```
40
+
41
+ Requires the theme once in your app: `import "@nucleux/tokens/styles.css";`
42
+ and the Tailwind preset from `@nucleux/tokens/preset`.
43
+
44
+ ## License
45
+
46
+ MIT © Nucleux
package/dist/index.cjs ADDED
@@ -0,0 +1,361 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var React = require('react');
5
+ var utils = require('@nucleux/utils');
6
+ var md3Button = require('@nucleux/md3-button');
7
+ var md3Chip = require('@nucleux/md3-chip');
8
+ var lucideReact = require('lucide-react');
9
+ var jsxRuntime = require('react/jsx-runtime');
10
+
11
+ function _interopNamespace(e) {
12
+ if (e && e.__esModule) return e;
13
+ var n = Object.create(null);
14
+ if (e) {
15
+ Object.keys(e).forEach(function (k) {
16
+ if (k !== 'default') {
17
+ var d = Object.getOwnPropertyDescriptor(e, k);
18
+ Object.defineProperty(n, k, d.get ? d : {
19
+ enumerable: true,
20
+ get: function () { return e[k]; }
21
+ });
22
+ }
23
+ });
24
+ }
25
+ n.default = e;
26
+ return Object.freeze(n);
27
+ }
28
+
29
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
30
+
31
+ // src/index.tsx
32
+ var statusWord = {
33
+ ready: "Ready",
34
+ processing: "Processing",
35
+ stale: "Needs refresh",
36
+ error: "Couldn't process"
37
+ };
38
+ var statusTone = {
39
+ ready: "text-md-primary",
40
+ processing: "text-md-on-surface-variant",
41
+ stale: "text-md-tertiary",
42
+ error: "text-md-error"
43
+ };
44
+ var StatusDot = ({ status }) => {
45
+ const usable = status === "ready" || status === "stale";
46
+ return /* @__PURE__ */ jsxRuntime.jsx(
47
+ "span",
48
+ {
49
+ "aria-hidden": "true",
50
+ className: utils.cn(
51
+ "inline-block size-2 shrink-0 rounded-full border-2 border-current align-middle transition-colors duration-200 motion-reduce:transition-none",
52
+ usable ? "bg-current" : "bg-transparent"
53
+ )
54
+ }
55
+ );
56
+ };
57
+ var nameText = (n, fallback) => typeof n === "string" ? n : fallback;
58
+ var Md3KnowledgeBase = React__namespace.forwardRef(
59
+ ({
60
+ sources,
61
+ value,
62
+ defaultValue = [],
63
+ onValueChange,
64
+ heading = "Knowledge sources",
65
+ variant = "list",
66
+ onAdd,
67
+ addLabel = "Add a base",
68
+ onRefresh,
69
+ className,
70
+ ...props
71
+ }, ref) => {
72
+ const [internal, setInternal] = React__namespace.useState(defaultValue);
73
+ const selected = value !== void 0 ? value : internal;
74
+ const headingId = React__namespace.useId();
75
+ const toggle = (id) => {
76
+ const next = selected.includes(id) ? selected.filter((v) => v !== id) : [...selected, id];
77
+ if (value === void 0) setInternal(next);
78
+ onValueChange?.(next);
79
+ };
80
+ if (variant === "chips") {
81
+ return /* @__PURE__ */ jsxRuntime.jsxs(
82
+ "div",
83
+ {
84
+ ref,
85
+ role: "group",
86
+ "aria-labelledby": heading ? headingId : void 0,
87
+ "aria-label": heading ? void 0 : "Knowledge sources",
88
+ className: utils.cn(
89
+ "flex flex-col gap-3 rounded-md-md bg-md-surface-container-low p-4 text-md-on-surface shadow-md-1",
90
+ className
91
+ ),
92
+ ...props,
93
+ children: [
94
+ heading && /* @__PURE__ */ jsxRuntime.jsx("p", { id: headingId, className: "text-sm font-medium tracking-[0.1px] text-md-on-surface", children: heading }),
95
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
96
+ sources.map((source) => {
97
+ const active = selected.includes(source.id);
98
+ return /* @__PURE__ */ jsxRuntime.jsxs(
99
+ md3Chip.Md3Chip,
100
+ {
101
+ variant: "filter",
102
+ selected: active,
103
+ role: "checkbox",
104
+ "aria-checked": active,
105
+ "aria-pressed": void 0,
106
+ onClick: () => toggle(source.id),
107
+ className: "transition-colors duration-200 motion-reduce:transition-none",
108
+ children: [
109
+ source.name,
110
+ source.count != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-normal", children: [
111
+ " \xB7 ",
112
+ source.count.toLocaleString()
113
+ ] }),
114
+ source.status && source.status !== "ready" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: utils.cn("font-normal", statusTone[source.status]), children: [
115
+ " \xB7 ",
116
+ statusWord[source.status]
117
+ ] })
118
+ ]
119
+ },
120
+ source.id
121
+ );
122
+ }),
123
+ onAdd && /* @__PURE__ */ jsxRuntime.jsx(md3Chip.Md3Chip, { variant: "assist", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { "aria-hidden": "true" }), onClick: onAdd, children: addLabel })
124
+ ] })
125
+ ]
126
+ }
127
+ );
128
+ }
129
+ return /* @__PURE__ */ jsxRuntime.jsxs(
130
+ "div",
131
+ {
132
+ ref,
133
+ className: utils.cn(
134
+ "flex flex-col gap-1 rounded-md-md bg-md-surface-container-low py-3 text-md-on-surface shadow-md-1",
135
+ className
136
+ ),
137
+ ...props,
138
+ children: [
139
+ heading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 pb-1", children: [
140
+ /* @__PURE__ */ jsxRuntime.jsx("p", { id: headingId, className: "text-sm font-medium tracking-[0.1px] text-md-on-surface-variant", children: heading }),
141
+ selected.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium tracking-[0.5px] text-md-on-surface-variant", children: [
142
+ selected.length,
143
+ " selected"
144
+ ] })
145
+ ] }),
146
+ /* @__PURE__ */ jsxRuntime.jsx(
147
+ "ul",
148
+ {
149
+ "aria-labelledby": heading ? headingId : void 0,
150
+ "aria-label": heading ? void 0 : "Knowledge sources",
151
+ className: "flex flex-col gap-1 px-2",
152
+ children: sources.map((source) => {
153
+ const active = selected.includes(source.id);
154
+ const failed = source.status === "error";
155
+ const recover = onRefresh && (source.status === "stale" || failed) ? /* @__PURE__ */ jsxRuntime.jsx(
156
+ md3Button.Md3Button,
157
+ {
158
+ variant: "text",
159
+ onClick: () => onRefresh(source.id),
160
+ "aria-label": `${failed ? "Retry" : "Refresh"} ${nameText(source.name, source.id)}`,
161
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCw, { "aria-hidden": "true" }),
162
+ className: "h-8 shrink-0 px-3 text-xs [&_svg]:size-4",
163
+ children: failed ? "Retry" : "Refresh"
164
+ }
165
+ ) : null;
166
+ return /* @__PURE__ */ jsxRuntime.jsxs(
167
+ "li",
168
+ {
169
+ "data-status": source.status,
170
+ className: utils.cn(
171
+ "flex items-center gap-1 rounded-md-sm border pr-1",
172
+ failed ? "border-md-error" : "border-transparent"
173
+ ),
174
+ children: [
175
+ /* @__PURE__ */ jsxRuntime.jsxs(
176
+ "button",
177
+ {
178
+ type: "button",
179
+ role: "checkbox",
180
+ "aria-checked": active,
181
+ onClick: () => toggle(source.id),
182
+ className: utils.cn(
183
+ "relative flex min-h-14 w-full min-w-0 flex-1 items-center gap-4 overflow-hidden rounded-md-sm px-2 py-2 text-left outline-none transition-colors duration-200 motion-reduce:transition-none",
184
+ "before:absolute before:inset-0 before:bg-md-on-surface before:opacity-0 before:transition-opacity before:content-['']",
185
+ "hover:before:opacity-[0.08] focus-visible:before:opacity-[0.12] active:before:opacity-[0.12]",
186
+ "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-md-primary",
187
+ active && "bg-md-secondary-container text-md-on-secondary-container"
188
+ ),
189
+ children: [
190
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex size-10 shrink-0 items-center justify-center rounded-full bg-md-surface-container-high text-md-on-surface-variant [&_svg]:size-5", children: source.icon ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { "aria-hidden": "true" }) }),
191
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex min-w-0 flex-1 flex-col", children: [
192
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-base text-md-on-surface", children: source.name }),
193
+ (source.meta || source.status || source.count != null) && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "truncate text-sm text-md-on-surface-variant", children: [
194
+ source.status && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: utils.cn("inline-flex items-center gap-1.5 font-medium", statusTone[source.status]), children: [
195
+ /* @__PURE__ */ jsxRuntime.jsx(StatusDot, { status: source.status }),
196
+ statusWord[source.status]
197
+ ] }),
198
+ source.status && (source.meta || source.count != null) && " \xB7 ",
199
+ source.count != null && `${source.count.toLocaleString()} docs`,
200
+ source.count != null && source.meta && " \xB7 ",
201
+ source.meta
202
+ ] })
203
+ ] }),
204
+ /* @__PURE__ */ jsxRuntime.jsx(
205
+ "span",
206
+ {
207
+ "aria-hidden": "true",
208
+ className: utils.cn(
209
+ "relative inline-flex size-[18px] shrink-0 items-center justify-center rounded-[2px] border-2 transition-colors duration-200 motion-reduce:transition-none [&_svg]:size-[14px]",
210
+ active ? "border-md-primary bg-md-primary text-md-on-primary" : "border-md-on-surface-variant text-transparent"
211
+ ),
212
+ children: active && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { "aria-hidden": "true" })
213
+ }
214
+ )
215
+ ]
216
+ }
217
+ ),
218
+ recover
219
+ ]
220
+ },
221
+ source.id
222
+ );
223
+ })
224
+ }
225
+ ),
226
+ onAdd && /* @__PURE__ */ jsxRuntime.jsx(
227
+ md3Button.Md3Button,
228
+ {
229
+ variant: "text",
230
+ onClick: onAdd,
231
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { "aria-hidden": "true" }),
232
+ className: "mx-2 mt-1 self-start px-3",
233
+ children: addLabel
234
+ }
235
+ )
236
+ ]
237
+ }
238
+ );
239
+ }
240
+ );
241
+ Md3KnowledgeBase.displayName = "Md3KnowledgeBase";
242
+ var Md3KnowledgeBaseSources = React__namespace.forwardRef(
243
+ ({ sources, baseName, heading, reading = false, className, ...props }, ref) => {
244
+ const headingId = React__namespace.useId();
245
+ const n = sources.length;
246
+ const count = `${n} ${n === 1 ? "source" : "sources"}`;
247
+ const title = heading ?? (reading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
248
+ "Reading",
249
+ baseName ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
250
+ " ",
251
+ baseName
252
+ ] }) : null,
253
+ "\u2026"
254
+ ] }) : baseName ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
255
+ "Used ",
256
+ count,
257
+ " from ",
258
+ baseName
259
+ ] }) : count);
260
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: utils.cn("flex flex-col gap-2 text-md-on-surface", className), ...props, children: [
261
+ /* @__PURE__ */ jsxRuntime.jsxs(
262
+ "p",
263
+ {
264
+ id: headingId,
265
+ role: "status",
266
+ "aria-live": "polite",
267
+ className: utils.cn(
268
+ "inline-flex items-center gap-2 text-xs font-medium tracking-[0.5px] text-md-on-surface-variant",
269
+ reading && "self-start rounded-full bg-md-secondary-container px-3 py-1 text-md-on-secondary-container"
270
+ ),
271
+ children: [
272
+ reading && /* @__PURE__ */ jsxRuntime.jsx(
273
+ "span",
274
+ {
275
+ "aria-hidden": "true",
276
+ className: "size-2 shrink-0 rounded-full bg-md-primary animate-pulse motion-reduce:animate-none"
277
+ }
278
+ ),
279
+ title
280
+ ]
281
+ }
282
+ ),
283
+ n > 0 && /* @__PURE__ */ jsxRuntime.jsx("ul", { "aria-labelledby": headingId, className: "flex flex-col gap-1", children: sources.map((s) => {
284
+ const body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
285
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { "aria-hidden": "true", className: "relative size-4 shrink-0 text-md-on-surface-variant" }),
286
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative truncate", children: s.name }),
287
+ s.section && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative shrink-0 text-md-on-surface-variant", children: [
288
+ "\xB7 ",
289
+ s.section
290
+ ] })
291
+ ] });
292
+ const cls = "relative flex items-center gap-2 overflow-hidden rounded-md-sm bg-md-surface-container px-3 py-2 text-sm text-md-on-surface";
293
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: s.href ? /* @__PURE__ */ jsxRuntime.jsx(
294
+ "a",
295
+ {
296
+ href: s.href,
297
+ className: utils.cn(
298
+ cls,
299
+ "outline-none before:absolute before:inset-0 before:bg-md-on-surface before:opacity-0 before:transition-opacity before:content-['']",
300
+ "hover:before:opacity-[0.08] focus-visible:before:opacity-[0.12] focus-visible:ring-2 focus-visible:ring-md-primary"
301
+ ),
302
+ children: body
303
+ }
304
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: cls, children: body }) }, s.id);
305
+ }) })
306
+ ] });
307
+ }
308
+ );
309
+ Md3KnowledgeBaseSources.displayName = "Md3KnowledgeBaseSources";
310
+ var coverage = {
311
+ high: {
312
+ word: "Well-covered",
313
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { "aria-hidden": "true", className: "size-3.5" }),
314
+ cls: "bg-md-primary-container text-md-on-primary-container"
315
+ },
316
+ partial: {
317
+ word: "Partly covered",
318
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { "aria-hidden": "true", className: "size-3.5" }),
319
+ cls: "bg-md-tertiary-container text-md-on-tertiary-container"
320
+ },
321
+ low: {
322
+ word: "Thin coverage",
323
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleAlert, { "aria-hidden": "true", className: "size-3.5" }),
324
+ cls: "bg-md-error-container text-md-on-error-container"
325
+ }
326
+ };
327
+ var Md3KnowledgeBaseCoverage = React__namespace.forwardRef(
328
+ ({ level, matches, label, className, ...props }, ref) => {
329
+ const c = coverage[level];
330
+ return /* @__PURE__ */ jsxRuntime.jsxs(
331
+ "span",
332
+ {
333
+ ref,
334
+ "data-level": level,
335
+ className: utils.cn(
336
+ "inline-flex h-6 items-center gap-1 rounded-md-sm px-2 text-xs font-medium tracking-[0.5px]",
337
+ c.cls,
338
+ className
339
+ ),
340
+ ...props,
341
+ children: [
342
+ c.icon,
343
+ label ?? c.word,
344
+ matches != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-normal", children: [
345
+ "\xB7 ",
346
+ matches,
347
+ " ",
348
+ matches === 1 ? "match" : "matches"
349
+ ] })
350
+ ]
351
+ }
352
+ );
353
+ }
354
+ );
355
+ Md3KnowledgeBaseCoverage.displayName = "Md3KnowledgeBaseCoverage";
356
+
357
+ exports.Md3KnowledgeBase = Md3KnowledgeBase;
358
+ exports.Md3KnowledgeBaseCoverage = Md3KnowledgeBaseCoverage;
359
+ exports.Md3KnowledgeBaseSources = Md3KnowledgeBaseSources;
360
+ //# sourceMappingURL=index.cjs.map
361
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.tsx"],"names":["jsx","cn","React","jsxs","Md3Chip","Plus","Md3Button","RotateCw","FileText","Check","Fragment","AlertTriangle","CircleAlert"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@nucleux/utils\";\nimport { Md3Button } from \"@nucleux/md3-button\";\nimport { Md3Chip } from \"@nucleux/md3-chip\";\nimport { AlertTriangle, Check, CircleAlert, FileText, Plus, RotateCw } from \"lucide-react\";\nimport type {\n KnowledgeBaseProps,\n KnowledgeBaseSourcesProps,\n KnowledgeBaseCoverageProps,\n KnowledgeBaseVariant,\n KnowledgeBaseCoverageLevel,\n KnowledgeSourceStatus,\n} from \"@nucleux/knowledge-base\";\n\n// Same API as @nucleux/knowledge-base: props and data shapes come from the twin.\nexport type Md3KnowledgeBaseProps = KnowledgeBaseProps;\nexport type Md3KnowledgeBaseSourcesProps = KnowledgeBaseSourcesProps;\nexport type Md3KnowledgeBaseCoverageProps = KnowledgeBaseCoverageProps;\nexport type Md3KnowledgeBaseVariant = KnowledgeBaseVariant;\nexport type Md3KnowledgeBaseCoverageLevel = KnowledgeBaseCoverageLevel;\nexport type Md3KnowledgeSourceStatus = KnowledgeSourceStatus;\nexport type { KnowledgeSource, KnowledgeBaseSourceRef } from \"@nucleux/knowledge-base\";\n\nconst statusWord: Record<KnowledgeSourceStatus, string> = {\n ready: \"Ready\",\n processing: \"Processing\",\n stale: \"Needs refresh\",\n error: \"Couldn't process\",\n};\n\nconst statusTone: Record<KnowledgeSourceStatus, string> = {\n ready: \"text-md-primary\",\n processing: \"text-md-on-surface-variant\",\n stale: \"text-md-tertiary\",\n error: \"text-md-error\",\n};\n\n/**\n * The status mark: a ring while the source cannot be used (processing, failed)\n * and a filled disc once it can (ready, stale) — the distinction is a shape,\n * not only a colour, so it survives greyscale.\n */\nconst StatusDot = ({ status }: { status: KnowledgeSourceStatus }) => {\n const usable = status === \"ready\" || status === \"stale\";\n return (\n <span\n aria-hidden=\"true\"\n className={cn(\n \"inline-block size-2 shrink-0 rounded-full border-2 border-current align-middle transition-colors duration-200 motion-reduce:transition-none\",\n usable ? \"bg-current\" : \"bg-transparent\",\n )}\n />\n );\n};\n\nconst nameText = (n: React.ReactNode, fallback: string) => (typeof n === \"string\" ? n : fallback);\n\n/**\n * Material 3 twin of `KnowledgeBase`: lets people choose which knowledge bases\n * the agent grounds in for this session — a card holding a list of checkable\n * rows (default) or a wrap of filter chips with document counts\n * (`variant=\"chips\"`). Readiness is a word on each row (Ready, Processing,\n * Needs refresh, Couldn't process) led by a ring (not usable yet) or a filled\n * disc (usable); a failed row is outlined in error, not flooded, with its\n * Retry/Refresh on the row itself. Shares the API of `@nucleux/knowledge-base`.\n */\nexport const Md3KnowledgeBase = React.forwardRef<HTMLDivElement, Md3KnowledgeBaseProps>(\n (\n {\n sources,\n value,\n defaultValue = [],\n onValueChange,\n heading = \"Knowledge sources\",\n variant = \"list\",\n onAdd,\n addLabel = \"Add a base\",\n onRefresh,\n className,\n ...props\n },\n ref,\n ) => {\n const [internal, setInternal] = React.useState<string[]>(defaultValue);\n const selected = value !== undefined ? value : internal;\n const headingId = React.useId();\n const toggle = (id: string) => {\n const next = selected.includes(id) ? selected.filter((v) => v !== id) : [...selected, id];\n if (value === undefined) setInternal(next);\n onValueChange?.(next);\n };\n\n if (variant === \"chips\") {\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-labelledby={heading ? headingId : undefined}\n aria-label={heading ? undefined : \"Knowledge sources\"}\n className={cn(\n \"flex flex-col gap-3 rounded-md-md bg-md-surface-container-low p-4 text-md-on-surface shadow-md-1\",\n className,\n )}\n {...props}\n >\n {heading && (\n <p id={headingId} className=\"text-sm font-medium tracking-[0.1px] text-md-on-surface\">\n {heading}\n </p>\n )}\n <div className=\"flex flex-wrap gap-2\">\n {sources.map((source) => {\n const active = selected.includes(source.id);\n return (\n <Md3Chip\n key={source.id}\n variant=\"filter\"\n selected={active}\n role=\"checkbox\"\n aria-checked={active}\n aria-pressed={undefined}\n onClick={() => toggle(source.id)}\n className=\"transition-colors duration-200 motion-reduce:transition-none\"\n >\n {source.name}\n {source.count != null && (\n <span className=\"font-normal\"> · {source.count.toLocaleString()}</span>\n )}\n {source.status && source.status !== \"ready\" && (\n <span className={cn(\"font-normal\", statusTone[source.status])}> · {statusWord[source.status]}</span>\n )}\n </Md3Chip>\n );\n })}\n {onAdd && (\n <Md3Chip variant=\"assist\" icon={<Plus aria-hidden=\"true\" />} onClick={onAdd}>\n {addLabel}\n </Md3Chip>\n )}\n </div>\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n className={cn(\n \"flex flex-col gap-1 rounded-md-md bg-md-surface-container-low py-3 text-md-on-surface shadow-md-1\",\n className,\n )}\n {...props}\n >\n {heading && (\n <div className=\"flex items-center justify-between px-4 pb-1\">\n <p id={headingId} className=\"text-sm font-medium tracking-[0.1px] text-md-on-surface-variant\">\n {heading}\n </p>\n {selected.length > 0 && (\n <span className=\"text-xs font-medium tracking-[0.5px] text-md-on-surface-variant\">\n {selected.length} selected\n </span>\n )}\n </div>\n )}\n <ul\n aria-labelledby={heading ? headingId : undefined}\n aria-label={heading ? undefined : \"Knowledge sources\"}\n className=\"flex flex-col gap-1 px-2\"\n >\n {sources.map((source) => {\n const active = selected.includes(source.id);\n const failed = source.status === \"error\";\n const recover =\n onRefresh && (source.status === \"stale\" || failed) ? (\n <Md3Button\n variant=\"text\"\n onClick={() => onRefresh(source.id)}\n aria-label={`${failed ? \"Retry\" : \"Refresh\"} ${nameText(source.name, source.id)}`}\n icon={<RotateCw aria-hidden=\"true\" />}\n className=\"h-8 shrink-0 px-3 text-xs [&_svg]:size-4\"\n >\n {failed ? \"Retry\" : \"Refresh\"}\n </Md3Button>\n ) : null;\n return (\n <li\n key={source.id}\n data-status={source.status}\n className={cn(\n \"flex items-center gap-1 rounded-md-sm border pr-1\",\n failed ? \"border-md-error\" : \"border-transparent\",\n )}\n >\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={active}\n onClick={() => toggle(source.id)}\n className={cn(\n \"relative flex min-h-14 w-full min-w-0 flex-1 items-center gap-4 overflow-hidden rounded-md-sm px-2 py-2 text-left outline-none transition-colors duration-200 motion-reduce:transition-none\",\n \"before:absolute before:inset-0 before:bg-md-on-surface before:opacity-0 before:transition-opacity before:content-['']\",\n \"hover:before:opacity-[0.08] focus-visible:before:opacity-[0.12] active:before:opacity-[0.12]\",\n \"focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-md-primary\",\n active && \"bg-md-secondary-container text-md-on-secondary-container\",\n )}\n >\n <span className=\"relative inline-flex size-10 shrink-0 items-center justify-center rounded-full bg-md-surface-container-high text-md-on-surface-variant [&_svg]:size-5\">\n {source.icon ?? <FileText aria-hidden=\"true\" />}\n </span>\n <span className=\"relative flex min-w-0 flex-1 flex-col\">\n <span className=\"truncate text-base text-md-on-surface\">{source.name}</span>\n {(source.meta || source.status || source.count != null) && (\n <span className=\"truncate text-sm text-md-on-surface-variant\">\n {source.status && (\n <span className={cn(\"inline-flex items-center gap-1.5 font-medium\", statusTone[source.status])}>\n <StatusDot status={source.status} />\n {statusWord[source.status]}\n </span>\n )}\n {source.status && (source.meta || source.count != null) && \" · \"}\n {source.count != null && `${source.count.toLocaleString()} docs`}\n {source.count != null && source.meta && \" · \"}\n {source.meta}\n </span>\n )}\n </span>\n {/* Material 3 checkbox visual (the row itself is the checkbox). */}\n <span\n aria-hidden=\"true\"\n className={cn(\n \"relative inline-flex size-[18px] shrink-0 items-center justify-center rounded-[2px] border-2 transition-colors duration-200 motion-reduce:transition-none [&_svg]:size-[14px]\",\n active\n ? \"border-md-primary bg-md-primary text-md-on-primary\"\n : \"border-md-on-surface-variant text-transparent\",\n )}\n >\n {active && <Check aria-hidden=\"true\" />}\n </span>\n </button>\n {recover}\n </li>\n );\n })}\n </ul>\n {onAdd && (\n <Md3Button\n variant=\"text\"\n onClick={onAdd}\n icon={<Plus aria-hidden=\"true\" />}\n className=\"mx-2 mt-1 self-start px-3\"\n >\n {addLabel}\n </Md3Button>\n )}\n </div>\n );\n },\n);\nMd3KnowledgeBase.displayName = \"Md3KnowledgeBase\";\n\n/**\n * Material 3 twin of `KnowledgeBaseSources`: the source list under an answer —\n * exactly which knowledge-base documents (and sections) the agent read. While\n * `reading`, a pulsing band says so (politely announced; deliberately not a\n * progress bar, since no honest percentage exists) and it swaps to provenance\n * when the answer finishes. Shares the API of `@nucleux/knowledge-base`.\n */\nexport const Md3KnowledgeBaseSources = React.forwardRef<HTMLDivElement, Md3KnowledgeBaseSourcesProps>(\n ({ sources, baseName, heading, reading = false, className, ...props }, ref) => {\n const headingId = React.useId();\n const n = sources.length;\n const count = `${n} ${n === 1 ? \"source\" : \"sources\"}`;\n const title =\n heading ??\n (reading ? (\n <>Reading{baseName ? <> {baseName}</> : null}…</>\n ) : baseName ? (\n <>\n Used {count} from {baseName}\n </>\n ) : (\n count\n ));\n return (\n <div ref={ref} className={cn(\"flex flex-col gap-2 text-md-on-surface\", className)} {...props}>\n <p\n id={headingId}\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n \"inline-flex items-center gap-2 text-xs font-medium tracking-[0.5px] text-md-on-surface-variant\",\n reading && \"self-start rounded-full bg-md-secondary-container px-3 py-1 text-md-on-secondary-container\",\n )}\n >\n {reading && (\n <span\n aria-hidden=\"true\"\n className=\"size-2 shrink-0 rounded-full bg-md-primary animate-pulse motion-reduce:animate-none\"\n />\n )}\n {title}\n </p>\n {n > 0 && (\n <ul aria-labelledby={headingId} className=\"flex flex-col gap-1\">\n {sources.map((s) => {\n const body = (\n <>\n <FileText aria-hidden=\"true\" className=\"relative size-4 shrink-0 text-md-on-surface-variant\" />\n <span className=\"relative truncate\">{s.name}</span>\n {s.section && <span className=\"relative shrink-0 text-md-on-surface-variant\">· {s.section}</span>}\n </>\n );\n const cls =\n \"relative flex items-center gap-2 overflow-hidden rounded-md-sm bg-md-surface-container px-3 py-2 text-sm text-md-on-surface\";\n return (\n <li key={s.id}>\n {s.href ? (\n <a\n href={s.href}\n className={cn(\n cls,\n \"outline-none before:absolute before:inset-0 before:bg-md-on-surface before:opacity-0 before:transition-opacity before:content-['']\",\n \"hover:before:opacity-[0.08] focus-visible:before:opacity-[0.12] focus-visible:ring-2 focus-visible:ring-md-primary\",\n )}\n >\n {body}\n </a>\n ) : (\n <span className={cls}>{body}</span>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n },\n);\nMd3KnowledgeBaseSources.displayName = \"Md3KnowledgeBaseSources\";\n\nconst coverage: Record<KnowledgeBaseCoverageLevel, { word: string; icon: React.ReactNode; cls: string }> = {\n high: {\n word: \"Well-covered\",\n icon: <Check aria-hidden=\"true\" className=\"size-3.5\" />,\n cls: \"bg-md-primary-container text-md-on-primary-container\",\n },\n partial: {\n word: \"Partly covered\",\n icon: <AlertTriangle aria-hidden=\"true\" className=\"size-3.5\" />,\n cls: \"bg-md-tertiary-container text-md-on-tertiary-container\",\n },\n low: {\n word: \"Thin coverage\",\n icon: <CircleAlert aria-hidden=\"true\" className=\"size-3.5\" />,\n cls: \"bg-md-error-container text-md-on-error-container\",\n },\n};\n\n/**\n * Material 3 twin of `KnowledgeBaseCoverage`: a small tonal label saying how\n * well the knowledge base covers the question — \"Well-covered · 14 matches\",\n * or a warning when context is thin. The word carries the meaning; the\n * container colour only reinforces it. Shares the API of `@nucleux/knowledge-base`.\n */\nexport const Md3KnowledgeBaseCoverage = React.forwardRef<HTMLSpanElement, Md3KnowledgeBaseCoverageProps>(\n ({ level, matches, label, className, ...props }, ref) => {\n const c = coverage[level];\n return (\n <span\n ref={ref}\n data-level={level}\n className={cn(\n \"inline-flex h-6 items-center gap-1 rounded-md-sm px-2 text-xs font-medium tracking-[0.5px]\",\n c.cls,\n className,\n )}\n {...props}\n >\n {c.icon}\n {label ?? c.word}\n {matches != null && (\n <span className=\"font-normal\">\n · {matches} {matches === 1 ? \"match\" : \"matches\"}\n </span>\n )}\n </span>\n );\n },\n);\nMd3KnowledgeBaseCoverage.displayName = \"Md3KnowledgeBaseCoverage\";\n"]}
@@ -0,0 +1,38 @@
1
+ import * as React from 'react';
2
+ import { KnowledgeBaseProps, KnowledgeBaseCoverageProps, KnowledgeBaseCoverageLevel, KnowledgeBaseSourcesProps, KnowledgeBaseVariant, KnowledgeSourceStatus } from '@nucleux/knowledge-base';
3
+ export { KnowledgeBaseSourceRef, KnowledgeSource } from '@nucleux/knowledge-base';
4
+
5
+ type Md3KnowledgeBaseProps = KnowledgeBaseProps;
6
+ type Md3KnowledgeBaseSourcesProps = KnowledgeBaseSourcesProps;
7
+ type Md3KnowledgeBaseCoverageProps = KnowledgeBaseCoverageProps;
8
+ type Md3KnowledgeBaseVariant = KnowledgeBaseVariant;
9
+ type Md3KnowledgeBaseCoverageLevel = KnowledgeBaseCoverageLevel;
10
+ type Md3KnowledgeSourceStatus = KnowledgeSourceStatus;
11
+
12
+ /**
13
+ * Material 3 twin of `KnowledgeBase`: lets people choose which knowledge bases
14
+ * the agent grounds in for this session — a card holding a list of checkable
15
+ * rows (default) or a wrap of filter chips with document counts
16
+ * (`variant="chips"`). Readiness is a word on each row (Ready, Processing,
17
+ * Needs refresh, Couldn't process) led by a ring (not usable yet) or a filled
18
+ * disc (usable); a failed row is outlined in error, not flooded, with its
19
+ * Retry/Refresh on the row itself. Shares the API of `@nucleux/knowledge-base`.
20
+ */
21
+ declare const Md3KnowledgeBase: React.ForwardRefExoticComponent<KnowledgeBaseProps & React.RefAttributes<HTMLDivElement>>;
22
+ /**
23
+ * Material 3 twin of `KnowledgeBaseSources`: the source list under an answer —
24
+ * exactly which knowledge-base documents (and sections) the agent read. While
25
+ * `reading`, a pulsing band says so (politely announced; deliberately not a
26
+ * progress bar, since no honest percentage exists) and it swaps to provenance
27
+ * when the answer finishes. Shares the API of `@nucleux/knowledge-base`.
28
+ */
29
+ declare const Md3KnowledgeBaseSources: React.ForwardRefExoticComponent<KnowledgeBaseSourcesProps & React.RefAttributes<HTMLDivElement>>;
30
+ /**
31
+ * Material 3 twin of `KnowledgeBaseCoverage`: a small tonal label saying how
32
+ * well the knowledge base covers the question — "Well-covered · 14 matches",
33
+ * or a warning when context is thin. The word carries the meaning; the
34
+ * container colour only reinforces it. Shares the API of `@nucleux/knowledge-base`.
35
+ */
36
+ declare const Md3KnowledgeBaseCoverage: React.ForwardRefExoticComponent<KnowledgeBaseCoverageProps & React.RefAttributes<HTMLSpanElement>>;
37
+
38
+ export { Md3KnowledgeBase, Md3KnowledgeBaseCoverage, type Md3KnowledgeBaseCoverageLevel, type Md3KnowledgeBaseCoverageProps, type Md3KnowledgeBaseProps, Md3KnowledgeBaseSources, type Md3KnowledgeBaseSourcesProps, type Md3KnowledgeBaseVariant, type Md3KnowledgeSourceStatus };
@@ -0,0 +1,38 @@
1
+ import * as React from 'react';
2
+ import { KnowledgeBaseProps, KnowledgeBaseCoverageProps, KnowledgeBaseCoverageLevel, KnowledgeBaseSourcesProps, KnowledgeBaseVariant, KnowledgeSourceStatus } from '@nucleux/knowledge-base';
3
+ export { KnowledgeBaseSourceRef, KnowledgeSource } from '@nucleux/knowledge-base';
4
+
5
+ type Md3KnowledgeBaseProps = KnowledgeBaseProps;
6
+ type Md3KnowledgeBaseSourcesProps = KnowledgeBaseSourcesProps;
7
+ type Md3KnowledgeBaseCoverageProps = KnowledgeBaseCoverageProps;
8
+ type Md3KnowledgeBaseVariant = KnowledgeBaseVariant;
9
+ type Md3KnowledgeBaseCoverageLevel = KnowledgeBaseCoverageLevel;
10
+ type Md3KnowledgeSourceStatus = KnowledgeSourceStatus;
11
+
12
+ /**
13
+ * Material 3 twin of `KnowledgeBase`: lets people choose which knowledge bases
14
+ * the agent grounds in for this session — a card holding a list of checkable
15
+ * rows (default) or a wrap of filter chips with document counts
16
+ * (`variant="chips"`). Readiness is a word on each row (Ready, Processing,
17
+ * Needs refresh, Couldn't process) led by a ring (not usable yet) or a filled
18
+ * disc (usable); a failed row is outlined in error, not flooded, with its
19
+ * Retry/Refresh on the row itself. Shares the API of `@nucleux/knowledge-base`.
20
+ */
21
+ declare const Md3KnowledgeBase: React.ForwardRefExoticComponent<KnowledgeBaseProps & React.RefAttributes<HTMLDivElement>>;
22
+ /**
23
+ * Material 3 twin of `KnowledgeBaseSources`: the source list under an answer —
24
+ * exactly which knowledge-base documents (and sections) the agent read. While
25
+ * `reading`, a pulsing band says so (politely announced; deliberately not a
26
+ * progress bar, since no honest percentage exists) and it swaps to provenance
27
+ * when the answer finishes. Shares the API of `@nucleux/knowledge-base`.
28
+ */
29
+ declare const Md3KnowledgeBaseSources: React.ForwardRefExoticComponent<KnowledgeBaseSourcesProps & React.RefAttributes<HTMLDivElement>>;
30
+ /**
31
+ * Material 3 twin of `KnowledgeBaseCoverage`: a small tonal label saying how
32
+ * well the knowledge base covers the question — "Well-covered · 14 matches",
33
+ * or a warning when context is thin. The word carries the meaning; the
34
+ * container colour only reinforces it. Shares the API of `@nucleux/knowledge-base`.
35
+ */
36
+ declare const Md3KnowledgeBaseCoverage: React.ForwardRefExoticComponent<KnowledgeBaseCoverageProps & React.RefAttributes<HTMLSpanElement>>;
37
+
38
+ export { Md3KnowledgeBase, Md3KnowledgeBaseCoverage, type Md3KnowledgeBaseCoverageLevel, type Md3KnowledgeBaseCoverageProps, type Md3KnowledgeBaseProps, Md3KnowledgeBaseSources, type Md3KnowledgeBaseSourcesProps, type Md3KnowledgeBaseVariant, type Md3KnowledgeSourceStatus };
package/dist/index.js ADDED
@@ -0,0 +1,337 @@
1
+ "use client";
2
+ import * as React from 'react';
3
+ import { cn } from '@nucleux/utils';
4
+ import { Md3Button } from '@nucleux/md3-button';
5
+ import { Md3Chip } from '@nucleux/md3-chip';
6
+ import { Plus, RotateCw, FileText, Check, CircleAlert, AlertTriangle } from 'lucide-react';
7
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
+
9
+ // src/index.tsx
10
+ var statusWord = {
11
+ ready: "Ready",
12
+ processing: "Processing",
13
+ stale: "Needs refresh",
14
+ error: "Couldn't process"
15
+ };
16
+ var statusTone = {
17
+ ready: "text-md-primary",
18
+ processing: "text-md-on-surface-variant",
19
+ stale: "text-md-tertiary",
20
+ error: "text-md-error"
21
+ };
22
+ var StatusDot = ({ status }) => {
23
+ const usable = status === "ready" || status === "stale";
24
+ return /* @__PURE__ */ jsx(
25
+ "span",
26
+ {
27
+ "aria-hidden": "true",
28
+ className: cn(
29
+ "inline-block size-2 shrink-0 rounded-full border-2 border-current align-middle transition-colors duration-200 motion-reduce:transition-none",
30
+ usable ? "bg-current" : "bg-transparent"
31
+ )
32
+ }
33
+ );
34
+ };
35
+ var nameText = (n, fallback) => typeof n === "string" ? n : fallback;
36
+ var Md3KnowledgeBase = React.forwardRef(
37
+ ({
38
+ sources,
39
+ value,
40
+ defaultValue = [],
41
+ onValueChange,
42
+ heading = "Knowledge sources",
43
+ variant = "list",
44
+ onAdd,
45
+ addLabel = "Add a base",
46
+ onRefresh,
47
+ className,
48
+ ...props
49
+ }, ref) => {
50
+ const [internal, setInternal] = React.useState(defaultValue);
51
+ const selected = value !== void 0 ? value : internal;
52
+ const headingId = React.useId();
53
+ const toggle = (id) => {
54
+ const next = selected.includes(id) ? selected.filter((v) => v !== id) : [...selected, id];
55
+ if (value === void 0) setInternal(next);
56
+ onValueChange?.(next);
57
+ };
58
+ if (variant === "chips") {
59
+ return /* @__PURE__ */ jsxs(
60
+ "div",
61
+ {
62
+ ref,
63
+ role: "group",
64
+ "aria-labelledby": heading ? headingId : void 0,
65
+ "aria-label": heading ? void 0 : "Knowledge sources",
66
+ className: cn(
67
+ "flex flex-col gap-3 rounded-md-md bg-md-surface-container-low p-4 text-md-on-surface shadow-md-1",
68
+ className
69
+ ),
70
+ ...props,
71
+ children: [
72
+ heading && /* @__PURE__ */ jsx("p", { id: headingId, className: "text-sm font-medium tracking-[0.1px] text-md-on-surface", children: heading }),
73
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
74
+ sources.map((source) => {
75
+ const active = selected.includes(source.id);
76
+ return /* @__PURE__ */ jsxs(
77
+ Md3Chip,
78
+ {
79
+ variant: "filter",
80
+ selected: active,
81
+ role: "checkbox",
82
+ "aria-checked": active,
83
+ "aria-pressed": void 0,
84
+ onClick: () => toggle(source.id),
85
+ className: "transition-colors duration-200 motion-reduce:transition-none",
86
+ children: [
87
+ source.name,
88
+ source.count != null && /* @__PURE__ */ jsxs("span", { className: "font-normal", children: [
89
+ " \xB7 ",
90
+ source.count.toLocaleString()
91
+ ] }),
92
+ source.status && source.status !== "ready" && /* @__PURE__ */ jsxs("span", { className: cn("font-normal", statusTone[source.status]), children: [
93
+ " \xB7 ",
94
+ statusWord[source.status]
95
+ ] })
96
+ ]
97
+ },
98
+ source.id
99
+ );
100
+ }),
101
+ onAdd && /* @__PURE__ */ jsx(Md3Chip, { variant: "assist", icon: /* @__PURE__ */ jsx(Plus, { "aria-hidden": "true" }), onClick: onAdd, children: addLabel })
102
+ ] })
103
+ ]
104
+ }
105
+ );
106
+ }
107
+ return /* @__PURE__ */ jsxs(
108
+ "div",
109
+ {
110
+ ref,
111
+ className: cn(
112
+ "flex flex-col gap-1 rounded-md-md bg-md-surface-container-low py-3 text-md-on-surface shadow-md-1",
113
+ className
114
+ ),
115
+ ...props,
116
+ children: [
117
+ heading && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 pb-1", children: [
118
+ /* @__PURE__ */ jsx("p", { id: headingId, className: "text-sm font-medium tracking-[0.1px] text-md-on-surface-variant", children: heading }),
119
+ selected.length > 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium tracking-[0.5px] text-md-on-surface-variant", children: [
120
+ selected.length,
121
+ " selected"
122
+ ] })
123
+ ] }),
124
+ /* @__PURE__ */ jsx(
125
+ "ul",
126
+ {
127
+ "aria-labelledby": heading ? headingId : void 0,
128
+ "aria-label": heading ? void 0 : "Knowledge sources",
129
+ className: "flex flex-col gap-1 px-2",
130
+ children: sources.map((source) => {
131
+ const active = selected.includes(source.id);
132
+ const failed = source.status === "error";
133
+ const recover = onRefresh && (source.status === "stale" || failed) ? /* @__PURE__ */ jsx(
134
+ Md3Button,
135
+ {
136
+ variant: "text",
137
+ onClick: () => onRefresh(source.id),
138
+ "aria-label": `${failed ? "Retry" : "Refresh"} ${nameText(source.name, source.id)}`,
139
+ icon: /* @__PURE__ */ jsx(RotateCw, { "aria-hidden": "true" }),
140
+ className: "h-8 shrink-0 px-3 text-xs [&_svg]:size-4",
141
+ children: failed ? "Retry" : "Refresh"
142
+ }
143
+ ) : null;
144
+ return /* @__PURE__ */ jsxs(
145
+ "li",
146
+ {
147
+ "data-status": source.status,
148
+ className: cn(
149
+ "flex items-center gap-1 rounded-md-sm border pr-1",
150
+ failed ? "border-md-error" : "border-transparent"
151
+ ),
152
+ children: [
153
+ /* @__PURE__ */ jsxs(
154
+ "button",
155
+ {
156
+ type: "button",
157
+ role: "checkbox",
158
+ "aria-checked": active,
159
+ onClick: () => toggle(source.id),
160
+ className: cn(
161
+ "relative flex min-h-14 w-full min-w-0 flex-1 items-center gap-4 overflow-hidden rounded-md-sm px-2 py-2 text-left outline-none transition-colors duration-200 motion-reduce:transition-none",
162
+ "before:absolute before:inset-0 before:bg-md-on-surface before:opacity-0 before:transition-opacity before:content-['']",
163
+ "hover:before:opacity-[0.08] focus-visible:before:opacity-[0.12] active:before:opacity-[0.12]",
164
+ "focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-md-primary",
165
+ active && "bg-md-secondary-container text-md-on-secondary-container"
166
+ ),
167
+ children: [
168
+ /* @__PURE__ */ jsx("span", { className: "relative inline-flex size-10 shrink-0 items-center justify-center rounded-full bg-md-surface-container-high text-md-on-surface-variant [&_svg]:size-5", children: source.icon ?? /* @__PURE__ */ jsx(FileText, { "aria-hidden": "true" }) }),
169
+ /* @__PURE__ */ jsxs("span", { className: "relative flex min-w-0 flex-1 flex-col", children: [
170
+ /* @__PURE__ */ jsx("span", { className: "truncate text-base text-md-on-surface", children: source.name }),
171
+ (source.meta || source.status || source.count != null) && /* @__PURE__ */ jsxs("span", { className: "truncate text-sm text-md-on-surface-variant", children: [
172
+ source.status && /* @__PURE__ */ jsxs("span", { className: cn("inline-flex items-center gap-1.5 font-medium", statusTone[source.status]), children: [
173
+ /* @__PURE__ */ jsx(StatusDot, { status: source.status }),
174
+ statusWord[source.status]
175
+ ] }),
176
+ source.status && (source.meta || source.count != null) && " \xB7 ",
177
+ source.count != null && `${source.count.toLocaleString()} docs`,
178
+ source.count != null && source.meta && " \xB7 ",
179
+ source.meta
180
+ ] })
181
+ ] }),
182
+ /* @__PURE__ */ jsx(
183
+ "span",
184
+ {
185
+ "aria-hidden": "true",
186
+ className: cn(
187
+ "relative inline-flex size-[18px] shrink-0 items-center justify-center rounded-[2px] border-2 transition-colors duration-200 motion-reduce:transition-none [&_svg]:size-[14px]",
188
+ active ? "border-md-primary bg-md-primary text-md-on-primary" : "border-md-on-surface-variant text-transparent"
189
+ ),
190
+ children: active && /* @__PURE__ */ jsx(Check, { "aria-hidden": "true" })
191
+ }
192
+ )
193
+ ]
194
+ }
195
+ ),
196
+ recover
197
+ ]
198
+ },
199
+ source.id
200
+ );
201
+ })
202
+ }
203
+ ),
204
+ onAdd && /* @__PURE__ */ jsx(
205
+ Md3Button,
206
+ {
207
+ variant: "text",
208
+ onClick: onAdd,
209
+ icon: /* @__PURE__ */ jsx(Plus, { "aria-hidden": "true" }),
210
+ className: "mx-2 mt-1 self-start px-3",
211
+ children: addLabel
212
+ }
213
+ )
214
+ ]
215
+ }
216
+ );
217
+ }
218
+ );
219
+ Md3KnowledgeBase.displayName = "Md3KnowledgeBase";
220
+ var Md3KnowledgeBaseSources = React.forwardRef(
221
+ ({ sources, baseName, heading, reading = false, className, ...props }, ref) => {
222
+ const headingId = React.useId();
223
+ const n = sources.length;
224
+ const count = `${n} ${n === 1 ? "source" : "sources"}`;
225
+ const title = heading ?? (reading ? /* @__PURE__ */ jsxs(Fragment, { children: [
226
+ "Reading",
227
+ baseName ? /* @__PURE__ */ jsxs(Fragment, { children: [
228
+ " ",
229
+ baseName
230
+ ] }) : null,
231
+ "\u2026"
232
+ ] }) : baseName ? /* @__PURE__ */ jsxs(Fragment, { children: [
233
+ "Used ",
234
+ count,
235
+ " from ",
236
+ baseName
237
+ ] }) : count);
238
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("flex flex-col gap-2 text-md-on-surface", className), ...props, children: [
239
+ /* @__PURE__ */ jsxs(
240
+ "p",
241
+ {
242
+ id: headingId,
243
+ role: "status",
244
+ "aria-live": "polite",
245
+ className: cn(
246
+ "inline-flex items-center gap-2 text-xs font-medium tracking-[0.5px] text-md-on-surface-variant",
247
+ reading && "self-start rounded-full bg-md-secondary-container px-3 py-1 text-md-on-secondary-container"
248
+ ),
249
+ children: [
250
+ reading && /* @__PURE__ */ jsx(
251
+ "span",
252
+ {
253
+ "aria-hidden": "true",
254
+ className: "size-2 shrink-0 rounded-full bg-md-primary animate-pulse motion-reduce:animate-none"
255
+ }
256
+ ),
257
+ title
258
+ ]
259
+ }
260
+ ),
261
+ n > 0 && /* @__PURE__ */ jsx("ul", { "aria-labelledby": headingId, className: "flex flex-col gap-1", children: sources.map((s) => {
262
+ const body = /* @__PURE__ */ jsxs(Fragment, { children: [
263
+ /* @__PURE__ */ jsx(FileText, { "aria-hidden": "true", className: "relative size-4 shrink-0 text-md-on-surface-variant" }),
264
+ /* @__PURE__ */ jsx("span", { className: "relative truncate", children: s.name }),
265
+ s.section && /* @__PURE__ */ jsxs("span", { className: "relative shrink-0 text-md-on-surface-variant", children: [
266
+ "\xB7 ",
267
+ s.section
268
+ ] })
269
+ ] });
270
+ const cls = "relative flex items-center gap-2 overflow-hidden rounded-md-sm bg-md-surface-container px-3 py-2 text-sm text-md-on-surface";
271
+ return /* @__PURE__ */ jsx("li", { children: s.href ? /* @__PURE__ */ jsx(
272
+ "a",
273
+ {
274
+ href: s.href,
275
+ className: cn(
276
+ cls,
277
+ "outline-none before:absolute before:inset-0 before:bg-md-on-surface before:opacity-0 before:transition-opacity before:content-['']",
278
+ "hover:before:opacity-[0.08] focus-visible:before:opacity-[0.12] focus-visible:ring-2 focus-visible:ring-md-primary"
279
+ ),
280
+ children: body
281
+ }
282
+ ) : /* @__PURE__ */ jsx("span", { className: cls, children: body }) }, s.id);
283
+ }) })
284
+ ] });
285
+ }
286
+ );
287
+ Md3KnowledgeBaseSources.displayName = "Md3KnowledgeBaseSources";
288
+ var coverage = {
289
+ high: {
290
+ word: "Well-covered",
291
+ icon: /* @__PURE__ */ jsx(Check, { "aria-hidden": "true", className: "size-3.5" }),
292
+ cls: "bg-md-primary-container text-md-on-primary-container"
293
+ },
294
+ partial: {
295
+ word: "Partly covered",
296
+ icon: /* @__PURE__ */ jsx(AlertTriangle, { "aria-hidden": "true", className: "size-3.5" }),
297
+ cls: "bg-md-tertiary-container text-md-on-tertiary-container"
298
+ },
299
+ low: {
300
+ word: "Thin coverage",
301
+ icon: /* @__PURE__ */ jsx(CircleAlert, { "aria-hidden": "true", className: "size-3.5" }),
302
+ cls: "bg-md-error-container text-md-on-error-container"
303
+ }
304
+ };
305
+ var Md3KnowledgeBaseCoverage = React.forwardRef(
306
+ ({ level, matches, label, className, ...props }, ref) => {
307
+ const c = coverage[level];
308
+ return /* @__PURE__ */ jsxs(
309
+ "span",
310
+ {
311
+ ref,
312
+ "data-level": level,
313
+ className: cn(
314
+ "inline-flex h-6 items-center gap-1 rounded-md-sm px-2 text-xs font-medium tracking-[0.5px]",
315
+ c.cls,
316
+ className
317
+ ),
318
+ ...props,
319
+ children: [
320
+ c.icon,
321
+ label ?? c.word,
322
+ matches != null && /* @__PURE__ */ jsxs("span", { className: "font-normal", children: [
323
+ "\xB7 ",
324
+ matches,
325
+ " ",
326
+ matches === 1 ? "match" : "matches"
327
+ ] })
328
+ ]
329
+ }
330
+ );
331
+ }
332
+ );
333
+ Md3KnowledgeBaseCoverage.displayName = "Md3KnowledgeBaseCoverage";
334
+
335
+ export { Md3KnowledgeBase, Md3KnowledgeBaseCoverage, Md3KnowledgeBaseSources };
336
+ //# sourceMappingURL=index.js.map
337
+ //# 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 { Md3Button } from \"@nucleux/md3-button\";\nimport { Md3Chip } from \"@nucleux/md3-chip\";\nimport { AlertTriangle, Check, CircleAlert, FileText, Plus, RotateCw } from \"lucide-react\";\nimport type {\n KnowledgeBaseProps,\n KnowledgeBaseSourcesProps,\n KnowledgeBaseCoverageProps,\n KnowledgeBaseVariant,\n KnowledgeBaseCoverageLevel,\n KnowledgeSourceStatus,\n} from \"@nucleux/knowledge-base\";\n\n// Same API as @nucleux/knowledge-base: props and data shapes come from the twin.\nexport type Md3KnowledgeBaseProps = KnowledgeBaseProps;\nexport type Md3KnowledgeBaseSourcesProps = KnowledgeBaseSourcesProps;\nexport type Md3KnowledgeBaseCoverageProps = KnowledgeBaseCoverageProps;\nexport type Md3KnowledgeBaseVariant = KnowledgeBaseVariant;\nexport type Md3KnowledgeBaseCoverageLevel = KnowledgeBaseCoverageLevel;\nexport type Md3KnowledgeSourceStatus = KnowledgeSourceStatus;\nexport type { KnowledgeSource, KnowledgeBaseSourceRef } from \"@nucleux/knowledge-base\";\n\nconst statusWord: Record<KnowledgeSourceStatus, string> = {\n ready: \"Ready\",\n processing: \"Processing\",\n stale: \"Needs refresh\",\n error: \"Couldn't process\",\n};\n\nconst statusTone: Record<KnowledgeSourceStatus, string> = {\n ready: \"text-md-primary\",\n processing: \"text-md-on-surface-variant\",\n stale: \"text-md-tertiary\",\n error: \"text-md-error\",\n};\n\n/**\n * The status mark: a ring while the source cannot be used (processing, failed)\n * and a filled disc once it can (ready, stale) — the distinction is a shape,\n * not only a colour, so it survives greyscale.\n */\nconst StatusDot = ({ status }: { status: KnowledgeSourceStatus }) => {\n const usable = status === \"ready\" || status === \"stale\";\n return (\n <span\n aria-hidden=\"true\"\n className={cn(\n \"inline-block size-2 shrink-0 rounded-full border-2 border-current align-middle transition-colors duration-200 motion-reduce:transition-none\",\n usable ? \"bg-current\" : \"bg-transparent\",\n )}\n />\n );\n};\n\nconst nameText = (n: React.ReactNode, fallback: string) => (typeof n === \"string\" ? n : fallback);\n\n/**\n * Material 3 twin of `KnowledgeBase`: lets people choose which knowledge bases\n * the agent grounds in for this session — a card holding a list of checkable\n * rows (default) or a wrap of filter chips with document counts\n * (`variant=\"chips\"`). Readiness is a word on each row (Ready, Processing,\n * Needs refresh, Couldn't process) led by a ring (not usable yet) or a filled\n * disc (usable); a failed row is outlined in error, not flooded, with its\n * Retry/Refresh on the row itself. Shares the API of `@nucleux/knowledge-base`.\n */\nexport const Md3KnowledgeBase = React.forwardRef<HTMLDivElement, Md3KnowledgeBaseProps>(\n (\n {\n sources,\n value,\n defaultValue = [],\n onValueChange,\n heading = \"Knowledge sources\",\n variant = \"list\",\n onAdd,\n addLabel = \"Add a base\",\n onRefresh,\n className,\n ...props\n },\n ref,\n ) => {\n const [internal, setInternal] = React.useState<string[]>(defaultValue);\n const selected = value !== undefined ? value : internal;\n const headingId = React.useId();\n const toggle = (id: string) => {\n const next = selected.includes(id) ? selected.filter((v) => v !== id) : [...selected, id];\n if (value === undefined) setInternal(next);\n onValueChange?.(next);\n };\n\n if (variant === \"chips\") {\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-labelledby={heading ? headingId : undefined}\n aria-label={heading ? undefined : \"Knowledge sources\"}\n className={cn(\n \"flex flex-col gap-3 rounded-md-md bg-md-surface-container-low p-4 text-md-on-surface shadow-md-1\",\n className,\n )}\n {...props}\n >\n {heading && (\n <p id={headingId} className=\"text-sm font-medium tracking-[0.1px] text-md-on-surface\">\n {heading}\n </p>\n )}\n <div className=\"flex flex-wrap gap-2\">\n {sources.map((source) => {\n const active = selected.includes(source.id);\n return (\n <Md3Chip\n key={source.id}\n variant=\"filter\"\n selected={active}\n role=\"checkbox\"\n aria-checked={active}\n aria-pressed={undefined}\n onClick={() => toggle(source.id)}\n className=\"transition-colors duration-200 motion-reduce:transition-none\"\n >\n {source.name}\n {source.count != null && (\n <span className=\"font-normal\"> · {source.count.toLocaleString()}</span>\n )}\n {source.status && source.status !== \"ready\" && (\n <span className={cn(\"font-normal\", statusTone[source.status])}> · {statusWord[source.status]}</span>\n )}\n </Md3Chip>\n );\n })}\n {onAdd && (\n <Md3Chip variant=\"assist\" icon={<Plus aria-hidden=\"true\" />} onClick={onAdd}>\n {addLabel}\n </Md3Chip>\n )}\n </div>\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n className={cn(\n \"flex flex-col gap-1 rounded-md-md bg-md-surface-container-low py-3 text-md-on-surface shadow-md-1\",\n className,\n )}\n {...props}\n >\n {heading && (\n <div className=\"flex items-center justify-between px-4 pb-1\">\n <p id={headingId} className=\"text-sm font-medium tracking-[0.1px] text-md-on-surface-variant\">\n {heading}\n </p>\n {selected.length > 0 && (\n <span className=\"text-xs font-medium tracking-[0.5px] text-md-on-surface-variant\">\n {selected.length} selected\n </span>\n )}\n </div>\n )}\n <ul\n aria-labelledby={heading ? headingId : undefined}\n aria-label={heading ? undefined : \"Knowledge sources\"}\n className=\"flex flex-col gap-1 px-2\"\n >\n {sources.map((source) => {\n const active = selected.includes(source.id);\n const failed = source.status === \"error\";\n const recover =\n onRefresh && (source.status === \"stale\" || failed) ? (\n <Md3Button\n variant=\"text\"\n onClick={() => onRefresh(source.id)}\n aria-label={`${failed ? \"Retry\" : \"Refresh\"} ${nameText(source.name, source.id)}`}\n icon={<RotateCw aria-hidden=\"true\" />}\n className=\"h-8 shrink-0 px-3 text-xs [&_svg]:size-4\"\n >\n {failed ? \"Retry\" : \"Refresh\"}\n </Md3Button>\n ) : null;\n return (\n <li\n key={source.id}\n data-status={source.status}\n className={cn(\n \"flex items-center gap-1 rounded-md-sm border pr-1\",\n failed ? \"border-md-error\" : \"border-transparent\",\n )}\n >\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={active}\n onClick={() => toggle(source.id)}\n className={cn(\n \"relative flex min-h-14 w-full min-w-0 flex-1 items-center gap-4 overflow-hidden rounded-md-sm px-2 py-2 text-left outline-none transition-colors duration-200 motion-reduce:transition-none\",\n \"before:absolute before:inset-0 before:bg-md-on-surface before:opacity-0 before:transition-opacity before:content-['']\",\n \"hover:before:opacity-[0.08] focus-visible:before:opacity-[0.12] active:before:opacity-[0.12]\",\n \"focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-md-primary\",\n active && \"bg-md-secondary-container text-md-on-secondary-container\",\n )}\n >\n <span className=\"relative inline-flex size-10 shrink-0 items-center justify-center rounded-full bg-md-surface-container-high text-md-on-surface-variant [&_svg]:size-5\">\n {source.icon ?? <FileText aria-hidden=\"true\" />}\n </span>\n <span className=\"relative flex min-w-0 flex-1 flex-col\">\n <span className=\"truncate text-base text-md-on-surface\">{source.name}</span>\n {(source.meta || source.status || source.count != null) && (\n <span className=\"truncate text-sm text-md-on-surface-variant\">\n {source.status && (\n <span className={cn(\"inline-flex items-center gap-1.5 font-medium\", statusTone[source.status])}>\n <StatusDot status={source.status} />\n {statusWord[source.status]}\n </span>\n )}\n {source.status && (source.meta || source.count != null) && \" · \"}\n {source.count != null && `${source.count.toLocaleString()} docs`}\n {source.count != null && source.meta && \" · \"}\n {source.meta}\n </span>\n )}\n </span>\n {/* Material 3 checkbox visual (the row itself is the checkbox). */}\n <span\n aria-hidden=\"true\"\n className={cn(\n \"relative inline-flex size-[18px] shrink-0 items-center justify-center rounded-[2px] border-2 transition-colors duration-200 motion-reduce:transition-none [&_svg]:size-[14px]\",\n active\n ? \"border-md-primary bg-md-primary text-md-on-primary\"\n : \"border-md-on-surface-variant text-transparent\",\n )}\n >\n {active && <Check aria-hidden=\"true\" />}\n </span>\n </button>\n {recover}\n </li>\n );\n })}\n </ul>\n {onAdd && (\n <Md3Button\n variant=\"text\"\n onClick={onAdd}\n icon={<Plus aria-hidden=\"true\" />}\n className=\"mx-2 mt-1 self-start px-3\"\n >\n {addLabel}\n </Md3Button>\n )}\n </div>\n );\n },\n);\nMd3KnowledgeBase.displayName = \"Md3KnowledgeBase\";\n\n/**\n * Material 3 twin of `KnowledgeBaseSources`: the source list under an answer —\n * exactly which knowledge-base documents (and sections) the agent read. While\n * `reading`, a pulsing band says so (politely announced; deliberately not a\n * progress bar, since no honest percentage exists) and it swaps to provenance\n * when the answer finishes. Shares the API of `@nucleux/knowledge-base`.\n */\nexport const Md3KnowledgeBaseSources = React.forwardRef<HTMLDivElement, Md3KnowledgeBaseSourcesProps>(\n ({ sources, baseName, heading, reading = false, className, ...props }, ref) => {\n const headingId = React.useId();\n const n = sources.length;\n const count = `${n} ${n === 1 ? \"source\" : \"sources\"}`;\n const title =\n heading ??\n (reading ? (\n <>Reading{baseName ? <> {baseName}</> : null}…</>\n ) : baseName ? (\n <>\n Used {count} from {baseName}\n </>\n ) : (\n count\n ));\n return (\n <div ref={ref} className={cn(\"flex flex-col gap-2 text-md-on-surface\", className)} {...props}>\n <p\n id={headingId}\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n \"inline-flex items-center gap-2 text-xs font-medium tracking-[0.5px] text-md-on-surface-variant\",\n reading && \"self-start rounded-full bg-md-secondary-container px-3 py-1 text-md-on-secondary-container\",\n )}\n >\n {reading && (\n <span\n aria-hidden=\"true\"\n className=\"size-2 shrink-0 rounded-full bg-md-primary animate-pulse motion-reduce:animate-none\"\n />\n )}\n {title}\n </p>\n {n > 0 && (\n <ul aria-labelledby={headingId} className=\"flex flex-col gap-1\">\n {sources.map((s) => {\n const body = (\n <>\n <FileText aria-hidden=\"true\" className=\"relative size-4 shrink-0 text-md-on-surface-variant\" />\n <span className=\"relative truncate\">{s.name}</span>\n {s.section && <span className=\"relative shrink-0 text-md-on-surface-variant\">· {s.section}</span>}\n </>\n );\n const cls =\n \"relative flex items-center gap-2 overflow-hidden rounded-md-sm bg-md-surface-container px-3 py-2 text-sm text-md-on-surface\";\n return (\n <li key={s.id}>\n {s.href ? (\n <a\n href={s.href}\n className={cn(\n cls,\n \"outline-none before:absolute before:inset-0 before:bg-md-on-surface before:opacity-0 before:transition-opacity before:content-['']\",\n \"hover:before:opacity-[0.08] focus-visible:before:opacity-[0.12] focus-visible:ring-2 focus-visible:ring-md-primary\",\n )}\n >\n {body}\n </a>\n ) : (\n <span className={cls}>{body}</span>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n },\n);\nMd3KnowledgeBaseSources.displayName = \"Md3KnowledgeBaseSources\";\n\nconst coverage: Record<KnowledgeBaseCoverageLevel, { word: string; icon: React.ReactNode; cls: string }> = {\n high: {\n word: \"Well-covered\",\n icon: <Check aria-hidden=\"true\" className=\"size-3.5\" />,\n cls: \"bg-md-primary-container text-md-on-primary-container\",\n },\n partial: {\n word: \"Partly covered\",\n icon: <AlertTriangle aria-hidden=\"true\" className=\"size-3.5\" />,\n cls: \"bg-md-tertiary-container text-md-on-tertiary-container\",\n },\n low: {\n word: \"Thin coverage\",\n icon: <CircleAlert aria-hidden=\"true\" className=\"size-3.5\" />,\n cls: \"bg-md-error-container text-md-on-error-container\",\n },\n};\n\n/**\n * Material 3 twin of `KnowledgeBaseCoverage`: a small tonal label saying how\n * well the knowledge base covers the question — \"Well-covered · 14 matches\",\n * or a warning when context is thin. The word carries the meaning; the\n * container colour only reinforces it. Shares the API of `@nucleux/knowledge-base`.\n */\nexport const Md3KnowledgeBaseCoverage = React.forwardRef<HTMLSpanElement, Md3KnowledgeBaseCoverageProps>(\n ({ level, matches, label, className, ...props }, ref) => {\n const c = coverage[level];\n return (\n <span\n ref={ref}\n data-level={level}\n className={cn(\n \"inline-flex h-6 items-center gap-1 rounded-md-sm px-2 text-xs font-medium tracking-[0.5px]\",\n c.cls,\n className,\n )}\n {...props}\n >\n {c.icon}\n {label ?? c.word}\n {matches != null && (\n <span className=\"font-normal\">\n · {matches} {matches === 1 ? \"match\" : \"matches\"}\n </span>\n )}\n </span>\n );\n },\n);\nMd3KnowledgeBaseCoverage.displayName = \"Md3KnowledgeBaseCoverage\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,65 @@
1
1
  {
2
2
  "name": "@nucleux/md3-knowledge-base",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.6.0",
4
+ "type": "module",
5
+ "sideEffects": false,
6
+ "description": "Material 3 Knowledge Base — persistent, named sources the agent grounds in, with readiness and provenance — Nucleux agentic UI for React.",
7
+ "keywords": [
8
+ "nucleux",
9
+ "react",
10
+ "ui",
11
+ "components",
12
+ "agentic",
13
+ "ai",
14
+ "tailwind",
15
+ "md3",
16
+ "material",
17
+ "knowledge-base",
18
+ "rag",
19
+ "sources"
20
+ ],
21
+ "main": "./dist/index.cjs",
22
+ "module": "./dist/index.js",
23
+ "types": "./dist/index.d.ts",
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "import": "./dist/index.js",
28
+ "require": "./dist/index.cjs"
29
+ }
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "README.md"
34
+ ],
35
+ "peerDependencies": {
36
+ "react": ">=18",
37
+ "react-dom": ">=18"
38
+ },
39
+ "dependencies": {
40
+ "@nucleux/knowledge-base": "0.6.0",
41
+ "@nucleux/md3-button": "0.6.0",
42
+ "@nucleux/md3-chip": "0.6.0",
43
+ "@nucleux/utils": "0.6.0",
44
+ "lucide-react": "^0.469.0"
45
+ },
46
+ "devDependencies": {
47
+ "tsup": "^8.3.5",
48
+ "typescript": "^5.7.2",
49
+ "@types/react": "^18.3.18",
50
+ "react": "^18.3.1"
51
+ },
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "license": "MIT",
56
+ "repository": {
57
+ "type": "git",
58
+ "url": "git+https://github.com/intelligaia-open-labs/nucleux.git",
59
+ "directory": "packages/md3-knowledge-base"
60
+ },
61
+ "homepage": "https://github.com/intelligaia-open-labs/nucleux#readme",
62
+ "scripts": {
63
+ "build": "tsup"
64
+ }
6
65
  }