ionbase-ui 0.22.0 → 0.25.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.
Files changed (56) hide show
  1. package/dist/components/AgentActivity.d.ts +41 -0
  2. package/dist/components/AgentActivity.d.ts.map +1 -0
  3. package/dist/components/AgentActivity.js +84 -0
  4. package/dist/components/AgentActivity.js.map +1 -0
  5. package/dist/components/AgentStop.d.ts +58 -0
  6. package/dist/components/AgentStop.d.ts.map +1 -0
  7. package/dist/components/AgentStop.js +82 -0
  8. package/dist/components/AgentStop.js.map +1 -0
  9. package/dist/components/ApprovalGate.d.ts +72 -0
  10. package/dist/components/ApprovalGate.d.ts.map +1 -0
  11. package/dist/components/ApprovalGate.js +68 -0
  12. package/dist/components/ApprovalGate.js.map +1 -0
  13. package/dist/components/Citation.d.ts +51 -0
  14. package/dist/components/Citation.d.ts.map +1 -0
  15. package/dist/components/Citation.js +41 -0
  16. package/dist/components/Citation.js.map +1 -0
  17. package/dist/components/ConfidenceIndicator.d.ts +37 -0
  18. package/dist/components/ConfidenceIndicator.d.ts.map +1 -0
  19. package/dist/components/ConfidenceIndicator.js +41 -0
  20. package/dist/components/ConfidenceIndicator.js.map +1 -0
  21. package/dist/components/StreamingText.d.ts +47 -0
  22. package/dist/components/StreamingText.d.ts.map +1 -0
  23. package/dist/components/StreamingText.js +44 -0
  24. package/dist/components/StreamingText.js.map +1 -0
  25. package/dist/components/index.d.ts +12 -0
  26. package/dist/components/index.d.ts.map +1 -1
  27. package/dist/components/index.js +6 -0
  28. package/dist/components/index.js.map +1 -1
  29. package/dist/figma-descriptions.json +147 -0
  30. package/dist/figma-map.json +3 -1
  31. package/dist/meta/AgentActivity.json +103 -0
  32. package/dist/meta/AgentActivityStep.json +117 -0
  33. package/dist/meta/AgentStop.json +164 -0
  34. package/dist/meta/ApprovalGate.json +255 -0
  35. package/dist/meta/Avatar.json +2 -2
  36. package/dist/meta/AvatarGroup.json +2 -2
  37. package/dist/meta/Citation.json +101 -0
  38. package/dist/meta/CitationList.json +94 -0
  39. package/dist/meta/CitationListItem.json +88 -0
  40. package/dist/meta/ConfidenceIndicator.json +115 -0
  41. package/dist/meta/Input.json +2 -2
  42. package/dist/meta/PhoneInput.json +38 -38
  43. package/dist/meta/StreamingText.json +99 -0
  44. package/dist/meta/components.json +2125 -989
  45. package/dist/meta/contrast.json +1086 -32
  46. package/dist/meta/index.json +100 -5
  47. package/dist/meta/patterns/index.json +1 -1
  48. package/dist/styles/agent-activity.css +95 -0
  49. package/dist/styles/agent-stop.css +109 -0
  50. package/dist/styles/approval-gate.css +181 -0
  51. package/dist/styles/citation.css +93 -0
  52. package/dist/styles/confidence-indicator.css +97 -0
  53. package/dist/styles/index.css +34 -0
  54. package/dist/styles/streaming-text.css +56 -0
  55. package/llms.txt +2 -2
  56. package/package.json +4 -3
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ export type AgentActivityStatus = 'pending' | 'active' | 'done' | 'failed' | 'skipped';
3
+ export interface AgentActivityProps extends React.HTMLAttributes<HTMLOListElement> {
4
+ children?: React.ReactNode;
5
+ /**
6
+ * Announce the step that just became active, once, in a polite live region.
7
+ *
8
+ * On by default because the whole point of an activity log is knowing what
9
+ * the agent is doing without watching it. Turn it off when several logs are
10
+ * on screen at once, or they narrate over each other.
11
+ */
12
+ announceActive?: boolean;
13
+ }
14
+ export interface AgentActivityStepProps extends React.LiHTMLAttributes<HTMLLIElement> {
15
+ /** What the agent did, in the user's language. Not a function name. */
16
+ children?: React.ReactNode;
17
+ status?: AgentActivityStatus;
18
+ /** The result, a tool name, a count — whatever makes the step checkable. */
19
+ detail?: React.ReactNode;
20
+ }
21
+ /**
22
+ * AgentActivity — what the agent is doing, in plain language.
23
+ *
24
+ * An ordered list, because the steps happened in an order and a screen reader
25
+ * should say "3 of 7". Not a log viewer: this is the account a person reads to
26
+ * decide whether to let the run continue, so the text belongs in their
27
+ * language — "Searched the invoice archive", not `searchIndex(q, {limit:50})`.
28
+ *
29
+ * STATUS IS NEVER CARRIED BY THE ICON ALONE. Every step renders its status as
30
+ * text as well as a glyph. The glyphs differ in shape rather than only in
31
+ * colour, so the list survives greyscale, colour blindness and forced-colours
32
+ * mode — WCAG 1.4.1, which a row of coloured dots fails outright.
33
+ *
34
+ * ONE POLITE ANNOUNCEMENT PER STEP, not one per render. The active step's text
35
+ * is announced when it changes, so a user who is not watching still knows where
36
+ * the run has got to. Watching the DOM instead would re-announce on every
37
+ * unrelated update, which is the failure mode that makes people turn logs off.
38
+ */
39
+ export declare const AgentActivity: React.ForwardRefExoticComponent<AgentActivityProps & React.RefAttributes<HTMLOListElement>>;
40
+ export declare const AgentActivityStep: React.ForwardRefExoticComponent<AgentActivityStepProps & React.RefAttributes<HTMLLIElement>>;
41
+ //# sourceMappingURL=AgentActivity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentActivity.d.ts","sourceRoot":"","sources":["../../src/components/AgentActivity.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAEvE,MAAM,MAAM,mBAAmB,GAC7B,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEvD,MAAM,WAAW,kBAAmB,SAAQ,KAAK,CAAC,cAAc,CAAC,gBAAgB,CAAC;IAChF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAuB,SAAQ,KAAK,CAAC,gBAAgB,CAAC,aAAa,CAAC;IACnF,uEAAuE;IACvE,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,4EAA4E;IAC5E,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC1B;AAsED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,aAAa,6FAyDzB,CAAC;AAIF,eAAO,MAAM,iBAAiB,8FA6B5B,CAAC"}
@@ -0,0 +1,84 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import React, { forwardRef, useEffect, useRef, useState } from 'react';
4
+ const STATUS_TEXT = {
5
+ pending: 'Not started',
6
+ active: 'In progress',
7
+ done: 'Done',
8
+ failed: 'Failed',
9
+ skipped: 'Skipped',
10
+ };
11
+ const Glyphs = {
12
+ pending: () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeWidth: "2" }) })),
13
+ active: () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: [_jsx("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeWidth: "2", opacity: "0.3" }), _jsx("path", { d: "M21 12a9 9 0 0 0-9-9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })] })),
14
+ done: () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: [_jsx("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeWidth: "2" }), _jsx("path", { d: "m8.5 12 2.5 2.5 4.5-5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] })),
15
+ failed: () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: [_jsx("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeWidth: "2" }), _jsx("path", { d: "m9 9 6 6M15 9l-6 6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })] })),
16
+ skipped: () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: [_jsx("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeWidth: "2" }), _jsx("path", { d: "M8.5 12h7", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })] })),
17
+ };
18
+ /**
19
+ * AgentActivity — what the agent is doing, in plain language.
20
+ *
21
+ * An ordered list, because the steps happened in an order and a screen reader
22
+ * should say "3 of 7". Not a log viewer: this is the account a person reads to
23
+ * decide whether to let the run continue, so the text belongs in their
24
+ * language — "Searched the invoice archive", not `searchIndex(q, {limit:50})`.
25
+ *
26
+ * STATUS IS NEVER CARRIED BY THE ICON ALONE. Every step renders its status as
27
+ * text as well as a glyph. The glyphs differ in shape rather than only in
28
+ * colour, so the list survives greyscale, colour blindness and forced-colours
29
+ * mode — WCAG 1.4.1, which a row of coloured dots fails outright.
30
+ *
31
+ * ONE POLITE ANNOUNCEMENT PER STEP, not one per render. The active step's text
32
+ * is announced when it changes, so a user who is not watching still knows where
33
+ * the run has got to. Watching the DOM instead would re-announce on every
34
+ * unrelated update, which is the failure mode that makes people turn logs off.
35
+ */
36
+ export const AgentActivity = forwardRef(({ children, announceActive = true, className, ...rest }, ref) => {
37
+ /*
38
+ * Read the active step out of the children rather than asking the caller to
39
+ * repeat it in a prop. Two sources for one fact is how they disagree.
40
+ */
41
+ const activeLabel = React.Children.toArray(children).reduce((found, child) => {
42
+ if (found)
43
+ return found;
44
+ if (!React.isValidElement(child))
45
+ return found;
46
+ if (child.props.status !== 'active')
47
+ return found;
48
+ return typeof child.props.children === 'string'
49
+ ? child.props.children
50
+ : 'In progress';
51
+ }, '');
52
+ const [announcement, setAnnouncement] = useState('');
53
+ /*
54
+ * Seeded with '' rather than the current label, so the FIRST active step is
55
+ * announced too. Seeding it with `activeLabel` reads as "only announce
56
+ * changes" and silently swallows the one announcement that matters most —
57
+ * the log usually mounts at the moment the run starts, and that first step
58
+ * is exactly what a user who is not watching needs to hear.
59
+ */
60
+ const previous = useRef('');
61
+ useEffect(() => {
62
+ if (!announceActive)
63
+ return;
64
+ if (activeLabel && activeLabel !== previous.current)
65
+ setAnnouncement(activeLabel);
66
+ previous.current = activeLabel;
67
+ }, [activeLabel, announceActive]);
68
+ return (_jsxs(_Fragment, { children: [_jsx("ol", { ...rest, ref: ref, className: ['ion-agent-activity', className]
69
+ .filter(Boolean)
70
+ .join(' '), children: children }), announceActive && (_jsx("span", { className: "ion-visually-hidden", role: "status", "aria-live": "polite", children: announcement }))] }));
71
+ });
72
+ AgentActivity.displayName = 'AgentActivity';
73
+ export const AgentActivityStep = forwardRef(({ children, status = 'pending', detail, className, ...rest }, ref) => {
74
+ const Glyph = Glyphs[status];
75
+ return (_jsxs("li", { ...rest, ref: ref, "data-status": status, className: [
76
+ 'ion-agent-activity__step',
77
+ `ion-agent-activity__step--${status}`,
78
+ className || '',
79
+ ]
80
+ .filter(Boolean)
81
+ .join(' '), children: [_jsx("span", { className: "ion-agent-activity__glyph", "aria-hidden": "true", children: _jsx(Glyph, {}) }), _jsxs("span", { className: "ion-agent-activity__body", children: [_jsx("span", { className: "ion-agent-activity__label", children: children }), detail && _jsx("span", { className: "ion-agent-activity__detail", children: detail })] }), _jsx("span", { className: "ion-visually-hidden", children: STATUS_TEXT[status] })] }));
82
+ });
83
+ AgentActivityStep.displayName = 'AgentActivityStep';
84
+ //# sourceMappingURL=AgentActivity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentActivity.js","sourceRoot":"","sources":["../../src/components/AgentActivity.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ export type AgentStopSize = 'sm' | 'md' | 'lg';
3
+ export interface AgentStopProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'type' | 'children'> {
4
+ /** Called when the user asks the run to stop. */
5
+ onStop: () => void;
6
+ /**
7
+ * The request is in flight. The control stays visible and keeps its place;
8
+ * it does not disappear while the thing it cancels is still running.
9
+ */
10
+ isStopping?: boolean;
11
+ /** Visible label. */
12
+ label?: string;
13
+ /** Visible label once `isStopping` is set. */
14
+ stoppingLabel?: string;
15
+ size?: AgentStopSize;
16
+ /**
17
+ * Bind Escape, at the document, to stop the run.
18
+ *
19
+ * Off by default and deliberately so: Escape already means "dismiss the
20
+ * thing in front of me" to every modal, popover and menu in this system, and
21
+ * a document-level handler would cancel a background run when the user meant
22
+ * to close a dialog. Turn it on only where the run IS the foreground task.
23
+ */
24
+ stopOnEscape?: boolean;
25
+ }
26
+ /**
27
+ * AgentStop — the always-visible way to end a run.
28
+ *
29
+ * NOT OPTIONAL, AND NOT BEHIND A MENU. A user who cannot stop an agent is
30
+ * watching it, not supervising it. Human oversight of an automated process is
31
+ * a compliance surface in regulated contexts, not a UX preference, and the
32
+ * control that provides it has to be present and reachable at the moment it is
33
+ * wanted — not two clicks into an overflow menu.
34
+ *
35
+ * WHY IT IS NOT JUST `<Button variant="destructive">`
36
+ *
37
+ * Three things it owns that a Button does not:
38
+ *
39
+ * It keeps its place while stopping. A control that vanishes the instant it
40
+ * is pressed leaves the user unsure whether the press registered, and the
41
+ * run is usually still going. It stays, relabels, and disables — the layout
42
+ * does not move.
43
+ *
44
+ * It announces. The label change is only announced to a screen reader if the
45
+ * button happens to hold focus, which it usually does not when a run was
46
+ * started elsewhere. A polite live region says "Stopping" once.
47
+ *
48
+ * It is not destructive-red. Stopping is a normal, expected, reversible-in-
49
+ * spirit action — you can run it again. Colouring it like `delete` teaches
50
+ * hesitation about the one control that must never be hesitated over.
51
+ *
52
+ * WHAT IT DOES NOT DO. It does not stop anything. It reports intent; the
53
+ * caller aborts the request, closes the stream and settles the state. A stop
54
+ * button that resolves optimistically while tokens keep arriving is worse than
55
+ * none, because it lies about a guarantee the user is relying on.
56
+ */
57
+ export declare const AgentStop: React.ForwardRefExoticComponent<AgentStopProps & React.RefAttributes<HTMLButtonElement>>;
58
+ //# sourceMappingURL=AgentStop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentStop.d.ts","sourceRoot":"","sources":["../../src/components/AgentStop.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAEvE,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE/C,MAAM,WAAW,cAAe,SAAQ,IAAI,CAC1C,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAC7C,MAAM,GAAG,UAAU,CACpB;IACC,iDAAiD;IACjD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAiBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,SAAS,0FAiFrB,CAAC"}
@@ -0,0 +1,82 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { forwardRef, useEffect, useRef, useState } from 'react';
4
+ /** A square, not a glyph with meaning to learn. Universal stop. */
5
+ const StopGlyph = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("rect", { x: "6", y: "6", width: "12", height: "12", rx: "1.5", fill: "currentColor", stroke: "none" }) }));
6
+ /**
7
+ * AgentStop — the always-visible way to end a run.
8
+ *
9
+ * NOT OPTIONAL, AND NOT BEHIND A MENU. A user who cannot stop an agent is
10
+ * watching it, not supervising it. Human oversight of an automated process is
11
+ * a compliance surface in regulated contexts, not a UX preference, and the
12
+ * control that provides it has to be present and reachable at the moment it is
13
+ * wanted — not two clicks into an overflow menu.
14
+ *
15
+ * WHY IT IS NOT JUST `<Button variant="destructive">`
16
+ *
17
+ * Three things it owns that a Button does not:
18
+ *
19
+ * It keeps its place while stopping. A control that vanishes the instant it
20
+ * is pressed leaves the user unsure whether the press registered, and the
21
+ * run is usually still going. It stays, relabels, and disables — the layout
22
+ * does not move.
23
+ *
24
+ * It announces. The label change is only announced to a screen reader if the
25
+ * button happens to hold focus, which it usually does not when a run was
26
+ * started elsewhere. A polite live region says "Stopping" once.
27
+ *
28
+ * It is not destructive-red. Stopping is a normal, expected, reversible-in-
29
+ * spirit action — you can run it again. Colouring it like `delete` teaches
30
+ * hesitation about the one control that must never be hesitated over.
31
+ *
32
+ * WHAT IT DOES NOT DO. It does not stop anything. It reports intent; the
33
+ * caller aborts the request, closes the stream and settles the state. A stop
34
+ * button that resolves optimistically while tokens keep arriving is worse than
35
+ * none, because it lies about a guarantee the user is relying on.
36
+ */
37
+ export const AgentStop = forwardRef(({ onStop, isStopping = false, label = 'Stop', stoppingLabel = 'Stopping…', size = 'md', stopOnEscape = false, className, ...rest }, ref) => {
38
+ /*
39
+ * Announce the transition, not the state. A live region that always holds
40
+ * "Stopping…" is re-read on unrelated updates in some screen readers;
41
+ * writing it once on the edge, and clearing it after, says it exactly once.
42
+ */
43
+ const [announcement, setAnnouncement] = useState('');
44
+ const wasStopping = useRef(isStopping);
45
+ useEffect(() => {
46
+ if (isStopping && !wasStopping.current)
47
+ setAnnouncement(stoppingLabel);
48
+ if (!isStopping && wasStopping.current)
49
+ setAnnouncement('');
50
+ wasStopping.current = isStopping;
51
+ }, [isStopping, stoppingLabel]);
52
+ const stopRef = useRef(onStop);
53
+ stopRef.current = onStop;
54
+ useEffect(() => {
55
+ if (!stopOnEscape || isStopping)
56
+ return;
57
+ const onKeyDown = (event) => {
58
+ if (event.key !== 'Escape')
59
+ return;
60
+ // An overlay that is open owns Escape. Do not cancel a run because the
61
+ // user tried to close a dialog on top of it.
62
+ if (event.target?.closest?.('[role="dialog"]'))
63
+ return;
64
+ stopRef.current();
65
+ };
66
+ document.addEventListener('keydown', onKeyDown);
67
+ return () => document.removeEventListener('keydown', onKeyDown);
68
+ }, [stopOnEscape, isStopping]);
69
+ return (_jsxs(_Fragment, { children: [_jsxs("button", { ...rest, ref: ref, type: "button", disabled: isStopping, "data-stopping": isStopping || undefined, onClick: (event) => {
70
+ rest.onClick?.(event);
71
+ if (!event.defaultPrevented)
72
+ onStop();
73
+ }, className: [
74
+ 'ion-agent-stop',
75
+ size !== 'md' ? `ion-agent-stop--${size}` : '',
76
+ className || '',
77
+ ]
78
+ .filter(Boolean)
79
+ .join(' '), children: [_jsx("span", { className: "ion-agent-stop__glyph", children: _jsx(StopGlyph, {}) }), _jsx("span", { className: "ion-agent-stop__label", children: isStopping ? stoppingLabel : label })] }), _jsx("span", { className: "ion-agent-stop__status ion-visually-hidden", role: "status", "aria-live": "polite", children: announcement })] }));
80
+ });
81
+ AgentStop.displayName = 'AgentStop';
82
+ //# sourceMappingURL=AgentStop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentStop.js","sourceRoot":"","sources":["../../src/components/AgentStop.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ import React from 'react';
2
+ export type ApprovalGateRisk = 'low' | 'medium' | 'high';
3
+ export type ApprovalGateStatus = 'pending' | 'approved' | 'rejected' | 'expired';
4
+ export interface ApprovalGateProps extends Omit<React.HTMLAttributes<HTMLElement>, 'title' | 'onChange'> {
5
+ /**
6
+ * What is being approved, stated as the action and its object — "Delete 14
7
+ * projects", not "Confirm action". Required: it is the region's accessible
8
+ * name, and a decision the user cannot name is not a decision.
9
+ */
10
+ title: React.ReactNode;
11
+ /** Why it stopped here, and what happens on approval. */
12
+ children?: React.ReactNode;
13
+ /**
14
+ * How much is at stake. Drives emphasis only — it does NOT change what the
15
+ * component enforces, because the component enforces nothing.
16
+ */
17
+ risk?: ApprovalGateRisk;
18
+ /** Where the decision has got to. `pending` is the only state with buttons. */
19
+ status?: ApprovalGateStatus;
20
+ onApprove?: () => void;
21
+ onReject?: () => void;
22
+ /**
23
+ * Offer "edit" as a third way out. Omit it when the proposal cannot be
24
+ * amended — an approve/reject pair the user cannot influence is honest;
25
+ * an edit button that discards their edit is not.
26
+ */
27
+ onEdit?: () => void;
28
+ approveLabel?: string;
29
+ rejectLabel?: string;
30
+ editLabel?: string;
31
+ /** A decision is in flight. Both actions disable; neither disappears. */
32
+ isSubmitting?: boolean;
33
+ /** Shown in place of the actions once the decision is made. */
34
+ resolution?: React.ReactNode;
35
+ }
36
+ /**
37
+ * ApprovalGate — a proposed action, held until a person decides.
38
+ *
39
+ * The human-in-the-loop control. An agent proposes; this is where a person
40
+ * approves, rejects, or amends before anything happens. In regulated contexts
41
+ * demonstrable human oversight is a compliance surface rather than a nicety,
42
+ * which is why this is a first-class component and not a Modal with two
43
+ * buttons in it.
44
+ *
45
+ * IT ENFORCES NOTHING, AND SAYING SO IS THE POINT
46
+ *
47
+ * This renders a decision. It does not gate execution — the caller does, by not
48
+ * acting until `onApprove` fires. A component that *looked* like it enforced a
49
+ * policy would be the worst possible thing to ship here: teams would rely on a
50
+ * guarantee that lives entirely in their own call site. `risk` changes emphasis
51
+ * and nothing else, for the same reason.
52
+ *
53
+ * NOT A MODAL, DELIBERATELY
54
+ *
55
+ * A modal steals focus and hides the page. But the page is the evidence: the
56
+ * user needs the plan, the diff, the tool call and the context in front of them
57
+ * while deciding. This sits inline, keeps everything visible, and never
58
+ * traps focus — an approval a user was rushed through is not oversight.
59
+ *
60
+ * NEITHER BUTTON IS FOCUSED ON MOUNT. Autofocusing approve turns a decision
61
+ * into an Enter keypress on a page the user has not read. Focus is moved to the
62
+ * region's heading instead, so a screen-reader user lands on what is being
63
+ * asked rather than on the answer.
64
+ *
65
+ * THE RESOLVED STATES ARE NOT DECORATION. `approved`, `rejected` and `expired`
66
+ * replace the actions with what happened, so the record of the decision stays
67
+ * on the page. `expired` exists because an approval request that nobody answers
68
+ * is the common real outcome, and a gate that sits pending for ever is
69
+ * indistinguishable from one that is broken.
70
+ */
71
+ export declare const ApprovalGate: React.ForwardRefExoticComponent<ApprovalGateProps & React.RefAttributes<HTMLElement>>;
72
+ //# sourceMappingURL=ApprovalGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApprovalGate.d.ts","sourceRoot":"","sources":["../../src/components/ApprovalGate.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAyD,MAAM,OAAO,CAAC;AAE9E,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AACzD,MAAM,MAAM,kBAAkB,GAC5B,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;AAElD,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAC7C,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,EACjC,OAAO,GAAG,UAAU,CACrB;IACC;;;;OAIG;IACH,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;OAGG;IACH,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC9B;AAyBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,YAAY,uFA4HxB,CAAC"}
@@ -0,0 +1,68 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { forwardRef, useEffect, useId, useRef, useState } from 'react';
4
+ const ShieldQuestion = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: [_jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z", stroke: "currentColor", strokeWidth: "2", strokeLinejoin: "round" }), _jsx("path", { d: "M9.5 9a2.5 2.5 0 1 1 3.5 2.3c-.6.3-1 .9-1 1.7M12 16h.01", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })] }));
5
+ const STATUS_TEXT = {
6
+ approved: 'Approved',
7
+ rejected: 'Rejected',
8
+ expired: 'Expired without a decision',
9
+ };
10
+ /**
11
+ * ApprovalGate — a proposed action, held until a person decides.
12
+ *
13
+ * The human-in-the-loop control. An agent proposes; this is where a person
14
+ * approves, rejects, or amends before anything happens. In regulated contexts
15
+ * demonstrable human oversight is a compliance surface rather than a nicety,
16
+ * which is why this is a first-class component and not a Modal with two
17
+ * buttons in it.
18
+ *
19
+ * IT ENFORCES NOTHING, AND SAYING SO IS THE POINT
20
+ *
21
+ * This renders a decision. It does not gate execution — the caller does, by not
22
+ * acting until `onApprove` fires. A component that *looked* like it enforced a
23
+ * policy would be the worst possible thing to ship here: teams would rely on a
24
+ * guarantee that lives entirely in their own call site. `risk` changes emphasis
25
+ * and nothing else, for the same reason.
26
+ *
27
+ * NOT A MODAL, DELIBERATELY
28
+ *
29
+ * A modal steals focus and hides the page. But the page is the evidence: the
30
+ * user needs the plan, the diff, the tool call and the context in front of them
31
+ * while deciding. This sits inline, keeps everything visible, and never
32
+ * traps focus — an approval a user was rushed through is not oversight.
33
+ *
34
+ * NEITHER BUTTON IS FOCUSED ON MOUNT. Autofocusing approve turns a decision
35
+ * into an Enter keypress on a page the user has not read. Focus is moved to the
36
+ * region's heading instead, so a screen-reader user lands on what is being
37
+ * asked rather than on the answer.
38
+ *
39
+ * THE RESOLVED STATES ARE NOT DECORATION. `approved`, `rejected` and `expired`
40
+ * replace the actions with what happened, so the record of the decision stays
41
+ * on the page. `expired` exists because an approval request that nobody answers
42
+ * is the common real outcome, and a gate that sits pending for ever is
43
+ * indistinguishable from one that is broken.
44
+ */
45
+ export const ApprovalGate = forwardRef(({ title, children, risk = 'medium', status = 'pending', onApprove, onReject, onEdit, approveLabel = 'Approve', rejectLabel = 'Reject', editLabel = 'Edit', isSubmitting = false, resolution, className, ...rest }, ref) => {
46
+ const headingRef = useRef(null);
47
+ // A <section> is only a landmark once it has a name, and the name a
48
+ // reviewer needs is the decision itself.
49
+ const titleId = useId();
50
+ const [announcement, setAnnouncement] = useState('');
51
+ const previous = useRef(status);
52
+ useEffect(() => {
53
+ if (status !== previous.current && status !== 'pending')
54
+ setAnnouncement(STATUS_TEXT[status]);
55
+ previous.current = status;
56
+ }, [status]);
57
+ const pending = status === 'pending';
58
+ return (_jsxs("section", { ...rest, ref: ref, "aria-labelledby": titleId, "data-risk": risk, "data-status": status, className: [
59
+ 'ion-approval-gate',
60
+ `ion-approval-gate--${risk}`,
61
+ !pending ? `ion-approval-gate--${status}` : '',
62
+ className || '',
63
+ ]
64
+ .filter(Boolean)
65
+ .join(' '), children: [_jsx("span", { className: "ion-approval-gate__icon", "aria-hidden": "true", children: _jsx(ShieldQuestion, {}) }), _jsxs("div", { className: "ion-approval-gate__body", children: [_jsx("p", { ref: headingRef, id: titleId, tabIndex: -1, className: "ion-approval-gate__title", children: title }), children && (_jsx("div", { className: "ion-approval-gate__detail", children: children })), pending ? (_jsxs("div", { className: "ion-approval-gate__actions", children: [_jsx("button", { type: "button", className: "ion-approval-gate__action ion-approval-gate__action--reject", disabled: isSubmitting || !onReject, onClick: onReject, children: rejectLabel }), onEdit && (_jsx("button", { type: "button", className: "ion-approval-gate__action ion-approval-gate__action--edit", disabled: isSubmitting, onClick: onEdit, children: editLabel })), _jsx("button", { type: "button", className: "ion-approval-gate__action ion-approval-gate__action--approve", disabled: isSubmitting || !onApprove, onClick: onApprove, children: approveLabel })] })) : (_jsx("p", { className: "ion-approval-gate__resolution", children: resolution ?? STATUS_TEXT[status] }))] }), _jsx("span", { className: "ion-approval-gate__status ion-visually-hidden", role: "status", "aria-live": "polite", children: announcement })] }));
66
+ });
67
+ ApprovalGate.displayName = 'ApprovalGate';
68
+ //# sourceMappingURL=ApprovalGate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApprovalGate.js","sourceRoot":"","sources":["../../src/components/ApprovalGate.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+ export interface CitationProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'children'> {
3
+ /** The marker shown inline — usually a number matching the footer list. */
4
+ index: number | string;
5
+ /**
6
+ * What is being cited. Required: it is the link's accessible name, and a
7
+ * citation a reader cannot identify without following it is not attribution.
8
+ */
9
+ source: string;
10
+ /** Where it goes. Omit for a source with no address — a document, a call. */
11
+ href?: string;
12
+ }
13
+ export interface CitationListProps extends React.OlHTMLAttributes<HTMLOListElement> {
14
+ children?: React.ReactNode;
15
+ /** Heading above the list. Rendered as plain text, not a heading element. */
16
+ label?: React.ReactNode;
17
+ }
18
+ export interface CitationListItemProps extends React.LiHTMLAttributes<HTMLLIElement> {
19
+ index: number | string;
20
+ source: string;
21
+ href?: string;
22
+ /** The quoted or summarised passage this citation supports. */
23
+ children?: React.ReactNode;
24
+ }
25
+ /**
26
+ * Citation — the inline marker.
27
+ *
28
+ * THE MARKER IS NOT THE NAME. Rendered naively, a superscript "1" announces as
29
+ * "link, 1", which tells a screen-reader user nothing about whether to follow
30
+ * it. The visible marker stays a number; the accessible name is
31
+ * "Source 1: <source>". The number is for the sighted reader's eye and the
32
+ * sentence is for everyone.
33
+ *
34
+ * NOT A TOOLTIP. A tooltip cannot be reached on touch and closes on the way to
35
+ * it; attribution has to survive both. It is a real link, or a real
36
+ * non-interactive marker when there is nowhere to go.
37
+ *
38
+ * WITHOUT `href` IT IS NOT A LINK. A citation to a phone call or an internal
39
+ * document has no address, and rendering a dead anchor for it puts an
40
+ * unfollowable link in the page's link list. It becomes a plain marked-up
41
+ * reference instead.
42
+ */
43
+ export declare const Citation: React.ForwardRefExoticComponent<CitationProps & React.RefAttributes<HTMLAnchorElement>>;
44
+ /**
45
+ * The footer list. An `<ol>` so the numbering is structural rather than typed
46
+ * into each row, and so a screen reader can say how many sources there are
47
+ * before the reader commits to hearing them.
48
+ */
49
+ export declare const CitationList: React.ForwardRefExoticComponent<CitationListProps & React.RefAttributes<HTMLOListElement>>;
50
+ export declare const CitationListItem: React.ForwardRefExoticComponent<CitationListItemProps & React.RefAttributes<HTMLLIElement>>;
51
+ //# sourceMappingURL=Citation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Citation.d.ts","sourceRoot":"","sources":["../../src/components/Citation.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAE1C,MAAM,WAAW,aAAc,SAAQ,IAAI,CACzC,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAC7C,UAAU,CACX;IACC,2EAA2E;IAC3E,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAkB,SAAQ,KAAK,CAAC,gBAAgB,CAAC,gBAAgB,CAAC;IACjF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,6EAA6E;IAC7E,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACzB;AAED,MAAM,WAAW,qBAAsB,SAAQ,KAAK,CAAC,gBAAgB,CAAC,aAAa,CAAC;IAClF,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,QAAQ,yFAmBpB,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,YAAY,4FAexB,CAAC;AAIF,eAAO,MAAM,gBAAgB,6FAyB3B,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef } from 'react';
3
+ /**
4
+ * Citation — the inline marker.
5
+ *
6
+ * THE MARKER IS NOT THE NAME. Rendered naively, a superscript "1" announces as
7
+ * "link, 1", which tells a screen-reader user nothing about whether to follow
8
+ * it. The visible marker stays a number; the accessible name is
9
+ * "Source 1: <source>". The number is for the sighted reader's eye and the
10
+ * sentence is for everyone.
11
+ *
12
+ * NOT A TOOLTIP. A tooltip cannot be reached on touch and closes on the way to
13
+ * it; attribution has to survive both. It is a real link, or a real
14
+ * non-interactive marker when there is nowhere to go.
15
+ *
16
+ * WITHOUT `href` IT IS NOT A LINK. A citation to a phone call or an internal
17
+ * document has no address, and rendering a dead anchor for it puts an
18
+ * unfollowable link in the page's link list. It becomes a plain marked-up
19
+ * reference instead.
20
+ */
21
+ export const Citation = forwardRef(({ index, source, href, className, ...rest }, ref) => {
22
+ const name = `Source ${index}: ${source}`;
23
+ const classes = ['ion-citation', className].filter(Boolean).join(' ');
24
+ if (!href) {
25
+ return (_jsx("span", { className: classes, role: "note", "aria-label": name, children: _jsx("span", { "aria-hidden": "true", children: index }) }));
26
+ }
27
+ return (_jsx("a", { ...rest, ref: ref, href: href, className: classes, "aria-label": name, children: _jsx("span", { "aria-hidden": "true", children: index }) }));
28
+ });
29
+ Citation.displayName = 'Citation';
30
+ /**
31
+ * The footer list. An `<ol>` so the numbering is structural rather than typed
32
+ * into each row, and so a screen reader can say how many sources there are
33
+ * before the reader commits to hearing them.
34
+ */
35
+ export const CitationList = forwardRef(({ children, label = 'Sources', className, ...rest }, ref) => (_jsxs("div", { className: "ion-citation-list", children: [label && _jsx("p", { className: "ion-citation-list__label", children: label }), _jsx("ol", { ...rest, ref: ref, className: ['ion-citation-list__items', className]
36
+ .filter(Boolean)
37
+ .join(' '), children: children })] })));
38
+ CitationList.displayName = 'CitationList';
39
+ export const CitationListItem = forwardRef(({ index, source, href, children, className, ...rest }, ref) => (_jsxs("li", { ...rest, ref: ref, className: ['ion-citation-list__item', className].filter(Boolean).join(' '), children: [_jsx("span", { className: "ion-citation-list__marker", "aria-hidden": "true", children: index }), _jsxs("span", { className: "ion-citation-list__body", children: [href ? (_jsx("a", { className: "ion-citation-list__source", href: href, children: source })) : (_jsx("span", { className: "ion-citation-list__source", children: source })), children && (_jsx("span", { className: "ion-citation-list__passage", children: children }))] })] })));
40
+ CitationListItem.displayName = 'CitationListItem';
41
+ //# sourceMappingURL=Citation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Citation.js","sourceRoot":"","sources":["../../src/components/Citation.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AA+B1C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAChC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE;IACnD,MAAM,IAAI,GAAG,UAAU,KAAK,KAAK,MAAM,EAAE,CAAC;IAC1C,MAAM,OAAO,GAAG,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEtE,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CACL,eAAM,SAAS,EAAE,OAAO,EAAE,IAAI,EAAC,MAAM,gBAAa,IAAI,YACpD,8BAAkB,MAAM,YAAE,KAAK,GAAQ,GAClC,CACR,CAAC;IACJ,CAAC;IAED,OAAO,CACL,eAAO,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,gBAAc,IAAI,YACrE,8BAAkB,MAAM,YAAE,KAAK,GAAQ,GACrC,CACL,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,QAAQ,CAAC,WAAW,GAAG,UAAU,CAAC;AAElC;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CACpC,CAAC,EAAE,QAAQ,EAAE,KAAK,GAAG,SAAS,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAC5D,eAAK,SAAS,EAAC,mBAAmB,aAC/B,KAAK,IAAI,YAAG,SAAS,EAAC,0BAA0B,YAAE,KAAK,GAAK,EAC7D,gBACM,IAAI,EACR,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,CAAC,0BAA0B,EAAE,SAAS,CAAC;iBAC/C,MAAM,CAAC,OAAO,CAAC;iBACf,IAAI,CAAC,GAAG,CAAC,YAEX,QAAQ,GACN,IACD,CACP,CACF,CAAC;AAEF,YAAY,CAAC,WAAW,GAAG,cAAc,CAAC;AAE1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAGxC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAChE,iBACM,IAAI,EACR,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,CAAC,yBAAyB,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,aAE3E,eAAM,SAAS,EAAC,2BAA2B,iBAAa,MAAM,YAC3D,KAAK,GACD,EACP,gBAAM,SAAS,EAAC,yBAAyB,aACtC,IAAI,CAAC,CAAC,CAAC,CACN,YAAG,SAAS,EAAC,2BAA2B,EAAC,IAAI,EAAE,IAAI,YAChD,MAAM,GACL,CACL,CAAC,CAAC,CAAC,CACF,eAAM,SAAS,EAAC,2BAA2B,YAAE,MAAM,GAAQ,CAC5D,EACA,QAAQ,IAAI,CACX,eAAM,SAAS,EAAC,4BAA4B,YAAE,QAAQ,GAAQ,CAC/D,IACI,IACJ,CACN,CAAC,CAAC;AAEH,gBAAgB,CAAC,WAAW,GAAG,kBAAkB,CAAC"}
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ export type ConfidenceLevel = 'low' | 'medium' | 'high';
3
+ export interface ConfidenceIndicatorProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'children'> {
4
+ level: ConfidenceLevel;
5
+ /**
6
+ * What the level is based on. REQUIRED, and the reason this component exists
7
+ * rather than a coloured dot: a confidence with no stated basis is a number
8
+ * the reader has no way to weigh. "3 of 4 sources agree", "no matching
9
+ * records found", "single unverified source".
10
+ */
11
+ basis: string;
12
+ /** Override the level's word. Keep it a word, not a percentage. */
13
+ label?: string;
14
+ }
15
+ /**
16
+ * ConfidenceIndicator — how much to trust the thing next to it.
17
+ *
18
+ * THERE IS NO PERCENTAGE PROP, AND THERE WILL NOT BE ONE
19
+ *
20
+ * "87% confident" reads as a measurement. Almost nowhere is it one: it is
21
+ * usually a softmax score, a heuristic, or a number a model produced about
22
+ * itself — none of which are calibrated probabilities, and all of which invite
23
+ * a reader to treat two digits of precision as real. Three levels cannot
24
+ * overclaim in that way.
25
+ *
26
+ * `basis` IS REQUIRED FOR THE SAME REASON. A level with nothing behind it is
27
+ * decoration that changes behaviour: people act on "high confidence" whether or
28
+ * not anything justifies it. Making the justification a required prop is the
29
+ * only enforcement available here, and it is a type error rather than a policy
30
+ * — which is the strongest kind this system can offer.
31
+ *
32
+ * It renders as text plus a three-bar meter, never the meter alone. The bars
33
+ * differ in filled COUNT, not only in colour, so the reading survives greyscale
34
+ * and forced-colours mode.
35
+ */
36
+ export declare const ConfidenceIndicator: React.ForwardRefExoticComponent<ConfidenceIndicatorProps & React.RefAttributes<HTMLSpanElement>>;
37
+ //# sourceMappingURL=ConfidenceIndicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfidenceIndicator.d.ts","sourceRoot":"","sources":["../../src/components/ConfidenceIndicator.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAE1C,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CACpD,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC,EACrC,UAAU,CACX;IACC,KAAK,EAAE,eAAe,CAAC;IACvB;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAQD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mBAAmB,kGAiC9B,CAAC"}