@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 +21 -0
- package/README.md +42 -2
- package/dist/index.cjs +247 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +103 -0
- package/dist/index.d.ts +103 -0
- package/dist/index.js +222 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -3
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
|
-
#
|
|
1
|
+
# @nucleux/connectors
|
|
2
2
|
|
|
3
|
-
|
|
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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -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.d.ts
ADDED
|
@@ -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.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
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
|
}
|