@basictech/react 0.12.0-beta.1 → 0.12.0-beta.3

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/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  "use strict";
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
@@ -30,10 +31,21 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
31
  // src/index.ts
31
32
  var index_exports = {};
32
33
  __export(index_exports, {
34
+ AccountSettingsModal: () => AccountSettingsModal,
35
+ AuthStatus: () => AuthStatus,
36
+ BasicButton: () => BasicButton,
33
37
  BasicProvider: () => BasicProvider,
38
+ BasicUIProvider: () => BasicUIProvider,
34
39
  BrowserKeyValueStorage: () => BrowserKeyValueStorage,
35
40
  BrowserTokenStore: () => BrowserTokenStore,
36
41
  PersistenceStore: () => PersistenceStore,
42
+ SharesModal: () => SharesModal,
43
+ SignInButton: () => SignInButton,
44
+ SignOutButton: () => SignOutButton,
45
+ SyncStatus: () => SyncStatus,
46
+ UserAvatar: () => UserAvatar,
47
+ UserButton: () => UserButton,
48
+ UserMenu: () => UserMenu,
37
49
  browserCurrentUrl: () => browserCurrentUrl,
38
50
  browserNavigate: () => browserNavigate,
39
51
  browserReplaceUrl: () => browserReplaceUrl,
@@ -51,6 +63,7 @@ __export(index_exports, {
51
63
  useFiles: () => useFiles,
52
64
  useMounts: () => useMounts,
53
65
  useOutgoingShares: () => useOutgoingShares,
66
+ useProjectProfile: () => useProjectProfile,
54
67
  useQuery: () => useQuery,
55
68
  useRepos: () => useRepos,
56
69
  useSchemaStatus: () => useSchemaStatus,
@@ -784,7 +797,7 @@ function useAsyncResult(load, initialData, enabled, settled, dependencies) {
784
797
  function useAccountsFor(client) {
785
798
  const snapshot = useClientSnapshot(client);
786
799
  const switchAccount = (0, import_react4.useCallback)((id) => client.switchAccount(id), [client]);
787
- const addAccount = (0, import_react4.useCallback)(() => client.addAccount(), [client]);
800
+ const addAccount = (0, import_react4.useCallback)((options) => client.addAccount(options), [client]);
788
801
  const removeAccount = (0, import_react4.useCallback)((id) => client.removeAccount(id), [client]);
789
802
  return (0, import_react4.useMemo)(() => ({
790
803
  accounts: snapshot.accounts,
@@ -1053,6 +1066,45 @@ function useQuery(collection, query = {}, options = {}) {
1053
1066
  return useQueryValueFor(useRequiredClient(), collection, query, options);
1054
1067
  }
1055
1068
 
1069
+ // src/hooks/profile.ts
1070
+ var import_core6 = require("@basictech/core");
1071
+ function useProjectProfileFor(client, enabled = true) {
1072
+ const snapshot = useClientSnapshot(client);
1073
+ const accountId = snapshot.activeAccount?.id;
1074
+ const result = useAsyncResult(
1075
+ async () => ({ accountId, profile: await client.getProjectProfile() }),
1076
+ null,
1077
+ enabled && snapshot.isReady && snapshot.isSignedIn,
1078
+ snapshot.isReady,
1079
+ [snapshot.activeAccount?.id]
1080
+ );
1081
+ const checkAccount = () => {
1082
+ if (client.getSnapshot().activeAccount?.id !== accountId)
1083
+ throw new import_core6.BasicError("ACCOUNT_CHANGED");
1084
+ };
1085
+ return {
1086
+ ...result,
1087
+ data: enabled && snapshot.isSignedIn && result.data && result.data.accountId === accountId ? result.data.profile : null,
1088
+ async update(patch) {
1089
+ checkAccount();
1090
+ const profile = await client.updateProjectProfile(patch);
1091
+ checkAccount();
1092
+ result.refresh();
1093
+ return profile;
1094
+ },
1095
+ async reset() {
1096
+ checkAccount();
1097
+ const profile = await client.resetProjectProfile();
1098
+ checkAccount();
1099
+ result.refresh();
1100
+ return profile;
1101
+ }
1102
+ };
1103
+ }
1104
+ function useProjectProfile(enabled = true) {
1105
+ return useProjectProfileFor(useRequiredClient(), enabled);
1106
+ }
1107
+
1056
1108
  // src/create-basic.tsx
1057
1109
  var import_jsx_runtime2 = require("react/jsx-runtime");
1058
1110
  function createBasic(config) {
@@ -1081,18 +1133,1086 @@ function createBasic(config) {
1081
1133
  useSyncStatus: (source) => useSyncStatusFor(useBound(), source),
1082
1134
  useSchemaStatus: (source = "default") => useSchemaStatusFor(useBound(), source),
1083
1135
  useRepos: () => useReposFor(useBound()),
1136
+ useProjectProfile: (enabled) => useProjectProfileFor(useBound(), enabled),
1084
1137
  useFiles: (query = {}, options = {}) => useFilesFor(useBound(), query, options),
1085
1138
  useStorageInfo: () => useStorageInfoFor(useBound()),
1086
1139
  useMounts: (query = {}) => useMountsFor(useBound(), query),
1087
1140
  useOutgoingShares: () => useOutgoingSharesFor(useBound())
1088
1141
  };
1089
1142
  }
1143
+
1144
+ // src/components.tsx
1145
+ var import_react13 = require("react");
1146
+ var import_avatar = require("@base-ui/react/avatar");
1147
+ var import_dialog = require("@base-ui/react/dialog");
1148
+ var import_menu = require("@base-ui/react/menu");
1149
+ var import_tabs = require("@base-ui/react/tabs");
1150
+ var import_core7 = require("@basictech/core");
1151
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1152
+ var AppearanceContext = (0, import_react13.createContext)({});
1153
+ function accentText(accent) {
1154
+ if (!/^#([\da-f]{3}|[\da-f]{6})$/i.test(accent)) return "#fff";
1155
+ const hex = accent.length === 4 ? accent.slice(1).split("").map((digit) => digit + digit).join("") : accent.slice(1);
1156
+ const [red, green, blue] = [0, 2, 4].map((offset) => {
1157
+ const channel = parseInt(hex.slice(offset, offset + 2), 16) / 255;
1158
+ return channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;
1159
+ });
1160
+ return 0.2126 * red + 0.7152 * green + 0.0722 * blue > 0.179 ? "#000" : "#fff";
1161
+ }
1162
+ function appearanceStyle(appearance) {
1163
+ return {
1164
+ ...appearance.base ? { "--basic-surface": appearance.base } : {},
1165
+ ...appearance.accent ? {
1166
+ "--basic-accent": appearance.accent,
1167
+ "--basic-accent-text": accentText(appearance.accent)
1168
+ } : {},
1169
+ ...appearance.radius ? { "--basic-radius": appearance.radius } : {}
1170
+ };
1171
+ }
1172
+ function BasicUIProvider({
1173
+ appearance = {},
1174
+ children
1175
+ }) {
1176
+ const parent = (0, import_react13.useContext)(AppearanceContext);
1177
+ const value = { ...parent, ...appearance };
1178
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AppearanceContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1179
+ "div",
1180
+ {
1181
+ className: "basic-ui",
1182
+ "data-theme": value.theme ?? "light",
1183
+ "data-density": value.density ?? "comfortable",
1184
+ style: appearanceStyle(value),
1185
+ children
1186
+ }
1187
+ ) });
1188
+ }
1189
+ function useAppearanceProps() {
1190
+ const appearance = (0, import_react13.useContext)(AppearanceContext);
1191
+ return {
1192
+ "data-theme": appearance.theme ?? "light",
1193
+ "data-density": appearance.density ?? "comfortable",
1194
+ style: appearanceStyle(appearance)
1195
+ };
1196
+ }
1197
+ var BasicButton = (0, import_react13.forwardRef)(
1198
+ function BasicButton2({ variant = "outline", className = "", type = "button", ...props }, ref) {
1199
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1200
+ "button",
1201
+ {
1202
+ ...props,
1203
+ ref,
1204
+ type,
1205
+ className: `basic-button ${className}`,
1206
+ "data-variant": variant
1207
+ }
1208
+ );
1209
+ }
1210
+ );
1211
+ function useAction() {
1212
+ const [pending, setPending] = (0, import_react13.useState)(false);
1213
+ const [error, setError] = (0, import_react13.useState)(null);
1214
+ const busy = (0, import_react13.useRef)(false);
1215
+ const mounted = (0, import_react13.useRef)(true);
1216
+ (0, import_react13.useEffect)(() => {
1217
+ mounted.current = true;
1218
+ return () => {
1219
+ mounted.current = false;
1220
+ };
1221
+ }, []);
1222
+ async function run(action) {
1223
+ if (busy.current) return;
1224
+ busy.current = true;
1225
+ setPending(true);
1226
+ setError(null);
1227
+ try {
1228
+ await action();
1229
+ } catch (cause) {
1230
+ if (mounted.current)
1231
+ setError(
1232
+ cause instanceof import_core7.BasicError && cause.code === "REDIRECT_URI_NOT_REGISTERED" ? "Sign-in is unavailable on this URL. Ask the app owner to register its callback URL in project settings." : cause instanceof Error ? cause.message : "The action failed. Please try again."
1233
+ );
1234
+ } finally {
1235
+ busy.current = false;
1236
+ if (mounted.current) setPending(false);
1237
+ }
1238
+ }
1239
+ return { pending, error, run, clearError: () => setError(null) };
1240
+ }
1241
+ function AuthButton({
1242
+ auth: supplied,
1243
+ input,
1244
+ signOut = false,
1245
+ children,
1246
+ disabled,
1247
+ onClick,
1248
+ ...props
1249
+ }) {
1250
+ const live = useAuth();
1251
+ const auth = supplied ?? live;
1252
+ const action = useAction();
1253
+ const expired = auth.status === "expired";
1254
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-action", children: [
1255
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1256
+ BasicButton,
1257
+ {
1258
+ ...props,
1259
+ disabled: disabled || !auth.isReady || action.pending || (signOut ? !auth.isSignedIn && !expired : auth.isSignedIn && !expired),
1260
+ "aria-busy": action.pending,
1261
+ onClick: (event) => {
1262
+ onClick?.(event);
1263
+ if (!event.defaultPrevented)
1264
+ void action.run(
1265
+ () => signOut ? auth.signOut() : auth.signIn(input)
1266
+ );
1267
+ },
1268
+ children: action.pending ? "Please wait\u2026" : children ?? (signOut ? "Sign out" : expired ? "Sign in again" : "Sign in")
1269
+ }
1270
+ ),
1271
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ActionError, { error: action.error, onClose: action.clearError })
1272
+ ] });
1273
+ }
1274
+ function SignInButton(props) {
1275
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AuthButton, { ...props });
1276
+ }
1277
+ function SignOutButton(props) {
1278
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AuthButton, { ...props, signOut: true });
1279
+ }
1280
+ function UserAvatar({
1281
+ accounts,
1282
+ auth,
1283
+ projectProfile,
1284
+ allowAddAccount,
1285
+ menuItems,
1286
+ ...avatarProps
1287
+ }) {
1288
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1289
+ UserMenu,
1290
+ {
1291
+ accounts,
1292
+ auth,
1293
+ projectProfile,
1294
+ allowAddAccount,
1295
+ menuItems,
1296
+ sync: avatarProps.sync,
1297
+ showSyncBadge: avatarProps.showSyncBadge,
1298
+ avatarProps
1299
+ }
1300
+ );
1301
+ }
1302
+ function AccountAvatar({
1303
+ profile: supplied,
1304
+ size = 32,
1305
+ showSyncBadge,
1306
+ sync,
1307
+ className = "",
1308
+ style,
1309
+ ...props
1310
+ }) {
1311
+ const accounts = useAccounts();
1312
+ const client = useRequiredClient();
1313
+ const profile = supplied === void 0 ? accounts.activeAccount : supplied;
1314
+ const name = profile?.name || (profile?.kind === "anon" ? "Local account" : profile?.handle || profile?.email || "Guest");
1315
+ const initials = name.trim().split(/\s+/).slice(0, 2).map((part) => Array.from(part)[0]).join("").toUpperCase();
1316
+ const avatar = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1317
+ import_avatar.Avatar.Root,
1318
+ {
1319
+ ...props,
1320
+ className: `basic-avatar ${className}`,
1321
+ style: { width: size, height: size, ...style },
1322
+ role: "img",
1323
+ "aria-label": props["aria-label"] ?? name,
1324
+ children: [
1325
+ profile?.picture && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1326
+ import_avatar.Avatar.Image,
1327
+ {
1328
+ src: profile.picture,
1329
+ alt: "",
1330
+ className: "basic-avatar-image",
1331
+ referrerPolicy: "no-referrer"
1332
+ }
1333
+ ),
1334
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_avatar.Avatar.Fallback, { className: "basic-avatar-fallback", children: initials || "?" })
1335
+ ]
1336
+ }
1337
+ );
1338
+ return showSyncBadge ?? client.mode === "sync" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-avatar-container", children: [
1339
+ avatar,
1340
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SyncStatus, { sync, className: "basic-avatar-sync" })
1341
+ ] }) : avatar;
1342
+ }
1343
+ function AuthStatus({
1344
+ auth: supplied,
1345
+ className = "",
1346
+ ...props
1347
+ }) {
1348
+ const live = useAuth();
1349
+ const auth = supplied ?? live;
1350
+ const expired = auth.status === "expired";
1351
+ const label = !auth.isReady || auth.status === "bootstrapping" ? "Checking session" : expired ? "Session expired" : auth.status === "recovering" ? "Reconnecting session" : auth.isSignedIn ? "Signed in" : auth.isAnonymous ? "Guest \xB7 local only" : "Signed out";
1352
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1353
+ "span",
1354
+ {
1355
+ ...props,
1356
+ role: "status",
1357
+ className: `basic-status ${className}`,
1358
+ "data-tone": expired || auth.error ? "warning" : auth.isSignedIn ? "success" : "neutral",
1359
+ children: [
1360
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "basic-dot" }),
1361
+ label
1362
+ ]
1363
+ }
1364
+ );
1365
+ }
1366
+ function SyncStatus({
1367
+ sync: supplied,
1368
+ source,
1369
+ className = "",
1370
+ ...props
1371
+ }) {
1372
+ const live = useSyncStatus(source);
1373
+ const client = useRequiredClient();
1374
+ const sync = supplied ?? live;
1375
+ if (client.mode === "rest") return null;
1376
+ const issues = sync.rejected.length + sync.conflicts.length;
1377
+ const labels = {
1378
+ idle: "Idle",
1379
+ bootstrapping: "Starting sync",
1380
+ connecting: "Connecting",
1381
+ online: "Synced",
1382
+ offline: "Offline",
1383
+ stopped: "Sync stopped",
1384
+ error: "Sync error",
1385
+ local: "Local only",
1386
+ stale: "Sync stale",
1387
+ ended: "Access ended"
1388
+ };
1389
+ const label = issues ? `${issues} sync ${issues === 1 ? "issue" : "issues"}` : sync.status === "online" && sync.pendingCount ? "Syncing" : labels[sync.status];
1390
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1391
+ "span",
1392
+ {
1393
+ ...props,
1394
+ role: "status",
1395
+ title: props.title ?? `${label}${sync.pendingCount > 0 ? ` \xB7 ${sync.pendingCount} pending` : ""}`,
1396
+ className: `basic-status ${className}`,
1397
+ "data-tone": issues || ["error", "stale", "ended"].includes(sync.status) ? "warning" : sync.status === "online" && !sync.pendingCount ? "success" : ["bootstrapping", "connecting"].includes(sync.status) || sync.status === "online" && sync.pendingCount > 0 ? "progress" : "neutral",
1398
+ children: [
1399
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "basic-dot" }),
1400
+ label,
1401
+ sync.pendingCount > 0 && ` \xB7 ${sync.pendingCount} pending`
1402
+ ]
1403
+ }
1404
+ );
1405
+ }
1406
+ function displayHandle(handle) {
1407
+ return handle ? `@${handle.replace(/^@+/, "")}` : "";
1408
+ }
1409
+ function UserButton(props) {
1410
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UserMenu, { ...props, trigger: "button" });
1411
+ }
1412
+ function UserMenu({
1413
+ accounts: supplied,
1414
+ auth: suppliedAuth,
1415
+ sync,
1416
+ showSyncStatus = true,
1417
+ showSyncBadge,
1418
+ shape = "rounded",
1419
+ trigger = "avatar",
1420
+ avatarProps,
1421
+ projectProfile,
1422
+ allowAddAccount = true,
1423
+ className = "",
1424
+ accountSettingsUrl,
1425
+ menuItems = []
1426
+ }) {
1427
+ const liveAccounts = useAccounts();
1428
+ const liveAuth = useAuth();
1429
+ const accounts = supplied ?? liveAccounts;
1430
+ const auth = suppliedAuth ?? liveAuth;
1431
+ const action = useAction();
1432
+ const [settingsOpen, setSettingsOpen] = (0, import_react13.useState)(false);
1433
+ const [clearAccountId, setClearAccountId] = (0, import_react13.useState)(null);
1434
+ const triggerRef = (0, import_react13.useRef)(null);
1435
+ const appearance = useAppearanceProps();
1436
+ const expired = auth.status === "expired";
1437
+ const active = accounts.activeAccount;
1438
+ const otherAccounts = accounts.accounts.filter(
1439
+ (account) => account.id !== active?.id
1440
+ );
1441
+ const name = active?.name || active?.kind !== "anon" && displayHandle(active?.handle) || "Local account";
1442
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: `basic-action ${className}`, children: [
1443
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_menu.Menu.Root, { children: [
1444
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1445
+ import_menu.Menu.Trigger,
1446
+ {
1447
+ ref: triggerRef,
1448
+ className: `basic-button basic-account-trigger basic-trigger-${trigger}`,
1449
+ "data-shape": shape,
1450
+ disabled: !auth.isReady || action.pending,
1451
+ "aria-label": "Open user menu",
1452
+ children: [
1453
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1454
+ AccountAvatar,
1455
+ {
1456
+ profile: accounts.activeAccount,
1457
+ sync,
1458
+ showSyncBadge,
1459
+ ...avatarProps
1460
+ }
1461
+ ),
1462
+ trigger === "button" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1463
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-identity", children: [
1464
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: name }),
1465
+ active?.kind !== "anon" && active?.handle && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { children: displayHandle(active.handle) })
1466
+ ] }),
1467
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1468
+ "svg",
1469
+ {
1470
+ className: "basic-chevron",
1471
+ width: "16",
1472
+ height: "16",
1473
+ viewBox: "0 0 24 24",
1474
+ fill: "none",
1475
+ stroke: "currentColor",
1476
+ strokeWidth: "2",
1477
+ strokeLinecap: "round",
1478
+ strokeLinejoin: "round",
1479
+ "aria-hidden": "true",
1480
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m6 9 6 6 6-6" })
1481
+ }
1482
+ )
1483
+ ] })
1484
+ ]
1485
+ }
1486
+ ),
1487
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_menu.Menu.Positioner, { sideOffset: 8, className: "basic-positioner", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_menu.Menu.Popup, { ...appearance, className: "basic-ui basic-menu", children: [
1488
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-menu-profile", children: [
1489
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1490
+ AccountAvatar,
1491
+ {
1492
+ profile: active,
1493
+ size: 48,
1494
+ sync,
1495
+ showSyncBadge: false
1496
+ }
1497
+ ),
1498
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-identity", children: [
1499
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: active ? name : "No active account" }),
1500
+ active?.kind !== "anon" && active?.handle && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { children: displayHandle(active.handle) }),
1501
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-account-statuses", children: [
1502
+ expired && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "basic-status", "data-tone": "warning", children: "Expired" }),
1503
+ showSyncStatus && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SyncStatus, { sync })
1504
+ ] })
1505
+ ] })
1506
+ ] }),
1507
+ expired && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1508
+ import_menu.Menu.Item,
1509
+ {
1510
+ className: "basic-menu-item basic-menu-reauth",
1511
+ disabled: action.pending,
1512
+ onClick: () => void action.run(() => auth.signIn()),
1513
+ children: "Sign in again"
1514
+ }
1515
+ ),
1516
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1517
+ import_menu.Menu.Item,
1518
+ {
1519
+ className: "basic-menu-item basic-manage-account",
1520
+ onClick: () => setSettingsOpen(true),
1521
+ children: [
1522
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1523
+ "svg",
1524
+ {
1525
+ className: "basic-menu-icon",
1526
+ width: "16",
1527
+ height: "16",
1528
+ viewBox: "0 0 24 24",
1529
+ fill: "none",
1530
+ stroke: "currentColor",
1531
+ strokeWidth: "1.75",
1532
+ strokeLinecap: "round",
1533
+ strokeLinejoin: "round",
1534
+ "aria-hidden": "true",
1535
+ children: [
1536
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "12", cy: "7", r: "4" }),
1537
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" })
1538
+ ]
1539
+ }
1540
+ ),
1541
+ "Manage account"
1542
+ ]
1543
+ }
1544
+ ),
1545
+ menuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1546
+ import_menu.Menu.Item,
1547
+ {
1548
+ className: "basic-menu-item",
1549
+ render: item.href !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { href: item.href }) : void 0,
1550
+ disabled: item.disabled || action.pending,
1551
+ onClick: () => {
1552
+ if (item.onClick) void action.run(item.onClick);
1553
+ },
1554
+ children: [
1555
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "basic-menu-icon", "aria-hidden": "true", children: item.icon }),
1556
+ item.label
1557
+ ]
1558
+ },
1559
+ item.id
1560
+ )),
1561
+ (auth.isSignedIn || expired || active?.kind === "anon") && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1562
+ import_menu.Menu.Item,
1563
+ {
1564
+ className: "basic-menu-item basic-menu-signout",
1565
+ disabled: action.pending,
1566
+ onClick: () => active?.kind === "anon" ? setClearAccountId(active.id) : void action.run(() => auth.signOut()),
1567
+ children: [
1568
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1569
+ "svg",
1570
+ {
1571
+ className: "basic-menu-icon",
1572
+ width: "16",
1573
+ height: "16",
1574
+ viewBox: "0 0 24 24",
1575
+ fill: "none",
1576
+ stroke: "currentColor",
1577
+ strokeWidth: "1.75",
1578
+ strokeLinecap: "round",
1579
+ strokeLinejoin: "round",
1580
+ "aria-hidden": "true",
1581
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9" })
1582
+ }
1583
+ ),
1584
+ active?.kind === "anon" ? "Clear account" : "Sign out"
1585
+ ]
1586
+ }
1587
+ ),
1588
+ otherAccounts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1589
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_menu.Menu.Separator, { className: "basic-separator" }),
1590
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "basic-menu-heading", children: "Switch accounts" })
1591
+ ] }),
1592
+ otherAccounts.map((account) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1593
+ import_menu.Menu.Item,
1594
+ {
1595
+ className: "basic-menu-item",
1596
+ disabled: action.pending,
1597
+ onClick: () => void action.run(() => accounts.switchAccount(account.id)),
1598
+ children: [
1599
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1600
+ AccountAvatar,
1601
+ {
1602
+ profile: account,
1603
+ size: 32,
1604
+ sync,
1605
+ showSyncBadge: false
1606
+ }
1607
+ ),
1608
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-identity", children: [
1609
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: account.name || account.kind !== "anon" && displayHandle(account.handle) || (account.kind === "anon" ? "Local account" : "Account") }),
1610
+ account.kind !== "anon" && account.handle && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { children: displayHandle(account.handle) })
1611
+ ] }),
1612
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "basic-account-statuses", children: account.auth.status === "expired" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "basic-status", "data-tone": "warning", children: "Expired" }) : null })
1613
+ ]
1614
+ },
1615
+ account.id
1616
+ )),
1617
+ (allowAddAccount || !auth.isSignedIn && !expired) && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1618
+ import_menu.Menu.Item,
1619
+ {
1620
+ className: "basic-menu-item",
1621
+ disabled: action.pending,
1622
+ onClick: () => void action.run(
1623
+ () => allowAddAccount ? accounts.addAccount({ signIn: true }) : auth.signIn()
1624
+ ),
1625
+ children: [
1626
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1627
+ "svg",
1628
+ {
1629
+ className: "basic-menu-icon",
1630
+ width: "16",
1631
+ height: "16",
1632
+ viewBox: "0 0 24 24",
1633
+ fill: "none",
1634
+ stroke: "currentColor",
1635
+ strokeWidth: "1.75",
1636
+ strokeLinecap: "round",
1637
+ "aria-hidden": "true",
1638
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 5v14M5 12h14" })
1639
+ }
1640
+ ),
1641
+ "Add account"
1642
+ ]
1643
+ }
1644
+ )
1645
+ ] }) }) })
1646
+ ] }),
1647
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1648
+ ActionError,
1649
+ {
1650
+ error: action.error,
1651
+ onClose: action.clearError,
1652
+ finalFocus: triggerRef
1653
+ }
1654
+ ),
1655
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1656
+ Modal,
1657
+ {
1658
+ open: clearAccountId !== null,
1659
+ onOpenChange: (open) => {
1660
+ if (!open) setClearAccountId(null);
1661
+ },
1662
+ trigger: null,
1663
+ finalFocus: triggerRef,
1664
+ title: "Clear local account?",
1665
+ description: "This deletes this account\u2019s local data, including unsynced changes. This cannot be undone.",
1666
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-actions", children: [
1667
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1668
+ BasicButton,
1669
+ {
1670
+ disabled: action.pending,
1671
+ onClick: () => setClearAccountId(null),
1672
+ children: "Cancel"
1673
+ }
1674
+ ),
1675
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1676
+ BasicButton,
1677
+ {
1678
+ disabled: action.pending,
1679
+ onClick: () => {
1680
+ const id = clearAccountId;
1681
+ if (!id) return;
1682
+ setClearAccountId(null);
1683
+ void action.run(() => accounts.removeAccount(id));
1684
+ },
1685
+ children: "Clear account"
1686
+ }
1687
+ )
1688
+ ] })
1689
+ }
1690
+ ),
1691
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1692
+ AccountSettingsModal,
1693
+ {
1694
+ auth,
1695
+ accounts,
1696
+ open: settingsOpen,
1697
+ onOpenChange: setSettingsOpen,
1698
+ trigger: null,
1699
+ finalFocus: triggerRef,
1700
+ accountSettingsUrl,
1701
+ projectProfile,
1702
+ sync
1703
+ }
1704
+ )
1705
+ ] });
1706
+ }
1707
+ function ActionError({
1708
+ error,
1709
+ onClose,
1710
+ finalFocus
1711
+ }) {
1712
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1713
+ Modal,
1714
+ {
1715
+ open: !!error,
1716
+ onOpenChange: (open) => {
1717
+ if (!open) onClose();
1718
+ },
1719
+ trigger: null,
1720
+ finalFocus,
1721
+ title: "Unable to complete action",
1722
+ description: "Your request could not be completed.",
1723
+ children: [
1724
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "basic-error", children: error }),
1725
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BasicButton, { onClick: onClose, children: "Dismiss" })
1726
+ ]
1727
+ }
1728
+ );
1729
+ }
1730
+ function Modal({
1731
+ open,
1732
+ onOpenChange,
1733
+ trigger,
1734
+ finalFocus,
1735
+ title,
1736
+ description,
1737
+ header,
1738
+ sectionLabel,
1739
+ children
1740
+ }) {
1741
+ const appearance = useAppearanceProps();
1742
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_dialog.Dialog.Root, { open, onOpenChange, children: [
1743
+ trigger !== null && ((0, import_react13.isValidElement)(trigger) ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dialog.Dialog.Trigger, { render: trigger }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dialog.Dialog.Trigger, { render: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BasicButton, {}), children: trigger ?? title })),
1744
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_dialog.Dialog.Portal, { children: [
1745
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dialog.Dialog.Backdrop, { className: "basic-backdrop" }),
1746
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1747
+ import_dialog.Dialog.Popup,
1748
+ {
1749
+ ...appearance,
1750
+ finalFocus,
1751
+ className: "basic-ui basic-dialog",
1752
+ children: [
1753
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1754
+ "div",
1755
+ {
1756
+ className: `basic-dialog-heading${header ? " basic-dialog-heading-overlay" : ""}`,
1757
+ children: [
1758
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dialog.Dialog.Title, { className: header ? "basic-sr-only" : "basic-title", children: title }),
1759
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1760
+ import_dialog.Dialog.Close,
1761
+ {
1762
+ className: "basic-button",
1763
+ "aria-label": `Close ${title.toLowerCase()}`,
1764
+ children: "\u2715"
1765
+ }
1766
+ )
1767
+ ]
1768
+ }
1769
+ ),
1770
+ header,
1771
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1772
+ import_dialog.Dialog.Description,
1773
+ {
1774
+ className: header ? "basic-sr-only" : "basic-muted",
1775
+ children: description
1776
+ }
1777
+ ),
1778
+ sectionLabel && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "basic-modal-section", children: sectionLabel }),
1779
+ children
1780
+ ]
1781
+ }
1782
+ )
1783
+ ] })
1784
+ ] });
1785
+ }
1786
+ function AccountSettingsModal({
1787
+ auth: suppliedAuth,
1788
+ accounts: suppliedAccounts,
1789
+ accountSettingsUrl,
1790
+ projectProfile,
1791
+ sync,
1792
+ children,
1793
+ ...props
1794
+ }) {
1795
+ const liveAuth = useAuth();
1796
+ const liveAccounts = useAccounts();
1797
+ const auth = suppliedAuth ?? liveAuth;
1798
+ const accounts = suppliedAccounts ?? liveAccounts;
1799
+ const liveSync = useSyncStatus();
1800
+ const syncState = sync ?? liveSync;
1801
+ const client = useRequiredClient();
1802
+ const account = accounts.activeAccount;
1803
+ const copyAction = useAction();
1804
+ const [copied, setCopied] = (0, import_react13.useState)(null);
1805
+ const details = [
1806
+ [
1807
+ "Account DID",
1808
+ account?.kind === "anon" ? "Not assigned (local account)" : account?.did ?? auth.did ?? "Unavailable"
1809
+ ],
1810
+ [
1811
+ "PDS URL",
1812
+ account?.kind === "anon" ? "Not connected (local account)" : auth.user?.pds_url ?? "Unavailable"
1813
+ ],
1814
+ ["Local account ID", account?.id ?? "None"],
1815
+ ["Account kind", account?.kind ?? "None"],
1816
+ ["Storage prefix", account?.storagePrefix ?? "None"],
1817
+ ["Client mode", client.mode],
1818
+ ["Auth state", auth.status],
1819
+ ["Ready", auth.isReady ? "Yes" : "No"],
1820
+ ["Can write", auth.canWrite ? "Yes" : "No"],
1821
+ ["Read-only reason", auth.readOnlyReason ?? "None"],
1822
+ ["Auth error code", auth.error?.code ?? "None"],
1823
+ ["Sync state", syncState.status],
1824
+ ["Pending writes", String(syncState.pendingCount)],
1825
+ ["Rejected writes", String(syncState.rejected.length)],
1826
+ ["Conflicts", String(syncState.conflicts.length)]
1827
+ ];
1828
+ const diagnostics = JSON.stringify(Object.fromEntries(details), null, 2);
1829
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1830
+ Modal,
1831
+ {
1832
+ ...props,
1833
+ title: "Account settings",
1834
+ description: "Your identity and session on this device.",
1835
+ header: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AccountHeader, { account: accounts.activeAccount, sync }),
1836
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_tabs.Tabs.Root, { defaultValue: "profile", children: [
1837
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1838
+ import_tabs.Tabs.List,
1839
+ {
1840
+ className: "basic-tabs",
1841
+ "aria-label": "Account settings sections",
1842
+ children: [
1843
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tabs.Tabs.Tab, { value: "profile", children: "Profile" }),
1844
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tabs.Tabs.Tab, { value: "advanced", children: "Advanced" })
1845
+ ]
1846
+ }
1847
+ ),
1848
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_tabs.Tabs.Panel, { value: "profile", keepMounted: true, children: [
1849
+ auth.isSignedIn && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1850
+ ProjectProfileEditor,
1851
+ {
1852
+ profile: projectProfile,
1853
+ canWrite: auth.canWrite
1854
+ },
1855
+ accounts.activeAccount?.id ?? auth.did
1856
+ ),
1857
+ accountSettingsUrl && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { className: "basic-link", href: accountSettingsUrl, children: "Manage profile and security \u2197" }),
1858
+ children,
1859
+ !auth.isSignedIn && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "basic-actions", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SignInButton, { auth }) })
1860
+ ] }),
1861
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_tabs.Tabs.Panel, { value: "advanced", children: [
1862
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "basic-muted", children: "Read-only diagnostics for this account." }),
1863
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dl", { className: "basic-details", children: details.map(([label, value]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react13.Fragment, { children: [
1864
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dt", { children: label }),
1865
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dd", { children: value })
1866
+ ] }, label)) }),
1867
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-actions", children: [
1868
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1869
+ BasicButton,
1870
+ {
1871
+ disabled: copyAction.pending,
1872
+ onClick: () => {
1873
+ setCopied(null);
1874
+ void copyAction.run(async () => {
1875
+ if (!navigator.clipboard?.writeText)
1876
+ throw new Error("Clipboard is unavailable in this browser.");
1877
+ await navigator.clipboard.writeText(diagnostics);
1878
+ setCopied(diagnostics);
1879
+ });
1880
+ },
1881
+ children: "Copy to clipboard"
1882
+ }
1883
+ ),
1884
+ copied === diagnostics && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { role: "status", className: "basic-muted", children: "Copied" })
1885
+ ] }),
1886
+ copyAction.error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "basic-error", children: copyAction.error })
1887
+ ] })
1888
+ ] })
1889
+ }
1890
+ );
1891
+ }
1892
+ function AccountHeader({
1893
+ account,
1894
+ sync
1895
+ }) {
1896
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-profile", children: [
1897
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1898
+ AccountAvatar,
1899
+ {
1900
+ profile: account,
1901
+ size: 72,
1902
+ sync,
1903
+ showSyncBadge: false
1904
+ }
1905
+ ),
1906
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-identity", children: [
1907
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: account?.name || account?.kind !== "anon" && displayHandle(account?.handle) || "Local account" }),
1908
+ account?.kind !== "anon" && account?.handle && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { children: displayHandle(account.handle) }),
1909
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "basic-account-statuses", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SyncStatus, { sync }) })
1910
+ ] })
1911
+ ] });
1912
+ }
1913
+ function ProjectProfileEditor({
1914
+ profile: supplied,
1915
+ canWrite
1916
+ }) {
1917
+ const live = useProjectProfile(supplied === void 0);
1918
+ const profile = supplied ?? live;
1919
+ const action = useAction();
1920
+ const [draft, setDraft] = (0, import_react13.useState)({});
1921
+ const [saved, setSaved] = (0, import_react13.useState)(false);
1922
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1923
+ "form",
1924
+ {
1925
+ className: "basic-profile-editor",
1926
+ onSubmit: (event) => {
1927
+ event.preventDefault();
1928
+ if (!canWrite || !Object.keys(draft).length) return;
1929
+ void action.run(async () => {
1930
+ await profile.update(draft);
1931
+ setDraft({});
1932
+ setSaved(true);
1933
+ });
1934
+ },
1935
+ children: [
1936
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "basic-section-label", children: "Personal information" }),
1937
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "basic-muted", children: "Only this app sees these overrides. Clear a field to use your universal profile value." }),
1938
+ profile.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "status", children: "Loading project profile\u2026" }) : profile.error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1939
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "basic-error", children: profile.error.message }),
1940
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BasicButton, { onClick: profile.refresh, children: "Retry profile" })
1941
+ ] }) : profile.data && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("fieldset", { disabled: !canWrite || action.pending, children: [
1942
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "basic-field", children: [
1943
+ "Display name",
1944
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1945
+ "input",
1946
+ {
1947
+ className: "basic-input",
1948
+ type: "text",
1949
+ maxLength: 64,
1950
+ value: ("name" in draft ? draft.name : profile.data?.profile.name) ?? "",
1951
+ onChange: (event) => {
1952
+ setSaved(false);
1953
+ setDraft((current) => ({
1954
+ ...current,
1955
+ name: event.target.value || null
1956
+ }));
1957
+ }
1958
+ }
1959
+ )
1960
+ ] }),
1961
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-actions basic-modal-footer", children: [
1962
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1963
+ BasicButton,
1964
+ {
1965
+ variant: "ghost",
1966
+ onClick: () => {
1967
+ setDraft({});
1968
+ setSaved(false);
1969
+ },
1970
+ children: "Cancel"
1971
+ }
1972
+ ),
1973
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1974
+ BasicButton,
1975
+ {
1976
+ type: "submit",
1977
+ variant: "solid",
1978
+ disabled: !Object.keys(draft).length,
1979
+ children: "Save changes"
1980
+ }
1981
+ )
1982
+ ] })
1983
+ ] }),
1984
+ action.error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "basic-error", children: action.error }),
1985
+ saved && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "status", children: "Project profile saved." })
1986
+ ]
1987
+ }
1988
+ );
1989
+ }
1990
+ function SharesModal({
1991
+ auth: supplied,
1992
+ accounts: suppliedAccounts,
1993
+ sync,
1994
+ shares,
1995
+ scope,
1996
+ repo = "default",
1997
+ ...props
1998
+ }) {
1999
+ const live = useAuth();
2000
+ const liveAccounts = useAccounts();
2001
+ const auth = supplied ?? live;
2002
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2003
+ Modal,
2004
+ {
2005
+ ...props,
2006
+ title: "Shares",
2007
+ description: "Manage incoming invitations and share access to selected data.",
2008
+ header: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2009
+ AccountHeader,
2010
+ {
2011
+ account: (suppliedAccounts ?? liveAccounts).activeAccount,
2012
+ sync
2013
+ }
2014
+ ),
2015
+ children: !auth.isReady ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "status", children: "Checking session\u2026" }) : !auth.isSignedIn ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
2016
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "basic-muted", children: "Sign in to share data." }),
2017
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SignInButton, { auth })
2018
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2019
+ SharesContent,
2020
+ {
2021
+ shares,
2022
+ scope,
2023
+ repo,
2024
+ canWrite: auth.canWrite
2025
+ },
2026
+ auth.did ?? "account"
2027
+ )
2028
+ }
2029
+ );
2030
+ }
2031
+ function SharesContent({
2032
+ shares: supplied,
2033
+ scope,
2034
+ repo,
2035
+ canWrite
2036
+ }) {
2037
+ const live = useOutgoingShares();
2038
+ const shares = supplied ?? live;
2039
+ const action = useAction();
2040
+ const [recipient, setRecipient] = (0, import_react13.useState)("");
2041
+ const [role, setRole] = (0, import_react13.useState)("viewer");
2042
+ const [confirmation, setConfirmation] = (0, import_react13.useState)(null);
2043
+ const [message, setMessage] = (0, import_react13.useState)("");
2044
+ const scopeValid = scope.length > 0 && scope.every(
2045
+ (item) => item.table.trim() && (item.recordIds === void 0 || item.recordIds.length > 0)
2046
+ );
2047
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_tabs.Tabs.Root, { defaultValue: "outgoing", className: "basic-shares", children: [
2048
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_tabs.Tabs.List, { className: "basic-tabs", "aria-label": "Share direction", children: [
2049
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tabs.Tabs.Tab, { value: "outgoing", children: "Outgoing" }),
2050
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tabs.Tabs.Tab, { value: "incoming", children: "Incoming invitations" })
2051
+ ] }),
2052
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tabs.Tabs.Panel, { value: "incoming", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { "aria-label": "Incoming invitations", children: [
2053
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "basic-title", children: "Incoming invitations" }),
2054
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "basic-muted", children: "View, accept, or decline incoming invitations in Basic ID. Your app session cannot access the account-wide inbox." }),
2055
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { className: "basic-link", href: shares.manageUrl(), children: "Open incoming invitations in Basic ID \u2197" })
2056
+ ] }) }),
2057
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_tabs.Tabs.Panel, { value: "outgoing", children: [
2058
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "basic-muted", children: "Revoking access stops future requests. It cannot retract data the recipient already downloaded." }),
2059
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-scope", children: [
2060
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "New invitation permissions" }),
2061
+ scope.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
2062
+ item.table,
2063
+ " \xB7",
2064
+ " ",
2065
+ item.recordIds ? `${item.recordIds.length} selected records` : "all records"
2066
+ ] }, index))
2067
+ ] }),
2068
+ !canWrite && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "basic-error", children: "This session is read only. Sharing changes are disabled." }),
2069
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2070
+ "form",
2071
+ {
2072
+ className: "basic-share-form",
2073
+ onSubmit: (event) => {
2074
+ event.preventDefault();
2075
+ if (!recipient.trim() || !scopeValid || !canWrite) return;
2076
+ void action.run(async () => {
2077
+ await shares.create({
2078
+ repo,
2079
+ scope,
2080
+ role,
2081
+ ...recipient.trim().startsWith("did:") ? { recipientDid: recipient.trim() } : { recipientHandle: recipient.trim().replace(/^@+/, "") }
2082
+ });
2083
+ setRecipient("");
2084
+ setMessage("Invitation sent.");
2085
+ shares.refresh();
2086
+ });
2087
+ },
2088
+ children: [
2089
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "basic-field", children: [
2090
+ "Recipient handle or DID",
2091
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2092
+ "input",
2093
+ {
2094
+ className: "basic-input",
2095
+ value: recipient,
2096
+ onChange: (event) => setRecipient(event.target.value),
2097
+ placeholder: "@alex.basic.id",
2098
+ required: true,
2099
+ disabled: action.pending || !canWrite
2100
+ }
2101
+ )
2102
+ ] }),
2103
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "basic-field", children: [
2104
+ "Permission",
2105
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2106
+ "select",
2107
+ {
2108
+ className: "basic-input",
2109
+ value: role,
2110
+ onChange: (event) => setRole(event.target.value),
2111
+ disabled: action.pending || !canWrite,
2112
+ children: [
2113
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "viewer", children: "Can view" }),
2114
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "editor", children: "Can edit" })
2115
+ ]
2116
+ }
2117
+ )
2118
+ ] }),
2119
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2120
+ BasicButton,
2121
+ {
2122
+ type: "submit",
2123
+ variant: "solid",
2124
+ disabled: action.pending || !canWrite || !scopeValid || !recipient.trim(),
2125
+ children: action.pending ? "Please wait\u2026" : "Send invitation"
2126
+ }
2127
+ )
2128
+ ]
2129
+ }
2130
+ ),
2131
+ !scopeValid && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "basic-error", children: "Select at least one table or record to share." }),
2132
+ action.error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "basic-error", children: action.error }),
2133
+ message && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "status", className: "basic-muted", children: message }),
2134
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-section-heading", children: [
2135
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "basic-title", children: "Outgoing shares \xB7 all permissions" }),
2136
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2137
+ BasicButton,
2138
+ {
2139
+ disabled: action.pending || shares.isLoading,
2140
+ onClick: shares.refresh,
2141
+ children: "Refresh"
2142
+ }
2143
+ )
2144
+ ] }),
2145
+ shares.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "status", children: "Loading shares\u2026" }) : shares.error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "basic-error", children: shares.error.message }) : !shares.data.length ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "basic-empty", children: "No outgoing shares yet." }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: "basic-share-list", children: shares.data.map((share) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { children: [
2146
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-identity", children: [
2147
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: share.display.shareName || share.recipientDid }),
2148
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("small", { children: [
2149
+ share.role === "viewer" ? "Can view" : "Can edit",
2150
+ " \xB7",
2151
+ " ",
2152
+ share.effectiveState,
2153
+ " \xB7",
2154
+ " ",
2155
+ share.scope.map((item) => item.table).join(", ")
2156
+ ] })
2157
+ ] }),
2158
+ share.state !== "ended" && (confirmation === share.id ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-actions", children: [
2159
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Remove access?" }),
2160
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2161
+ BasicButton,
2162
+ {
2163
+ disabled: action.pending || !canWrite,
2164
+ onClick: () => void action.run(async () => {
2165
+ await (share.state === "pending" ? shares.cancel(share.id) : shares.revoke(share.id));
2166
+ setConfirmation(null);
2167
+ setMessage(
2168
+ share.state === "pending" ? "Invitation canceled." : "Access revoked."
2169
+ );
2170
+ shares.refresh();
2171
+ }),
2172
+ children: [
2173
+ "Confirm",
2174
+ " ",
2175
+ share.state === "pending" ? "cancel" : "revoke"
2176
+ ]
2177
+ }
2178
+ ),
2179
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2180
+ BasicButton,
2181
+ {
2182
+ disabled: action.pending,
2183
+ onClick: () => setConfirmation(null),
2184
+ children: "Keep access"
2185
+ }
2186
+ )
2187
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2188
+ BasicButton,
2189
+ {
2190
+ disabled: action.pending || !canWrite,
2191
+ onClick: () => setConfirmation(share.id),
2192
+ children: share.state === "pending" ? "Cancel invitation" : "Revoke access"
2193
+ }
2194
+ ))
2195
+ ] }, share.id)) })
2196
+ ] })
2197
+ ] });
2198
+ }
1090
2199
  // Annotate the CommonJS export names for ESM import in node:
1091
2200
  0 && (module.exports = {
2201
+ AccountSettingsModal,
2202
+ AuthStatus,
2203
+ BasicButton,
1092
2204
  BasicProvider,
2205
+ BasicUIProvider,
1093
2206
  BrowserKeyValueStorage,
1094
2207
  BrowserTokenStore,
1095
2208
  PersistenceStore,
2209
+ SharesModal,
2210
+ SignInButton,
2211
+ SignOutButton,
2212
+ SyncStatus,
2213
+ UserAvatar,
2214
+ UserButton,
2215
+ UserMenu,
1096
2216
  browserCurrentUrl,
1097
2217
  browserNavigate,
1098
2218
  browserReplaceUrl,
@@ -1110,6 +2230,7 @@ function createBasic(config) {
1110
2230
  useFiles,
1111
2231
  useMounts,
1112
2232
  useOutgoingShares,
2233
+ useProjectProfile,
1113
2234
  useQuery,
1114
2235
  useRepos,
1115
2236
  useSchemaStatus,