@nucleux/connectors 0.0.0-stage → 0.7.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,43 @@
1
- # Temporary Holding Version
1
+ # @nucleux/connectors
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
+ Connector — enable an external tool or data connector — 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
+ ## Exports
8
+
9
+ - **`Connector`** — one service: `name`, `description`, `icon`, `connected`, `onConnect`, `onDisconnect`, `connectLabel`, `disconnectLabel`, plus
10
+ - `status` (`"disconnected"` | `"connecting"` | `"connected"` | `"expired"` | `"error"`; overrides `connected`), announced politely
11
+ - `scopes` — what the agent will be able to do, in plain verbs, shown before connecting
12
+ - `account` — who the sign-in is with, shown once connected ("You can disconnect at any time")
13
+ - `onReconnect` — for an expired sign-in (falls back to `onConnect`); `error`
14
+ - **`ConnectorList`** (variant `connector-list`) — a list of Connector cards (`label`, default "Connected services").
15
+ - **`ConnectorScopePicker`** (variant `scope-picker`) — "Aria can read from:" with a checkbox per channel, folder or repo, starting from nothing; `allowWrite` / `onAllowWriteChange` asks for write access as a separate switch.
16
+ - **`ConnectorLivePill`** (variant `live-source-pill`) — "Reading 12 docs from Drive…", pulsing (the pulse stops under reduced motion), announced politely.
17
+ - Types: `ConnectorProps`, `ConnectorStatus`, `ConnectorListProps`, `ConnectorScope`, `ConnectorScopePickerProps`, `ConnectorLivePillProps`.
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ pnpm add @nucleux/connectors @nucleux/tokens
23
+ ```
24
+
25
+ `react` / `react-dom` are peer dependencies.
26
+
27
+ ## Usage
28
+
29
+ ```tsx
30
+ import { Connector, ConnectorList, ConnectorScopePicker, ConnectorLivePill } from "@nucleux/connectors";
31
+
32
+ <ConnectorList>
33
+ <Connector name="Google Drive" connected account="sam@acme.com" onDisconnect={disconnect} />
34
+ <Connector name="Slack" scopes={["Read channels you choose"]} onConnect={connectSlack} />
35
+ </ConnectorList>
36
+ ```
37
+
38
+ Requires the theme once in your app: `import "@nucleux/tokens/styles.css";`
39
+ and the Tailwind preset from `@nucleux/tokens/preset`.
40
+
41
+ ## License
42
+
43
+ MIT © Nucleux
package/dist/index.cjs ADDED
@@ -0,0 +1,247 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var React = require('react');
5
+ var utils = require('@nucleux/utils');
6
+ var button = require('@nucleux/button');
7
+ var checkbox = require('@nucleux/checkbox');
8
+ var spinner = require('@nucleux/spinner');
9
+ var _switch = require('@nucleux/switch');
10
+ var lucideReact = require('lucide-react');
11
+ var jsxRuntime = require('react/jsx-runtime');
12
+
13
+ function _interopNamespace(e) {
14
+ if (e && e.__esModule) return e;
15
+ var n = Object.create(null);
16
+ if (e) {
17
+ Object.keys(e).forEach(function (k) {
18
+ if (k !== 'default') {
19
+ var d = Object.getOwnPropertyDescriptor(e, k);
20
+ Object.defineProperty(n, k, d.get ? d : {
21
+ enumerable: true,
22
+ get: function () { return e[k]; }
23
+ });
24
+ }
25
+ });
26
+ }
27
+ n.default = e;
28
+ return Object.freeze(n);
29
+ }
30
+
31
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
32
+
33
+ // src/index.tsx
34
+ var statusText = {
35
+ connecting: "Connecting\u2026",
36
+ expired: "Sign-in expired",
37
+ error: "Couldn't connect"
38
+ };
39
+ var Connector = React__namespace.forwardRef(
40
+ ({
41
+ name,
42
+ description,
43
+ icon,
44
+ connected = false,
45
+ status: statusProp,
46
+ onConnect,
47
+ onDisconnect,
48
+ onReconnect,
49
+ connectLabel = "Connect",
50
+ disconnectLabel = "Disconnect",
51
+ scopes,
52
+ account,
53
+ error,
54
+ className,
55
+ ...props
56
+ }, ref) => {
57
+ const status = statusProp ?? (connected ? "connected" : "disconnected");
58
+ const reconnect = onReconnect ?? onConnect;
59
+ return /* @__PURE__ */ jsxRuntime.jsxs(
60
+ "div",
61
+ {
62
+ ref,
63
+ "data-status": status,
64
+ className: utils.cn(
65
+ "flex flex-col gap-3 rounded-xl border border-border bg-background p-4",
66
+ status === "expired" && "border-warning/50",
67
+ status === "error" && "border-destructive/50",
68
+ className
69
+ ),
70
+ ...props,
71
+ children: [
72
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
73
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg]:size-5", children: icon ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plug, { "aria-hidden": "true" }) }),
74
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
75
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground", children: name }),
76
+ description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: description })
77
+ ] }),
78
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { role: "status", "aria-live": "polite", className: "contents", children: [
79
+ status === "connected" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex shrink-0 items-center gap-1 rounded-full bg-success/15 px-2 py-0.5 text-xs font-medium text-success [&_svg]:size-3.5", children: [
80
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { "aria-hidden": "true" }),
81
+ "Connected"
82
+ ] }),
83
+ status === "connecting" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground", children: [
84
+ /* @__PURE__ */ jsxRuntime.jsx(spinner.Spinner, { "aria-hidden": "true", role: void 0, className: "size-3.5 motion-reduce:animate-none" }),
85
+ statusText.connecting
86
+ ] }),
87
+ status === "expired" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 rounded-full bg-warning/15 px-2 py-0.5 text-xs font-medium text-warning", children: statusText.expired }),
88
+ status === "error" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 rounded-full bg-destructive/15 px-2 py-0.5 text-xs font-medium text-destructive", children: statusText.error })
89
+ ] }),
90
+ status === "connected" && onDisconnect && /* @__PURE__ */ jsxRuntime.jsx(
91
+ "button",
92
+ {
93
+ type: "button",
94
+ onClick: onDisconnect,
95
+ className: "shrink-0 rounded-md px-2 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
96
+ children: disconnectLabel
97
+ }
98
+ ),
99
+ status === "disconnected" && /* @__PURE__ */ jsxRuntime.jsx(
100
+ "button",
101
+ {
102
+ type: "button",
103
+ onClick: onConnect,
104
+ className: "inline-flex shrink-0 items-center rounded-lg border border-border bg-background px-3 py-1.5 text-sm font-medium text-foreground shadow-sm transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
105
+ children: connectLabel
106
+ }
107
+ ),
108
+ (status === "expired" || status === "error") && reconnect && /* @__PURE__ */ jsxRuntime.jsx(button.Button, { size: "sm", variant: "secondary", onClick: reconnect, className: "shrink-0", children: status === "expired" ? "Reconnect" : "Try again" })
109
+ ] }),
110
+ status === "error" && error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive", children: error }),
111
+ status === "expired" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground", children: [
112
+ "Nothing was lost \u2014 sign in again",
113
+ account ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
114
+ " as ",
115
+ account
116
+ ] }) : null,
117
+ " to keep reading from ",
118
+ name,
119
+ "."
120
+ ] }),
121
+ (status === "disconnected" || status === "connecting") && scopes && scopes.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 border-t border-border pt-3", children: [
122
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium text-foreground", children: "If you connect, the agent can:" }),
123
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-0.5 text-xs text-muted-foreground", children: scopes.map((scope, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start gap-1.5", children: [
124
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { "aria-hidden": "true", className: "mt-0.5 size-3 shrink-0 text-muted-foreground" }),
125
+ scope
126
+ ] }, i)) })
127
+ ] }),
128
+ status === "connected" && account && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground", children: [
129
+ "Signed in as ",
130
+ account,
131
+ ". You can disconnect at any time."
132
+ ] })
133
+ ]
134
+ }
135
+ );
136
+ }
137
+ );
138
+ Connector.displayName = "Connector";
139
+ var ConnectorList = React__namespace.forwardRef(
140
+ ({ label = "Connected services", className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, role: "list", "aria-label": label, className: utils.cn("flex flex-col gap-2", className), ...props, children: React__namespace.Children.map(
141
+ children,
142
+ (child) => child == null || child === false ? null : /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listitem", children: child })
143
+ ) })
144
+ );
145
+ ConnectorList.displayName = "ConnectorList";
146
+ var ConnectorScopePicker = React__namespace.forwardRef(
147
+ ({
148
+ scopes,
149
+ value,
150
+ defaultValue = [],
151
+ onValueChange,
152
+ agentName = "Aria",
153
+ title,
154
+ allowWrite,
155
+ onAllowWriteChange,
156
+ writeLabel = "Also allow changes (create, edit, post)",
157
+ className,
158
+ ...props
159
+ }, ref) => {
160
+ const [internal, setInternal] = React__namespace.useState(defaultValue);
161
+ const granted = value !== void 0 ? value : internal;
162
+ const headingId = React__namespace.useId();
163
+ const set = (id, on) => {
164
+ const next = on ? [...granted, id] : granted.filter((g) => g !== id);
165
+ if (value === void 0) setInternal(next);
166
+ onValueChange?.(next);
167
+ };
168
+ return /* @__PURE__ */ jsxRuntime.jsxs(
169
+ "div",
170
+ {
171
+ ref,
172
+ role: "group",
173
+ "aria-labelledby": headingId,
174
+ className: utils.cn("flex flex-col gap-2 rounded-xl border border-border bg-background p-3", className),
175
+ ...props,
176
+ children: [
177
+ /* @__PURE__ */ jsxRuntime.jsx("p", { id: headingId, className: "text-sm font-semibold text-foreground", children: title ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
178
+ agentName,
179
+ " can read from:"
180
+ ] }) }),
181
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-1.5", children: scopes.map((scope) => {
182
+ const on = granted.includes(scope.id);
183
+ const labelId = `${headingId}-${scope.id}`;
184
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex cursor-pointer items-center gap-2 text-sm", children: [
185
+ /* @__PURE__ */ jsxRuntime.jsx(checkbox.Checkbox, { checked: on, onCheckedChange: (c) => set(scope.id, c), "aria-labelledby": labelId }),
186
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { id: labelId, className: utils.cn(on ? "text-foreground" : "text-muted-foreground"), children: [
187
+ scope.label,
188
+ scope.description && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
189
+ " \xB7 ",
190
+ scope.description
191
+ ] })
192
+ ] })
193
+ ] }) }, scope.id);
194
+ }) }),
195
+ (allowWrite !== void 0 || onAllowWriteChange) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-border pt-2", children: [
196
+ /* @__PURE__ */ jsxRuntime.jsx("span", { id: `${headingId}-write`, className: "text-sm text-foreground", children: writeLabel }),
197
+ /* @__PURE__ */ jsxRuntime.jsx(
198
+ _switch.Switch,
199
+ {
200
+ size: "sm",
201
+ checked: allowWrite ?? false,
202
+ onCheckedChange: onAllowWriteChange,
203
+ "aria-labelledby": `${headingId}-write`
204
+ }
205
+ )
206
+ ] })
207
+ ]
208
+ }
209
+ );
210
+ }
211
+ );
212
+ ConnectorScopePicker.displayName = "ConnectorScopePicker";
213
+ var ConnectorLivePill = React__namespace.forwardRef(
214
+ ({ source, count, noun = "docs", className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
215
+ "span",
216
+ {
217
+ ref,
218
+ role: "status",
219
+ "aria-live": "polite",
220
+ className: utils.cn(
221
+ "inline-flex items-center gap-2 rounded-full border border-brand/50 bg-brand-muted/50 px-3 py-1 text-xs font-semibold text-brand",
222
+ className
223
+ ),
224
+ ...props,
225
+ children: [
226
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "size-2 rounded-full bg-brand animate-pulse motion-reduce:animate-none" }),
227
+ children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
228
+ "Reading",
229
+ count != null ? ` ${count} ${noun}` : "",
230
+ source ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
231
+ " from ",
232
+ source
233
+ ] }) : null,
234
+ "\u2026"
235
+ ] })
236
+ ]
237
+ }
238
+ )
239
+ );
240
+ ConnectorLivePill.displayName = "ConnectorLivePill";
241
+
242
+ exports.Connector = Connector;
243
+ exports.ConnectorList = ConnectorList;
244
+ exports.ConnectorLivePill = ConnectorLivePill;
245
+ exports.ConnectorScopePicker = ConnectorScopePicker;
246
+ //# sourceMappingURL=index.cjs.map
247
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.tsx"],"names":["React","jsxs","cn","jsx","Plug","Check","Spinner","Button","Fragment","Checkbox","Switch"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@nucleux/utils\";\nimport { Button } from \"@nucleux/button\";\nimport { Checkbox } from \"@nucleux/checkbox\";\nimport { Spinner } from \"@nucleux/spinner\";\nimport { Switch } from \"@nucleux/switch\";\nimport { Plug, Check } from \"lucide-react\";\n\n/** Connection state. `expired` is the sign-in people meet most often: connected once, needs signing in again. */\nexport type ConnectorStatus = \"disconnected\" | \"connecting\" | \"connected\" | \"expired\" | \"error\";\n\nexport interface ConnectorProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Connector name, e.g. `\"GitHub\"`. */\n name: React.ReactNode;\n /** What the connector gives the agent access to. */\n description?: React.ReactNode;\n /** Connector logo/icon. Defaults to a plug glyph. */\n icon?: React.ReactNode;\n /** Whether the connector is already connected. Shorthand for `status=\"connected\"`. */\n connected?: boolean;\n /** Full connection state; overrides `connected` when set. */\n status?: ConnectorStatus;\n /** Called to connect. Renders the connect button when set and not connected. */\n onConnect?: () => void;\n /** Called to disconnect. Renders a manage/disconnect control when connected. */\n onDisconnect?: () => void;\n /** Called to sign in again when `status` is `\"expired\"` or `\"error\"`. Falls back to `onConnect`. */\n onReconnect?: () => void;\n /** Label for the connect action. Defaults to a localized \"Connect\". */\n connectLabel?: React.ReactNode;\n /** Label for the disconnect action. Defaults to a localized \"Disconnect\". */\n disconnectLabel?: React.ReactNode;\n /** What the agent will be able to do, in plain verbs — shown before the handoff, e.g. `[\"Read files in folders you choose\", \"Search file names\"]`. */\n scopes?: React.ReactNode[];\n /** Who the sign-in is with, e.g. `\"sam@acme.com\"`. Shown once connected. */\n account?: React.ReactNode;\n /** What went wrong, when `status` is `\"error\"`. */\n error?: React.ReactNode;\n}\n\nconst statusText: Record<Exclude<ConnectorStatus, \"disconnected\">, string> = {\n connecting: \"Connecting…\",\n connected: \"Connected\",\n expired: \"Sign-in expired\",\n error: \"Couldn't connect\",\n};\n\n/**\n * A card to enable an external tool or data connector for the agent — icon,\n * name, what it unlocks, and a connect action. Before connecting it can list\n * the scopes in plain verbs (never over-grant); once connected it says who the\n * sign-in is with and that access can be withdrawn. Status is a word, announced\n * politely: Connecting…, Connected, Sign-in expired (with Reconnect), Couldn't\n * connect. Group several in a ConnectorList; narrow access with\n * ConnectorScopePicker; show live reads with ConnectorLivePill.\n * Source: Figma \"Context Expansion / Connector suggestion card\".\n */\nexport const Connector = React.forwardRef<HTMLDivElement, ConnectorProps>(\n (\n {\n name,\n description,\n icon,\n connected = false,\n status: statusProp,\n onConnect,\n onDisconnect,\n onReconnect,\n connectLabel = \"Connect\",\n disconnectLabel = \"Disconnect\",\n scopes,\n account,\n error,\n className,\n ...props\n },\n ref,\n ) => {\n const status: ConnectorStatus = statusProp ?? (connected ? \"connected\" : \"disconnected\");\n const reconnect = onReconnect ?? onConnect;\n return (\n <div\n ref={ref}\n data-status={status}\n className={cn(\n \"flex flex-col gap-3 rounded-xl border border-border bg-background p-4\",\n status === \"expired\" && \"border-warning/50\",\n status === \"error\" && \"border-destructive/50\",\n className,\n )}\n {...props}\n >\n <div className=\"flex items-center gap-3\">\n <span className=\"inline-flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg]:size-5\">\n {icon ?? <Plug aria-hidden=\"true\" />}\n </span>\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <span className=\"text-sm font-medium text-foreground\">{name}</span>\n {description && <span className=\"text-xs text-muted-foreground\">{description}</span>}\n </div>\n <span role=\"status\" aria-live=\"polite\" className=\"contents\">\n {status === \"connected\" && (\n <span className=\"inline-flex shrink-0 items-center gap-1 rounded-full bg-success/15 px-2 py-0.5 text-xs font-medium text-success [&_svg]:size-3.5\">\n <Check aria-hidden=\"true\" />\n Connected\n </span>\n )}\n {status === \"connecting\" && (\n <span className=\"inline-flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground\">\n <Spinner aria-hidden=\"true\" role={undefined} className=\"size-3.5 motion-reduce:animate-none\" />\n {statusText.connecting}\n </span>\n )}\n {status === \"expired\" && (\n <span className=\"shrink-0 rounded-full bg-warning/15 px-2 py-0.5 text-xs font-medium text-warning\">\n {statusText.expired}\n </span>\n )}\n {status === \"error\" && (\n <span className=\"shrink-0 rounded-full bg-destructive/15 px-2 py-0.5 text-xs font-medium text-destructive\">\n {statusText.error}\n </span>\n )}\n </span>\n {status === \"connected\" && onDisconnect && (\n <button\n type=\"button\"\n onClick={onDisconnect}\n className=\"shrink-0 rounded-md px-2 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {disconnectLabel}\n </button>\n )}\n {status === \"disconnected\" && (\n <button\n type=\"button\"\n onClick={onConnect}\n className=\"inline-flex shrink-0 items-center rounded-lg border border-border bg-background px-3 py-1.5 text-sm font-medium text-foreground shadow-sm transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {connectLabel}\n </button>\n )}\n {(status === \"expired\" || status === \"error\") && reconnect && (\n <Button size=\"sm\" variant=\"secondary\" onClick={reconnect} className=\"shrink-0\">\n {status === \"expired\" ? \"Reconnect\" : \"Try again\"}\n </Button>\n )}\n </div>\n {status === \"error\" && error && <p className=\"text-xs text-destructive\">{error}</p>}\n {status === \"expired\" && (\n <p className=\"text-xs text-muted-foreground\">\n Nothing was lost — sign in again{account ? <> as {account}</> : null} to keep reading from {name}.\n </p>\n )}\n {(status === \"disconnected\" || status === \"connecting\") && scopes && scopes.length > 0 && (\n <div className=\"flex flex-col gap-1 border-t border-border pt-3\">\n <p className=\"text-xs font-medium text-foreground\">If you connect, the agent can:</p>\n <ul className=\"flex flex-col gap-0.5 text-xs text-muted-foreground\">\n {scopes.map((scope, i) => (\n <li key={i} className=\"flex items-start gap-1.5\">\n <Check aria-hidden=\"true\" className=\"mt-0.5 size-3 shrink-0 text-muted-foreground\" />\n {scope}\n </li>\n ))}\n </ul>\n </div>\n )}\n {status === \"connected\" && account && (\n <p className=\"text-xs text-muted-foreground\">\n Signed in as {account}. You can disconnect at any time.\n </p>\n )}\n </div>\n );\n },\n);\nConnector.displayName = \"Connector\";\n\nexport interface ConnectorListProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Accessible name. Defaults to `\"Connected services\"`. */\n label?: string;\n}\n\n/**\n * The connector list: available services with their status and a connect\n * button, one per row. Wrap Connector cards; each child becomes a list item.\n */\nexport const ConnectorList = React.forwardRef<HTMLDivElement, ConnectorListProps>(\n ({ label = \"Connected services\", className, children, ...props }, ref) => (\n <div ref={ref} role=\"list\" aria-label={label} className={cn(\"flex flex-col gap-2\", className)} {...props}>\n {React.Children.map(children, (child) =>\n child == null || child === false ? null : <div role=\"listitem\">{child}</div>,\n )}\n </div>\n ),\n);\nConnectorList.displayName = \"ConnectorList\";\n\n/** One thing the agent could read: a channel, folder, repo or branch. */\nexport interface ConnectorScope {\n /** Stable id. */\n id: string;\n /** Label, e.g. `\"#renewals\"`. */\n label: React.ReactNode;\n /** Optional detail, e.g. `\"412 messages\"`. */\n description?: React.ReactNode;\n}\n\nexport interface ConnectorScopePickerProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\" | \"defaultValue\" | \"onChange\"> {\n /** The scopes on offer. */\n scopes: ConnectorScope[];\n /** Granted scope ids (controlled). */\n value?: string[];\n /** Initial grant (uncontrolled). Defaults to none — least privilege. */\n defaultValue?: string[];\n /** Called with the granted ids. */\n onValueChange?: (ids: string[]) => void;\n /** Who reads. Defaults to `\"Aria\"`. */\n agentName?: React.ReactNode;\n /** Heading override. Defaults to `\"<agent> can read from:\"`. */\n title?: React.ReactNode;\n /** Write access, asked separately (controlled). Renders the write switch when this or `onAllowWriteChange` is set. */\n allowWrite?: boolean;\n /** Called when write access is switched. */\n onAllowWriteChange?: (on: boolean) => void;\n /** Label for the write switch. Defaults to `\"Also allow changes (create, edit, post)\"`. */\n writeLabel?: React.ReactNode;\n}\n\n/**\n * The scope picker: exactly what the agent can read — workspace, channel,\n * folder, repo — granular rather than all-or-nothing, starting from nothing.\n * Write access, when offered, is a separate and visible question.\n */\nexport const ConnectorScopePicker = React.forwardRef<HTMLDivElement, ConnectorScopePickerProps>(\n (\n {\n scopes,\n value,\n defaultValue = [],\n onValueChange,\n agentName = \"Aria\",\n title,\n allowWrite,\n onAllowWriteChange,\n writeLabel = \"Also allow changes (create, edit, post)\",\n className,\n ...props\n },\n ref,\n ) => {\n const [internal, setInternal] = React.useState<string[]>(defaultValue);\n const granted = value !== undefined ? value : internal;\n const headingId = React.useId();\n const set = (id: string, on: boolean) => {\n const next = on ? [...granted, id] : granted.filter((g) => g !== id);\n if (value === undefined) setInternal(next);\n onValueChange?.(next);\n };\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-labelledby={headingId}\n className={cn(\"flex flex-col gap-2 rounded-xl border border-border bg-background p-3\", className)}\n {...props}\n >\n <p id={headingId} className=\"text-sm font-semibold text-foreground\">\n {title ?? <>{agentName} can read from:</>}\n </p>\n <ul className=\"flex flex-col gap-1.5\">\n {scopes.map((scope) => {\n const on = granted.includes(scope.id);\n const labelId = `${headingId}-${scope.id}`;\n return (\n <li key={scope.id}>\n <label className=\"flex cursor-pointer items-center gap-2 text-sm\">\n <Checkbox checked={on} onCheckedChange={(c) => set(scope.id, c)} aria-labelledby={labelId} />\n <span id={labelId} className={cn(on ? \"text-foreground\" : \"text-muted-foreground\")}>\n {scope.label}\n {scope.description && <span className=\"text-xs text-muted-foreground\"> · {scope.description}</span>}\n </span>\n </label>\n </li>\n );\n })}\n </ul>\n {(allowWrite !== undefined || onAllowWriteChange) && (\n <div className=\"flex items-center justify-between gap-3 border-t border-border pt-2\">\n <span id={`${headingId}-write`} className=\"text-sm text-foreground\">\n {writeLabel}\n </span>\n <Switch\n size=\"sm\"\n checked={allowWrite ?? false}\n onCheckedChange={onAllowWriteChange}\n aria-labelledby={`${headingId}-write`}\n />\n </div>\n )}\n </div>\n );\n },\n);\nConnectorScopePicker.displayName = \"ConnectorScopePicker\";\n\nexport interface ConnectorLivePillProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** The connector being read, e.g. `\"Drive\"`. */\n source?: React.ReactNode;\n /** How many items are being read. */\n count?: number;\n /** Noun for `count`. Defaults to `\"docs\"`. */\n noun?: string;\n}\n\n/**\n * The live source pill: a pulsing chip that shows the agent is reading from a\n * connector right now (\"Reading 12 docs from Drive…\"), announced politely.\n * Pass children to word it yourself. The pulse stops under reduced motion.\n */\nexport const ConnectorLivePill = React.forwardRef<HTMLSpanElement, ConnectorLivePillProps>(\n ({ source, count, noun = \"docs\", className, children, ...props }, ref) => (\n <span\n ref={ref}\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n \"inline-flex items-center gap-2 rounded-full border border-brand/50 bg-brand-muted/50 px-3 py-1 text-xs font-semibold text-brand\",\n className,\n )}\n {...props}\n >\n <span aria-hidden=\"true\" className=\"size-2 rounded-full bg-brand animate-pulse motion-reduce:animate-none\" />\n {children ?? (\n <>\n Reading{count != null ? ` ${count} ${noun}` : \"\"}\n {source ? <> from {source}</> : null}…\n </>\n )}\n </span>\n ),\n);\nConnectorLivePill.displayName = \"ConnectorLivePill\";\n"]}
@@ -0,0 +1,103 @@
1
+ import * as React from 'react';
2
+
3
+ /** Connection state. `expired` is the sign-in people meet most often: connected once, needs signing in again. */
4
+ type ConnectorStatus = "disconnected" | "connecting" | "connected" | "expired" | "error";
5
+ interface ConnectorProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
6
+ /** Connector name, e.g. `"GitHub"`. */
7
+ name: React.ReactNode;
8
+ /** What the connector gives the agent access to. */
9
+ description?: React.ReactNode;
10
+ /** Connector logo/icon. Defaults to a plug glyph. */
11
+ icon?: React.ReactNode;
12
+ /** Whether the connector is already connected. Shorthand for `status="connected"`. */
13
+ connected?: boolean;
14
+ /** Full connection state; overrides `connected` when set. */
15
+ status?: ConnectorStatus;
16
+ /** Called to connect. Renders the connect button when set and not connected. */
17
+ onConnect?: () => void;
18
+ /** Called to disconnect. Renders a manage/disconnect control when connected. */
19
+ onDisconnect?: () => void;
20
+ /** Called to sign in again when `status` is `"expired"` or `"error"`. Falls back to `onConnect`. */
21
+ onReconnect?: () => void;
22
+ /** Label for the connect action. Defaults to a localized "Connect". */
23
+ connectLabel?: React.ReactNode;
24
+ /** Label for the disconnect action. Defaults to a localized "Disconnect". */
25
+ disconnectLabel?: React.ReactNode;
26
+ /** What the agent will be able to do, in plain verbs — shown before the handoff, e.g. `["Read files in folders you choose", "Search file names"]`. */
27
+ scopes?: React.ReactNode[];
28
+ /** Who the sign-in is with, e.g. `"sam@acme.com"`. Shown once connected. */
29
+ account?: React.ReactNode;
30
+ /** What went wrong, when `status` is `"error"`. */
31
+ error?: React.ReactNode;
32
+ }
33
+ /**
34
+ * A card to enable an external tool or data connector for the agent — icon,
35
+ * name, what it unlocks, and a connect action. Before connecting it can list
36
+ * the scopes in plain verbs (never over-grant); once connected it says who the
37
+ * sign-in is with and that access can be withdrawn. Status is a word, announced
38
+ * politely: Connecting…, Connected, Sign-in expired (with Reconnect), Couldn't
39
+ * connect. Group several in a ConnectorList; narrow access with
40
+ * ConnectorScopePicker; show live reads with ConnectorLivePill.
41
+ * Source: Figma "Context Expansion / Connector suggestion card".
42
+ */
43
+ declare const Connector: React.ForwardRefExoticComponent<ConnectorProps & React.RefAttributes<HTMLDivElement>>;
44
+ interface ConnectorListProps extends React.HTMLAttributes<HTMLDivElement> {
45
+ /** Accessible name. Defaults to `"Connected services"`. */
46
+ label?: string;
47
+ }
48
+ /**
49
+ * The connector list: available services with their status and a connect
50
+ * button, one per row. Wrap Connector cards; each child becomes a list item.
51
+ */
52
+ declare const ConnectorList: React.ForwardRefExoticComponent<ConnectorListProps & React.RefAttributes<HTMLDivElement>>;
53
+ /** One thing the agent could read: a channel, folder, repo or branch. */
54
+ interface ConnectorScope {
55
+ /** Stable id. */
56
+ id: string;
57
+ /** Label, e.g. `"#renewals"`. */
58
+ label: React.ReactNode;
59
+ /** Optional detail, e.g. `"412 messages"`. */
60
+ description?: React.ReactNode;
61
+ }
62
+ interface ConnectorScopePickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title" | "defaultValue" | "onChange"> {
63
+ /** The scopes on offer. */
64
+ scopes: ConnectorScope[];
65
+ /** Granted scope ids (controlled). */
66
+ value?: string[];
67
+ /** Initial grant (uncontrolled). Defaults to none — least privilege. */
68
+ defaultValue?: string[];
69
+ /** Called with the granted ids. */
70
+ onValueChange?: (ids: string[]) => void;
71
+ /** Who reads. Defaults to `"Aria"`. */
72
+ agentName?: React.ReactNode;
73
+ /** Heading override. Defaults to `"<agent> can read from:"`. */
74
+ title?: React.ReactNode;
75
+ /** Write access, asked separately (controlled). Renders the write switch when this or `onAllowWriteChange` is set. */
76
+ allowWrite?: boolean;
77
+ /** Called when write access is switched. */
78
+ onAllowWriteChange?: (on: boolean) => void;
79
+ /** Label for the write switch. Defaults to `"Also allow changes (create, edit, post)"`. */
80
+ writeLabel?: React.ReactNode;
81
+ }
82
+ /**
83
+ * The scope picker: exactly what the agent can read — workspace, channel,
84
+ * folder, repo — granular rather than all-or-nothing, starting from nothing.
85
+ * Write access, when offered, is a separate and visible question.
86
+ */
87
+ declare const ConnectorScopePicker: React.ForwardRefExoticComponent<ConnectorScopePickerProps & React.RefAttributes<HTMLDivElement>>;
88
+ interface ConnectorLivePillProps extends React.HTMLAttributes<HTMLSpanElement> {
89
+ /** The connector being read, e.g. `"Drive"`. */
90
+ source?: React.ReactNode;
91
+ /** How many items are being read. */
92
+ count?: number;
93
+ /** Noun for `count`. Defaults to `"docs"`. */
94
+ noun?: string;
95
+ }
96
+ /**
97
+ * The live source pill: a pulsing chip that shows the agent is reading from a
98
+ * connector right now ("Reading 12 docs from Drive…"), announced politely.
99
+ * Pass children to word it yourself. The pulse stops under reduced motion.
100
+ */
101
+ declare const ConnectorLivePill: React.ForwardRefExoticComponent<ConnectorLivePillProps & React.RefAttributes<HTMLSpanElement>>;
102
+
103
+ export { Connector, ConnectorList, type ConnectorListProps, ConnectorLivePill, type ConnectorLivePillProps, type ConnectorProps, type ConnectorScope, ConnectorScopePicker, type ConnectorScopePickerProps, type ConnectorStatus };
@@ -0,0 +1,103 @@
1
+ import * as React from 'react';
2
+
3
+ /** Connection state. `expired` is the sign-in people meet most often: connected once, needs signing in again. */
4
+ type ConnectorStatus = "disconnected" | "connecting" | "connected" | "expired" | "error";
5
+ interface ConnectorProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
6
+ /** Connector name, e.g. `"GitHub"`. */
7
+ name: React.ReactNode;
8
+ /** What the connector gives the agent access to. */
9
+ description?: React.ReactNode;
10
+ /** Connector logo/icon. Defaults to a plug glyph. */
11
+ icon?: React.ReactNode;
12
+ /** Whether the connector is already connected. Shorthand for `status="connected"`. */
13
+ connected?: boolean;
14
+ /** Full connection state; overrides `connected` when set. */
15
+ status?: ConnectorStatus;
16
+ /** Called to connect. Renders the connect button when set and not connected. */
17
+ onConnect?: () => void;
18
+ /** Called to disconnect. Renders a manage/disconnect control when connected. */
19
+ onDisconnect?: () => void;
20
+ /** Called to sign in again when `status` is `"expired"` or `"error"`. Falls back to `onConnect`. */
21
+ onReconnect?: () => void;
22
+ /** Label for the connect action. Defaults to a localized "Connect". */
23
+ connectLabel?: React.ReactNode;
24
+ /** Label for the disconnect action. Defaults to a localized "Disconnect". */
25
+ disconnectLabel?: React.ReactNode;
26
+ /** What the agent will be able to do, in plain verbs — shown before the handoff, e.g. `["Read files in folders you choose", "Search file names"]`. */
27
+ scopes?: React.ReactNode[];
28
+ /** Who the sign-in is with, e.g. `"sam@acme.com"`. Shown once connected. */
29
+ account?: React.ReactNode;
30
+ /** What went wrong, when `status` is `"error"`. */
31
+ error?: React.ReactNode;
32
+ }
33
+ /**
34
+ * A card to enable an external tool or data connector for the agent — icon,
35
+ * name, what it unlocks, and a connect action. Before connecting it can list
36
+ * the scopes in plain verbs (never over-grant); once connected it says who the
37
+ * sign-in is with and that access can be withdrawn. Status is a word, announced
38
+ * politely: Connecting…, Connected, Sign-in expired (with Reconnect), Couldn't
39
+ * connect. Group several in a ConnectorList; narrow access with
40
+ * ConnectorScopePicker; show live reads with ConnectorLivePill.
41
+ * Source: Figma "Context Expansion / Connector suggestion card".
42
+ */
43
+ declare const Connector: React.ForwardRefExoticComponent<ConnectorProps & React.RefAttributes<HTMLDivElement>>;
44
+ interface ConnectorListProps extends React.HTMLAttributes<HTMLDivElement> {
45
+ /** Accessible name. Defaults to `"Connected services"`. */
46
+ label?: string;
47
+ }
48
+ /**
49
+ * The connector list: available services with their status and a connect
50
+ * button, one per row. Wrap Connector cards; each child becomes a list item.
51
+ */
52
+ declare const ConnectorList: React.ForwardRefExoticComponent<ConnectorListProps & React.RefAttributes<HTMLDivElement>>;
53
+ /** One thing the agent could read: a channel, folder, repo or branch. */
54
+ interface ConnectorScope {
55
+ /** Stable id. */
56
+ id: string;
57
+ /** Label, e.g. `"#renewals"`. */
58
+ label: React.ReactNode;
59
+ /** Optional detail, e.g. `"412 messages"`. */
60
+ description?: React.ReactNode;
61
+ }
62
+ interface ConnectorScopePickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title" | "defaultValue" | "onChange"> {
63
+ /** The scopes on offer. */
64
+ scopes: ConnectorScope[];
65
+ /** Granted scope ids (controlled). */
66
+ value?: string[];
67
+ /** Initial grant (uncontrolled). Defaults to none — least privilege. */
68
+ defaultValue?: string[];
69
+ /** Called with the granted ids. */
70
+ onValueChange?: (ids: string[]) => void;
71
+ /** Who reads. Defaults to `"Aria"`. */
72
+ agentName?: React.ReactNode;
73
+ /** Heading override. Defaults to `"<agent> can read from:"`. */
74
+ title?: React.ReactNode;
75
+ /** Write access, asked separately (controlled). Renders the write switch when this or `onAllowWriteChange` is set. */
76
+ allowWrite?: boolean;
77
+ /** Called when write access is switched. */
78
+ onAllowWriteChange?: (on: boolean) => void;
79
+ /** Label for the write switch. Defaults to `"Also allow changes (create, edit, post)"`. */
80
+ writeLabel?: React.ReactNode;
81
+ }
82
+ /**
83
+ * The scope picker: exactly what the agent can read — workspace, channel,
84
+ * folder, repo — granular rather than all-or-nothing, starting from nothing.
85
+ * Write access, when offered, is a separate and visible question.
86
+ */
87
+ declare const ConnectorScopePicker: React.ForwardRefExoticComponent<ConnectorScopePickerProps & React.RefAttributes<HTMLDivElement>>;
88
+ interface ConnectorLivePillProps extends React.HTMLAttributes<HTMLSpanElement> {
89
+ /** The connector being read, e.g. `"Drive"`. */
90
+ source?: React.ReactNode;
91
+ /** How many items are being read. */
92
+ count?: number;
93
+ /** Noun for `count`. Defaults to `"docs"`. */
94
+ noun?: string;
95
+ }
96
+ /**
97
+ * The live source pill: a pulsing chip that shows the agent is reading from a
98
+ * connector right now ("Reading 12 docs from Drive…"), announced politely.
99
+ * Pass children to word it yourself. The pulse stops under reduced motion.
100
+ */
101
+ declare const ConnectorLivePill: React.ForwardRefExoticComponent<ConnectorLivePillProps & React.RefAttributes<HTMLSpanElement>>;
102
+
103
+ export { Connector, ConnectorList, type ConnectorListProps, ConnectorLivePill, type ConnectorLivePillProps, type ConnectorProps, type ConnectorScope, ConnectorScopePicker, type ConnectorScopePickerProps, type ConnectorStatus };
package/dist/index.js ADDED
@@ -0,0 +1,222 @@
1
+ "use client";
2
+ import * as React from 'react';
3
+ import { cn } from '@nucleux/utils';
4
+ import { Button } from '@nucleux/button';
5
+ import { Checkbox } from '@nucleux/checkbox';
6
+ import { Spinner } from '@nucleux/spinner';
7
+ import { Switch } from '@nucleux/switch';
8
+ import { Plug, Check } from 'lucide-react';
9
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
10
+
11
+ // src/index.tsx
12
+ var statusText = {
13
+ connecting: "Connecting\u2026",
14
+ expired: "Sign-in expired",
15
+ error: "Couldn't connect"
16
+ };
17
+ var Connector = React.forwardRef(
18
+ ({
19
+ name,
20
+ description,
21
+ icon,
22
+ connected = false,
23
+ status: statusProp,
24
+ onConnect,
25
+ onDisconnect,
26
+ onReconnect,
27
+ connectLabel = "Connect",
28
+ disconnectLabel = "Disconnect",
29
+ scopes,
30
+ account,
31
+ error,
32
+ className,
33
+ ...props
34
+ }, ref) => {
35
+ const status = statusProp ?? (connected ? "connected" : "disconnected");
36
+ const reconnect = onReconnect ?? onConnect;
37
+ return /* @__PURE__ */ jsxs(
38
+ "div",
39
+ {
40
+ ref,
41
+ "data-status": status,
42
+ className: cn(
43
+ "flex flex-col gap-3 rounded-xl border border-border bg-background p-4",
44
+ status === "expired" && "border-warning/50",
45
+ status === "error" && "border-destructive/50",
46
+ className
47
+ ),
48
+ ...props,
49
+ children: [
50
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
51
+ /* @__PURE__ */ jsx("span", { className: "inline-flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg]:size-5", children: icon ?? /* @__PURE__ */ jsx(Plug, { "aria-hidden": "true" }) }),
52
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
53
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: name }),
54
+ description && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: description })
55
+ ] }),
56
+ /* @__PURE__ */ jsxs("span", { role: "status", "aria-live": "polite", className: "contents", children: [
57
+ status === "connected" && /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-1 rounded-full bg-success/15 px-2 py-0.5 text-xs font-medium text-success [&_svg]:size-3.5", children: [
58
+ /* @__PURE__ */ jsx(Check, { "aria-hidden": "true" }),
59
+ "Connected"
60
+ ] }),
61
+ status === "connecting" && /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground", children: [
62
+ /* @__PURE__ */ jsx(Spinner, { "aria-hidden": "true", role: void 0, className: "size-3.5 motion-reduce:animate-none" }),
63
+ statusText.connecting
64
+ ] }),
65
+ status === "expired" && /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full bg-warning/15 px-2 py-0.5 text-xs font-medium text-warning", children: statusText.expired }),
66
+ status === "error" && /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full bg-destructive/15 px-2 py-0.5 text-xs font-medium text-destructive", children: statusText.error })
67
+ ] }),
68
+ status === "connected" && onDisconnect && /* @__PURE__ */ jsx(
69
+ "button",
70
+ {
71
+ type: "button",
72
+ onClick: onDisconnect,
73
+ className: "shrink-0 rounded-md px-2 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
74
+ children: disconnectLabel
75
+ }
76
+ ),
77
+ status === "disconnected" && /* @__PURE__ */ jsx(
78
+ "button",
79
+ {
80
+ type: "button",
81
+ onClick: onConnect,
82
+ className: "inline-flex shrink-0 items-center rounded-lg border border-border bg-background px-3 py-1.5 text-sm font-medium text-foreground shadow-sm transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
83
+ children: connectLabel
84
+ }
85
+ ),
86
+ (status === "expired" || status === "error") && reconnect && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "secondary", onClick: reconnect, className: "shrink-0", children: status === "expired" ? "Reconnect" : "Try again" })
87
+ ] }),
88
+ status === "error" && error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: error }),
89
+ status === "expired" && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
90
+ "Nothing was lost \u2014 sign in again",
91
+ account ? /* @__PURE__ */ jsxs(Fragment, { children: [
92
+ " as ",
93
+ account
94
+ ] }) : null,
95
+ " to keep reading from ",
96
+ name,
97
+ "."
98
+ ] }),
99
+ (status === "disconnected" || status === "connecting") && scopes && scopes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 border-t border-border pt-3", children: [
100
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-foreground", children: "If you connect, the agent can:" }),
101
+ /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-0.5 text-xs text-muted-foreground", children: scopes.map((scope, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-1.5", children: [
102
+ /* @__PURE__ */ jsx(Check, { "aria-hidden": "true", className: "mt-0.5 size-3 shrink-0 text-muted-foreground" }),
103
+ scope
104
+ ] }, i)) })
105
+ ] }),
106
+ status === "connected" && account && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
107
+ "Signed in as ",
108
+ account,
109
+ ". You can disconnect at any time."
110
+ ] })
111
+ ]
112
+ }
113
+ );
114
+ }
115
+ );
116
+ Connector.displayName = "Connector";
117
+ var ConnectorList = React.forwardRef(
118
+ ({ label = "Connected services", className, children, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, role: "list", "aria-label": label, className: cn("flex flex-col gap-2", className), ...props, children: React.Children.map(
119
+ children,
120
+ (child) => child == null || child === false ? null : /* @__PURE__ */ jsx("div", { role: "listitem", children: child })
121
+ ) })
122
+ );
123
+ ConnectorList.displayName = "ConnectorList";
124
+ var ConnectorScopePicker = React.forwardRef(
125
+ ({
126
+ scopes,
127
+ value,
128
+ defaultValue = [],
129
+ onValueChange,
130
+ agentName = "Aria",
131
+ title,
132
+ allowWrite,
133
+ onAllowWriteChange,
134
+ writeLabel = "Also allow changes (create, edit, post)",
135
+ className,
136
+ ...props
137
+ }, ref) => {
138
+ const [internal, setInternal] = React.useState(defaultValue);
139
+ const granted = value !== void 0 ? value : internal;
140
+ const headingId = React.useId();
141
+ const set = (id, on) => {
142
+ const next = on ? [...granted, id] : granted.filter((g) => g !== id);
143
+ if (value === void 0) setInternal(next);
144
+ onValueChange?.(next);
145
+ };
146
+ return /* @__PURE__ */ jsxs(
147
+ "div",
148
+ {
149
+ ref,
150
+ role: "group",
151
+ "aria-labelledby": headingId,
152
+ className: cn("flex flex-col gap-2 rounded-xl border border-border bg-background p-3", className),
153
+ ...props,
154
+ children: [
155
+ /* @__PURE__ */ jsx("p", { id: headingId, className: "text-sm font-semibold text-foreground", children: title ?? /* @__PURE__ */ jsxs(Fragment, { children: [
156
+ agentName,
157
+ " can read from:"
158
+ ] }) }),
159
+ /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-1.5", children: scopes.map((scope) => {
160
+ const on = granted.includes(scope.id);
161
+ const labelId = `${headingId}-${scope.id}`;
162
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("label", { className: "flex cursor-pointer items-center gap-2 text-sm", children: [
163
+ /* @__PURE__ */ jsx(Checkbox, { checked: on, onCheckedChange: (c) => set(scope.id, c), "aria-labelledby": labelId }),
164
+ /* @__PURE__ */ jsxs("span", { id: labelId, className: cn(on ? "text-foreground" : "text-muted-foreground"), children: [
165
+ scope.label,
166
+ scope.description && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
167
+ " \xB7 ",
168
+ scope.description
169
+ ] })
170
+ ] })
171
+ ] }) }, scope.id);
172
+ }) }),
173
+ (allowWrite !== void 0 || onAllowWriteChange) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-border pt-2", children: [
174
+ /* @__PURE__ */ jsx("span", { id: `${headingId}-write`, className: "text-sm text-foreground", children: writeLabel }),
175
+ /* @__PURE__ */ jsx(
176
+ Switch,
177
+ {
178
+ size: "sm",
179
+ checked: allowWrite ?? false,
180
+ onCheckedChange: onAllowWriteChange,
181
+ "aria-labelledby": `${headingId}-write`
182
+ }
183
+ )
184
+ ] })
185
+ ]
186
+ }
187
+ );
188
+ }
189
+ );
190
+ ConnectorScopePicker.displayName = "ConnectorScopePicker";
191
+ var ConnectorLivePill = React.forwardRef(
192
+ ({ source, count, noun = "docs", className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
193
+ "span",
194
+ {
195
+ ref,
196
+ role: "status",
197
+ "aria-live": "polite",
198
+ className: cn(
199
+ "inline-flex items-center gap-2 rounded-full border border-brand/50 bg-brand-muted/50 px-3 py-1 text-xs font-semibold text-brand",
200
+ className
201
+ ),
202
+ ...props,
203
+ children: [
204
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "size-2 rounded-full bg-brand animate-pulse motion-reduce:animate-none" }),
205
+ children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
206
+ "Reading",
207
+ count != null ? ` ${count} ${noun}` : "",
208
+ source ? /* @__PURE__ */ jsxs(Fragment, { children: [
209
+ " from ",
210
+ source
211
+ ] }) : null,
212
+ "\u2026"
213
+ ] })
214
+ ]
215
+ }
216
+ )
217
+ );
218
+ ConnectorLivePill.displayName = "ConnectorLivePill";
219
+
220
+ export { Connector, ConnectorList, ConnectorLivePill, ConnectorScopePicker };
221
+ //# sourceMappingURL=index.js.map
222
+ //# 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 { Button } from \"@nucleux/button\";\nimport { Checkbox } from \"@nucleux/checkbox\";\nimport { Spinner } from \"@nucleux/spinner\";\nimport { Switch } from \"@nucleux/switch\";\nimport { Plug, Check } from \"lucide-react\";\n\n/** Connection state. `expired` is the sign-in people meet most often: connected once, needs signing in again. */\nexport type ConnectorStatus = \"disconnected\" | \"connecting\" | \"connected\" | \"expired\" | \"error\";\n\nexport interface ConnectorProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Connector name, e.g. `\"GitHub\"`. */\n name: React.ReactNode;\n /** What the connector gives the agent access to. */\n description?: React.ReactNode;\n /** Connector logo/icon. Defaults to a plug glyph. */\n icon?: React.ReactNode;\n /** Whether the connector is already connected. Shorthand for `status=\"connected\"`. */\n connected?: boolean;\n /** Full connection state; overrides `connected` when set. */\n status?: ConnectorStatus;\n /** Called to connect. Renders the connect button when set and not connected. */\n onConnect?: () => void;\n /** Called to disconnect. Renders a manage/disconnect control when connected. */\n onDisconnect?: () => void;\n /** Called to sign in again when `status` is `\"expired\"` or `\"error\"`. Falls back to `onConnect`. */\n onReconnect?: () => void;\n /** Label for the connect action. Defaults to a localized \"Connect\". */\n connectLabel?: React.ReactNode;\n /** Label for the disconnect action. Defaults to a localized \"Disconnect\". */\n disconnectLabel?: React.ReactNode;\n /** What the agent will be able to do, in plain verbs — shown before the handoff, e.g. `[\"Read files in folders you choose\", \"Search file names\"]`. */\n scopes?: React.ReactNode[];\n /** Who the sign-in is with, e.g. `\"sam@acme.com\"`. Shown once connected. */\n account?: React.ReactNode;\n /** What went wrong, when `status` is `\"error\"`. */\n error?: React.ReactNode;\n}\n\nconst statusText: Record<Exclude<ConnectorStatus, \"disconnected\">, string> = {\n connecting: \"Connecting…\",\n connected: \"Connected\",\n expired: \"Sign-in expired\",\n error: \"Couldn't connect\",\n};\n\n/**\n * A card to enable an external tool or data connector for the agent — icon,\n * name, what it unlocks, and a connect action. Before connecting it can list\n * the scopes in plain verbs (never over-grant); once connected it says who the\n * sign-in is with and that access can be withdrawn. Status is a word, announced\n * politely: Connecting…, Connected, Sign-in expired (with Reconnect), Couldn't\n * connect. Group several in a ConnectorList; narrow access with\n * ConnectorScopePicker; show live reads with ConnectorLivePill.\n * Source: Figma \"Context Expansion / Connector suggestion card\".\n */\nexport const Connector = React.forwardRef<HTMLDivElement, ConnectorProps>(\n (\n {\n name,\n description,\n icon,\n connected = false,\n status: statusProp,\n onConnect,\n onDisconnect,\n onReconnect,\n connectLabel = \"Connect\",\n disconnectLabel = \"Disconnect\",\n scopes,\n account,\n error,\n className,\n ...props\n },\n ref,\n ) => {\n const status: ConnectorStatus = statusProp ?? (connected ? \"connected\" : \"disconnected\");\n const reconnect = onReconnect ?? onConnect;\n return (\n <div\n ref={ref}\n data-status={status}\n className={cn(\n \"flex flex-col gap-3 rounded-xl border border-border bg-background p-4\",\n status === \"expired\" && \"border-warning/50\",\n status === \"error\" && \"border-destructive/50\",\n className,\n )}\n {...props}\n >\n <div className=\"flex items-center gap-3\">\n <span className=\"inline-flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg]:size-5\">\n {icon ?? <Plug aria-hidden=\"true\" />}\n </span>\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <span className=\"text-sm font-medium text-foreground\">{name}</span>\n {description && <span className=\"text-xs text-muted-foreground\">{description}</span>}\n </div>\n <span role=\"status\" aria-live=\"polite\" className=\"contents\">\n {status === \"connected\" && (\n <span className=\"inline-flex shrink-0 items-center gap-1 rounded-full bg-success/15 px-2 py-0.5 text-xs font-medium text-success [&_svg]:size-3.5\">\n <Check aria-hidden=\"true\" />\n Connected\n </span>\n )}\n {status === \"connecting\" && (\n <span className=\"inline-flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground\">\n <Spinner aria-hidden=\"true\" role={undefined} className=\"size-3.5 motion-reduce:animate-none\" />\n {statusText.connecting}\n </span>\n )}\n {status === \"expired\" && (\n <span className=\"shrink-0 rounded-full bg-warning/15 px-2 py-0.5 text-xs font-medium text-warning\">\n {statusText.expired}\n </span>\n )}\n {status === \"error\" && (\n <span className=\"shrink-0 rounded-full bg-destructive/15 px-2 py-0.5 text-xs font-medium text-destructive\">\n {statusText.error}\n </span>\n )}\n </span>\n {status === \"connected\" && onDisconnect && (\n <button\n type=\"button\"\n onClick={onDisconnect}\n className=\"shrink-0 rounded-md px-2 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {disconnectLabel}\n </button>\n )}\n {status === \"disconnected\" && (\n <button\n type=\"button\"\n onClick={onConnect}\n className=\"inline-flex shrink-0 items-center rounded-lg border border-border bg-background px-3 py-1.5 text-sm font-medium text-foreground shadow-sm transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {connectLabel}\n </button>\n )}\n {(status === \"expired\" || status === \"error\") && reconnect && (\n <Button size=\"sm\" variant=\"secondary\" onClick={reconnect} className=\"shrink-0\">\n {status === \"expired\" ? \"Reconnect\" : \"Try again\"}\n </Button>\n )}\n </div>\n {status === \"error\" && error && <p className=\"text-xs text-destructive\">{error}</p>}\n {status === \"expired\" && (\n <p className=\"text-xs text-muted-foreground\">\n Nothing was lost — sign in again{account ? <> as {account}</> : null} to keep reading from {name}.\n </p>\n )}\n {(status === \"disconnected\" || status === \"connecting\") && scopes && scopes.length > 0 && (\n <div className=\"flex flex-col gap-1 border-t border-border pt-3\">\n <p className=\"text-xs font-medium text-foreground\">If you connect, the agent can:</p>\n <ul className=\"flex flex-col gap-0.5 text-xs text-muted-foreground\">\n {scopes.map((scope, i) => (\n <li key={i} className=\"flex items-start gap-1.5\">\n <Check aria-hidden=\"true\" className=\"mt-0.5 size-3 shrink-0 text-muted-foreground\" />\n {scope}\n </li>\n ))}\n </ul>\n </div>\n )}\n {status === \"connected\" && account && (\n <p className=\"text-xs text-muted-foreground\">\n Signed in as {account}. You can disconnect at any time.\n </p>\n )}\n </div>\n );\n },\n);\nConnector.displayName = \"Connector\";\n\nexport interface ConnectorListProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Accessible name. Defaults to `\"Connected services\"`. */\n label?: string;\n}\n\n/**\n * The connector list: available services with their status and a connect\n * button, one per row. Wrap Connector cards; each child becomes a list item.\n */\nexport const ConnectorList = React.forwardRef<HTMLDivElement, ConnectorListProps>(\n ({ label = \"Connected services\", className, children, ...props }, ref) => (\n <div ref={ref} role=\"list\" aria-label={label} className={cn(\"flex flex-col gap-2\", className)} {...props}>\n {React.Children.map(children, (child) =>\n child == null || child === false ? null : <div role=\"listitem\">{child}</div>,\n )}\n </div>\n ),\n);\nConnectorList.displayName = \"ConnectorList\";\n\n/** One thing the agent could read: a channel, folder, repo or branch. */\nexport interface ConnectorScope {\n /** Stable id. */\n id: string;\n /** Label, e.g. `\"#renewals\"`. */\n label: React.ReactNode;\n /** Optional detail, e.g. `\"412 messages\"`. */\n description?: React.ReactNode;\n}\n\nexport interface ConnectorScopePickerProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\" | \"defaultValue\" | \"onChange\"> {\n /** The scopes on offer. */\n scopes: ConnectorScope[];\n /** Granted scope ids (controlled). */\n value?: string[];\n /** Initial grant (uncontrolled). Defaults to none — least privilege. */\n defaultValue?: string[];\n /** Called with the granted ids. */\n onValueChange?: (ids: string[]) => void;\n /** Who reads. Defaults to `\"Aria\"`. */\n agentName?: React.ReactNode;\n /** Heading override. Defaults to `\"<agent> can read from:\"`. */\n title?: React.ReactNode;\n /** Write access, asked separately (controlled). Renders the write switch when this or `onAllowWriteChange` is set. */\n allowWrite?: boolean;\n /** Called when write access is switched. */\n onAllowWriteChange?: (on: boolean) => void;\n /** Label for the write switch. Defaults to `\"Also allow changes (create, edit, post)\"`. */\n writeLabel?: React.ReactNode;\n}\n\n/**\n * The scope picker: exactly what the agent can read — workspace, channel,\n * folder, repo — granular rather than all-or-nothing, starting from nothing.\n * Write access, when offered, is a separate and visible question.\n */\nexport const ConnectorScopePicker = React.forwardRef<HTMLDivElement, ConnectorScopePickerProps>(\n (\n {\n scopes,\n value,\n defaultValue = [],\n onValueChange,\n agentName = \"Aria\",\n title,\n allowWrite,\n onAllowWriteChange,\n writeLabel = \"Also allow changes (create, edit, post)\",\n className,\n ...props\n },\n ref,\n ) => {\n const [internal, setInternal] = React.useState<string[]>(defaultValue);\n const granted = value !== undefined ? value : internal;\n const headingId = React.useId();\n const set = (id: string, on: boolean) => {\n const next = on ? [...granted, id] : granted.filter((g) => g !== id);\n if (value === undefined) setInternal(next);\n onValueChange?.(next);\n };\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-labelledby={headingId}\n className={cn(\"flex flex-col gap-2 rounded-xl border border-border bg-background p-3\", className)}\n {...props}\n >\n <p id={headingId} className=\"text-sm font-semibold text-foreground\">\n {title ?? <>{agentName} can read from:</>}\n </p>\n <ul className=\"flex flex-col gap-1.5\">\n {scopes.map((scope) => {\n const on = granted.includes(scope.id);\n const labelId = `${headingId}-${scope.id}`;\n return (\n <li key={scope.id}>\n <label className=\"flex cursor-pointer items-center gap-2 text-sm\">\n <Checkbox checked={on} onCheckedChange={(c) => set(scope.id, c)} aria-labelledby={labelId} />\n <span id={labelId} className={cn(on ? \"text-foreground\" : \"text-muted-foreground\")}>\n {scope.label}\n {scope.description && <span className=\"text-xs text-muted-foreground\"> · {scope.description}</span>}\n </span>\n </label>\n </li>\n );\n })}\n </ul>\n {(allowWrite !== undefined || onAllowWriteChange) && (\n <div className=\"flex items-center justify-between gap-3 border-t border-border pt-2\">\n <span id={`${headingId}-write`} className=\"text-sm text-foreground\">\n {writeLabel}\n </span>\n <Switch\n size=\"sm\"\n checked={allowWrite ?? false}\n onCheckedChange={onAllowWriteChange}\n aria-labelledby={`${headingId}-write`}\n />\n </div>\n )}\n </div>\n );\n },\n);\nConnectorScopePicker.displayName = \"ConnectorScopePicker\";\n\nexport interface ConnectorLivePillProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** The connector being read, e.g. `\"Drive\"`. */\n source?: React.ReactNode;\n /** How many items are being read. */\n count?: number;\n /** Noun for `count`. Defaults to `\"docs\"`. */\n noun?: string;\n}\n\n/**\n * The live source pill: a pulsing chip that shows the agent is reading from a\n * connector right now (\"Reading 12 docs from Drive…\"), announced politely.\n * Pass children to word it yourself. The pulse stops under reduced motion.\n */\nexport const ConnectorLivePill = React.forwardRef<HTMLSpanElement, ConnectorLivePillProps>(\n ({ source, count, noun = \"docs\", className, children, ...props }, ref) => (\n <span\n ref={ref}\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n \"inline-flex items-center gap-2 rounded-full border border-brand/50 bg-brand-muted/50 px-3 py-1 text-xs font-semibold text-brand\",\n className,\n )}\n {...props}\n >\n <span aria-hidden=\"true\" className=\"size-2 rounded-full bg-brand animate-pulse motion-reduce:animate-none\" />\n {children ?? (\n <>\n Reading{count != null ? ` ${count} ${noun}` : \"\"}\n {source ? <> from {source}</> : null}…\n </>\n )}\n </span>\n ),\n);\nConnectorLivePill.displayName = \"ConnectorLivePill\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,62 @@
1
1
  {
2
2
  "name": "@nucleux/connectors",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.7.0",
4
+ "type": "module",
5
+ "sideEffects": false,
6
+ "description": "Connectors — connect an external tool or data source — Nucleux agentic UI for React.",
7
+ "keywords": [
8
+ "nucleux",
9
+ "react",
10
+ "ui",
11
+ "components",
12
+ "agentic",
13
+ "ai",
14
+ "tailwind",
15
+ "connectors"
16
+ ],
17
+ "main": "./dist/index.cjs",
18
+ "module": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js",
24
+ "require": "./dist/index.cjs"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "README.md"
30
+ ],
31
+ "peerDependencies": {
32
+ "react": ">=18",
33
+ "react-dom": ">=18"
34
+ },
35
+ "dependencies": {
36
+ "@nucleux/utils": "0.7.0",
37
+ "@nucleux/button": "0.7.0",
38
+ "@nucleux/checkbox": "0.7.0",
39
+ "@nucleux/spinner": "0.7.0",
40
+ "@nucleux/switch": "0.7.0",
41
+ "lucide-react": "^0.469.0"
42
+ },
43
+ "devDependencies": {
44
+ "tsup": "^8.3.5",
45
+ "typescript": "^5.7.2",
46
+ "@types/react": "^18.3.18",
47
+ "react": "^18.3.1"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "license": "MIT",
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "git+https://github.com/intelligaia-open-labs/nucleux.git",
56
+ "directory": "packages/connectors"
57
+ },
58
+ "homepage": "https://github.com/intelligaia-open-labs/nucleux#readme",
59
+ "scripts": {
60
+ "build": "tsup"
61
+ }
6
62
  }