@basictech/react 0.12.0-beta.0 → 0.12.0-beta.2

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,
@@ -59,10 +72,21 @@ __export(index_exports, {
59
72
  });
60
73
  module.exports = __toCommonJS(index_exports);
61
74
 
75
+ // src/create-basic.tsx
76
+ var import_react12 = require("react");
77
+
78
+ // src/context.ts
79
+ var import_react = require("react");
80
+ var BasicClientContext = (0, import_react.createContext)(null);
81
+
62
82
  // src/create-client.ts
63
83
  var import_core4 = require("@basictech/core");
64
84
 
65
85
  // src/adapters/broadcast-channel.ts
86
+ function supportsAccessTokenAdoption(store) {
87
+ const candidate = store;
88
+ return typeof candidate?.accessToken === "function" && typeof candidate?.adoptAccessToken === "function";
89
+ }
66
90
  function createBrowserMessageChannel(name) {
67
91
  const channel = new BroadcastChannel(name);
68
92
  const adapter = {
@@ -73,12 +97,11 @@ function createBrowserMessageChannel(name) {
73
97
  channel.onmessage = (event) => adapter.onmessage?.({ data: event.data });
74
98
  return adapter;
75
99
  }
76
- function createBrowserAuthChannelFactory(clientId, tokenStore) {
77
- const prefix = `basic_auth:${clientId}:`;
78
- return (name) => {
100
+ function createBrowserAuthChannelFactory(tokenStore) {
101
+ return (name, context) => {
79
102
  const channel = createBrowserMessageChannel(name);
80
- const profileId = name.startsWith(prefix) ? name.slice(prefix.length) : "";
81
- const tokenKey = `u:${profileId}:basic_tokens`;
103
+ if (!context) return channel;
104
+ const { tokenKey } = context;
82
105
  const adapter = {
83
106
  postMessage: (message) => {
84
107
  const outgoing = message;
@@ -620,32 +643,27 @@ function browserReconcileTrigger(listener) {
620
643
  function createBasicClient(config) {
621
644
  const local = browserStorage("localStorage") ?? new import_core4.MemoryKeyValueStorage();
622
645
  const session = browserStorage("sessionStorage") ?? new import_core4.MemoryKeyValueStorage();
623
- const defaultTokenStore = config.tokenStore ? null : new BrowserTokenStore(local);
646
+ const tokenStore = config.tokenStore ?? new BrowserTokenStore(local);
624
647
  const canBroadcast = typeof BroadcastChannel !== "undefined";
625
648
  const canPersistReplica = typeof indexedDB !== "undefined";
649
+ const messageChannel = !canBroadcast ? void 0 : supportsAccessTokenAdoption(tokenStore) ? createBrowserAuthChannelFactory(tokenStore) : createBrowserMessageChannel;
626
650
  return (0, import_core4.createBasicClient)({
627
651
  ...config,
628
652
  kv: config.kv ?? local,
629
- tokenStore: config.tokenStore ?? defaultTokenStore,
653
+ tokenStore,
630
654
  sessionStorage: config.sessionStorage ?? session,
631
655
  replicaStore: config.replicaStore ?? (canPersistReplica ? new PersistenceStore(config.clientId) : new import_core4.MemoryReplicaStoreFactory()),
632
656
  navigate: config.navigate ?? browserNavigate,
633
657
  currentUrl: config.currentUrl ?? browserCurrentUrl,
634
658
  replaceUrl: config.replaceUrl ?? browserReplaceUrl,
635
659
  reconcileTrigger: config.reconcileTrigger ?? browserReconcileTrigger,
636
- createMessageChannel: config.createMessageChannel ?? (canBroadcast && defaultTokenStore ? createBrowserAuthChannelFactory(config.clientId, defaultTokenStore) : void 0),
660
+ createMessageChannel: config.createMessageChannel ?? messageChannel,
637
661
  uploadTransport: config.uploadTransport ?? (typeof XMLHttpRequest === "undefined" ? void 0 : browserUploadTransport)
638
662
  });
639
663
  }
640
664
 
641
665
  // src/provider.tsx
642
666
  var import_react2 = require("react");
643
-
644
- // src/context.ts
645
- var import_react = require("react");
646
- var BasicClientContext = (0, import_react.createContext)(null);
647
-
648
- // src/provider.tsx
649
667
  var import_jsx_runtime = require("react/jsx-runtime");
650
668
  var clientLifecycles = /* @__PURE__ */ new WeakMap();
651
669
  function retainClient(client) {
@@ -727,6 +745,10 @@ function useRequiredClient() {
727
745
  function useClientSnapshot(client) {
728
746
  return (0, import_react3.useSyncExternalStore)(client.subscribe, client.getSnapshot, client.getSnapshot);
729
747
  }
748
+ function useSignInGate(snapshot) {
749
+ const code = snapshot.isReady && !snapshot.isSignedIn ? snapshot.readOnlyReason ?? "AUTHORIZATION_REQUIRED" : null;
750
+ return (0, import_react3.useMemo)(() => code === null ? null : new import_core5.BasicError(code, code === "AUTH_EXPIRED" ? "Session expired. Sign in again to load this list." : "Sign in to load this list."), [code]);
751
+ }
730
752
  function toBasicError(error, fallback = "UNKNOWN_ERROR") {
731
753
  if (error instanceof import_core5.BasicError) return error;
732
754
  return new import_core5.BasicError(fallback, error instanceof Error ? error.message : String(error));
@@ -775,15 +797,15 @@ function useAsyncResult(load, initialData, enabled, settled, dependencies) {
775
797
  function useAccountsFor(client) {
776
798
  const snapshot = useClientSnapshot(client);
777
799
  const switchAccount = (0, import_react4.useCallback)((id) => client.switchAccount(id), [client]);
778
- const addAccount = (0, import_react4.useCallback)(() => client.addAccount(), [client]);
800
+ const addAccount = (0, import_react4.useCallback)((options) => client.addAccount(options), [client]);
779
801
  const removeAccount = (0, import_react4.useCallback)((id) => client.removeAccount(id), [client]);
780
802
  return (0, import_react4.useMemo)(() => ({
781
803
  accounts: snapshot.accounts,
782
- active: snapshot.activeProfile,
804
+ activeAccount: snapshot.activeAccount,
783
805
  switchAccount,
784
806
  addAccount,
785
807
  removeAccount
786
- }), [snapshot.accounts, snapshot.activeProfile, switchAccount, addAccount, removeAccount]);
808
+ }), [snapshot.accounts, snapshot.activeAccount, switchAccount, addAccount, removeAccount]);
787
809
  }
788
810
  function useAccounts() {
789
811
  return useAccountsFor(useRequiredClient());
@@ -791,7 +813,6 @@ function useAccounts() {
791
813
 
792
814
  // src/hooks/auth.ts
793
815
  var import_react5 = require("react");
794
- var import_core6 = require("@basictech/core");
795
816
  function useAuthFor(client) {
796
817
  const snapshot = useClientSnapshot(client);
797
818
  const signIn = (0, import_react5.useCallback)((input) => client.signIn(input), [client]);
@@ -804,7 +825,7 @@ function useAuthFor(client) {
804
825
  canWrite: snapshot.canWrite,
805
826
  readOnlyReason: snapshot.readOnlyReason,
806
827
  status: snapshot.authStatus,
807
- error: snapshot.authErrorCode ? new import_core6.BasicError(snapshot.authErrorCode) : null,
828
+ error: snapshot.authError,
808
829
  user: snapshot.user,
809
830
  did: snapshot.did,
810
831
  handle: snapshot.handle,
@@ -817,6 +838,9 @@ function useAuth() {
817
838
  return useAuthFor(useRequiredClient());
818
839
  }
819
840
 
841
+ // src/hooks/basic.ts
842
+ var import_react8 = require("react");
843
+
820
844
  // src/hooks/db.ts
821
845
  function useDbFor(client, source = "default") {
822
846
  return client.db(source);
@@ -893,51 +917,41 @@ function useBasicFor(client) {
893
917
  const auth = useAuthFor(client);
894
918
  const accounts = useAccountsFor(client);
895
919
  const sync = useSyncStatusFor(client);
896
- const repos = useReposFor(client);
897
- return {
920
+ const repos = useReposFor(client).repos;
921
+ const db = useDbFor(client);
922
+ return (0, import_react8.useMemo)(() => ({
898
923
  ...auth,
899
924
  client,
900
- db: useDbFor(client),
925
+ db,
901
926
  accounts,
902
927
  sync,
903
- repos: repos.repos
904
- };
928
+ repos
929
+ }), [auth, client, db, accounts, sync, repos]);
905
930
  }
906
931
  function useBasic() {
907
932
  return useBasicFor(useRequiredClient());
908
933
  }
909
934
 
910
935
  // src/hooks/files.ts
911
- var import_react8 = require("react");
936
+ var import_react9 = require("react");
912
937
  var zero = () => 0;
913
938
  function useFilesFor(client, query = {}, options = {}) {
914
939
  const source = options.source ?? "default";
915
940
  const sourceKey = JSON.stringify(source);
916
941
  const queryKey = JSON.stringify(query);
917
942
  const snapshot = useClientSnapshot(client);
918
- const subscription = (0, import_react8.useMemo)(
943
+ const subscription = (0, import_react9.useMemo)(
919
944
  () => client.queryStore.collection(source, "_files"),
920
945
  // eslint-disable-next-line react-hooks/exhaustive-deps
921
946
  [client, sourceKey]
922
947
  );
923
- const version = (0, import_react8.useSyncExternalStore)(subscription.subscribe, subscription.getSnapshot, zero);
948
+ const version = (0, import_react9.useSyncExternalStore)(subscription.subscribe, subscription.getSnapshot, zero);
924
949
  return useAsyncResult(
925
- async () => {
926
- const files = client.db(source).files;
927
- if (source !== "default" && "mountId" in source) {
928
- const page = await files.list({
929
- ...query.prefix !== void 0 ? { prefix: query.prefix } : {},
930
- ...query.limit !== void 0 ? { limit: query.limit } : {},
931
- ...query.cursor !== void 0 ? { cursor: query.cursor } : {}
932
- });
933
- return page.data;
934
- }
935
- return (await files.list(query)).data;
936
- },
950
+ async () => (await client.db(source).files.list(query)).data,
937
951
  [],
938
952
  snapshot.isReady,
939
953
  snapshot.isReady,
940
- [sourceKey, queryKey, version, snapshot.activeProfile?.id]
954
+ [sourceKey, queryKey, version, snapshot.activeAccount?.id]
941
955
  );
942
956
  }
943
957
  function useFiles(query = {}, options = {}) {
@@ -945,61 +959,62 @@ function useFiles(query = {}, options = {}) {
945
959
  }
946
960
  function useStorageInfoFor(client) {
947
961
  const snapshot = useClientSnapshot(client);
948
- return useAsyncResult(
962
+ const gate = useSignInGate(snapshot);
963
+ const result = useAsyncResult(
949
964
  () => client.storageInfo(client.resolveRepoId()),
950
965
  null,
951
966
  snapshot.isReady && snapshot.isSignedIn,
952
967
  snapshot.isReady,
953
- [snapshot.activeProfile?.id]
968
+ [snapshot.activeAccount?.id]
954
969
  );
970
+ return { ...result, error: result.error ?? gate };
955
971
  }
956
972
  function useStorageInfo() {
957
973
  return useStorageInfoFor(useRequiredClient());
958
974
  }
959
975
 
960
976
  // src/hooks/mounts.ts
961
- var import_react9 = require("react");
977
+ var import_react10 = require("react");
962
978
  function useMountsFor(client, query = {}) {
963
979
  const snapshot = useClientSnapshot(client);
980
+ const gate = useSignInGate(snapshot);
964
981
  const queryKey = JSON.stringify(query);
965
982
  const result = useAsyncResult(
966
983
  () => client.shares.mounts(query),
967
984
  [],
968
985
  snapshot.isReady && snapshot.isSignedIn,
969
986
  snapshot.isReady,
970
- [queryKey, snapshot.activeProfile?.id]
987
+ [queryKey, snapshot.activeAccount?.id]
971
988
  );
972
- const open = (0, import_react9.useCallback)(
989
+ const open = (0, import_react10.useCallback)(
973
990
  (mountId) => client.shares.mount(mountId),
974
991
  [client]
975
992
  );
976
- const manageUrl = (0, import_react9.useCallback)(() => client.shares.manageUrl(), [client]);
977
- const { data: mounts, ...state } = result;
978
- return { data: mounts, mounts, ...state, open, manageUrl };
993
+ const manageUrl = (0, import_react10.useCallback)(() => client.shares.manageUrl(), [client]);
994
+ return { ...result, error: result.error ?? gate, open, manageUrl };
979
995
  }
980
996
  function useMounts(query = {}) {
981
997
  return useMountsFor(useRequiredClient(), query);
982
998
  }
983
999
  function useOutgoingSharesFor(client) {
984
1000
  const snapshot = useClientSnapshot(client);
1001
+ const gate = useSignInGate(snapshot);
985
1002
  const result = useAsyncResult(
986
1003
  () => client.shares.listOutgoing(),
987
1004
  [],
988
1005
  snapshot.isReady && snapshot.isSignedIn,
989
1006
  snapshot.isReady,
990
- [snapshot.activeProfile?.id]
1007
+ [snapshot.activeAccount?.id]
991
1008
  );
992
- const create = (0, import_react9.useCallback)((input) => client.shares.createOutgoing(input), [client]);
993
- const get = (0, import_react9.useCallback)((id) => client.shares.getOutgoing(id), [client]);
994
- const cancel = (0, import_react9.useCallback)((id) => client.shares.cancel(id), [client]);
995
- const revoke = (0, import_react9.useCallback)((id) => client.shares.revoke(id), [client]);
996
- const getContactHandle = (0, import_react9.useCallback)((did) => client.shares.getContactHandle(did), [client]);
997
- const manageUrl = (0, import_react9.useCallback)(() => client.shares.manageUrl(), [client]);
998
- const { data: outgoingShares, ...state } = result;
1009
+ const create = (0, import_react10.useCallback)((input) => client.shares.createOutgoing(input), [client]);
1010
+ const get = (0, import_react10.useCallback)((id) => client.shares.getOutgoing(id), [client]);
1011
+ const cancel = (0, import_react10.useCallback)((id) => client.shares.cancel(id), [client]);
1012
+ const revoke = (0, import_react10.useCallback)((id) => client.shares.revoke(id), [client]);
1013
+ const getContactHandle = (0, import_react10.useCallback)((did) => client.shares.getContactHandle(did), [client]);
1014
+ const manageUrl = (0, import_react10.useCallback)(() => client.shares.manageUrl(), [client]);
999
1015
  return {
1000
- data: outgoingShares,
1001
- outgoingShares,
1002
- ...state,
1016
+ ...result,
1017
+ error: result.error ?? gate,
1003
1018
  create,
1004
1019
  get,
1005
1020
  cancel,
@@ -1013,58 +1028,35 @@ function useOutgoingShares() {
1013
1028
  }
1014
1029
 
1015
1030
  // src/hooks/query.ts
1016
- var import_react10 = require("react");
1017
- var subscribeNever = () => () => {
1018
- };
1019
- var zero2 = () => 0;
1031
+ var import_react11 = require("react");
1020
1032
  function useQueryValueFor(client, collection, query = {}, options = {}) {
1021
1033
  const source = options.source ?? "default";
1022
1034
  const sourceKey = JSON.stringify(source);
1023
1035
  const queryKey = JSON.stringify(query);
1024
1036
  const snapshot = useClientSnapshot(client);
1025
- const subscription = (0, import_react10.useMemo)(
1026
- () => client.queryStore.collection(source, collection),
1027
- // sourceKey captures semantic source identity rather than object identity.
1028
- // eslint-disable-next-line react-hooks/exhaustive-deps
1029
- [client, sourceKey, collection]
1030
- );
1031
- const version = (0, import_react10.useSyncExternalStore)(
1032
- subscription?.subscribe ?? subscribeNever,
1033
- subscription?.getSnapshot ?? zero2,
1034
- zero2
1035
- );
1036
- const [result, setResult] = (0, import_react10.useState)({
1037
+ const [result, setResult] = (0, import_react11.useState)({
1037
1038
  data: [],
1038
1039
  isLoading: true,
1039
1040
  error: null
1040
1041
  });
1041
- (0, import_react10.useEffect)(() => {
1042
- let active = true;
1043
- if (!snapshot.isReady) {
1044
- setResult((current) => ({ ...current, isLoading: true, error: null }));
1045
- return () => {
1046
- active = false;
1047
- };
1048
- }
1042
+ (0, import_react11.useEffect)(() => {
1049
1043
  setResult((current) => ({ ...current, isLoading: true, error: null }));
1050
- const collectionApi = client.db(source).collection(collection);
1051
- const list = collectionApi.list;
1052
- void list.call(collectionApi, query).then(
1053
- (page) => {
1054
- if (active) setResult({ data: page.data, isLoading: false, error: null });
1055
- },
1056
- (error) => {
1057
- if (active) setResult((current) => ({
1044
+ if (!snapshot.isReady) return;
1045
+ try {
1046
+ return client.db(source).collection(collection).watch(
1047
+ query,
1048
+ (page) => setResult({ data: page.data, isLoading: false, error: null }),
1049
+ (error) => setResult((current) => ({
1058
1050
  ...current,
1059
1051
  isLoading: false,
1060
1052
  error: toBasicError(error, "QUERY_FAILED")
1061
- }));
1062
- }
1063
- );
1064
- return () => {
1065
- active = false;
1066
- };
1067
- }, [client, collection, sourceKey, queryKey, version, snapshot.isReady]);
1053
+ }))
1054
+ );
1055
+ } catch (error) {
1056
+ setResult((current) => ({ ...current, isLoading: false, error: toBasicError(error, "QUERY_FAILED") }));
1057
+ return;
1058
+ }
1059
+ }, [client, collection, sourceKey, queryKey, snapshot.isReady]);
1068
1060
  return result;
1069
1061
  }
1070
1062
  function useQueryFor(client, collection, query = {}, options = {}) {
@@ -1074,6 +1066,45 @@ function useQuery(collection, query = {}, options = {}) {
1074
1066
  return useQueryValueFor(useRequiredClient(), collection, query, options);
1075
1067
  }
1076
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
+
1077
1108
  // src/create-basic.tsx
1078
1109
  var import_jsx_runtime2 = require("react/jsx-runtime");
1079
1110
  function createBasic(config) {
@@ -1081,33 +1112,1058 @@ function createBasic(config) {
1081
1112
  function Provider({ children, renderWhileLoading }) {
1082
1113
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BasicProvider, { client, renderWhileLoading, children });
1083
1114
  }
1115
+ function useBound() {
1116
+ if ((0, import_react12.useContext)(BasicClientContext) !== client) {
1117
+ throw new Error("Bound Basic hooks must be used within their own <basic.Provider>");
1118
+ }
1119
+ return client;
1120
+ }
1084
1121
  function useBoundDb(source = "default") {
1085
- return client.db(source);
1122
+ return useBound().db(source);
1086
1123
  }
1087
1124
  return {
1088
1125
  client,
1089
1126
  Provider,
1090
- useBasic: () => useBasicFor(client),
1091
- useAuth: () => useAuthFor(client),
1092
- useAccounts: () => useAccountsFor(client),
1127
+ useBasic: () => useBasicFor(useBound()),
1128
+ useAuth: () => useAuthFor(useBound()),
1129
+ useAccounts: () => useAccountsFor(useBound()),
1093
1130
  useDb: useBoundDb,
1094
- useCollection: (name, options = {}) => useCollectionFor(client, name, options),
1095
- useQuery: (collection, query = {}, options = {}) => useQueryFor(client, collection, query, options),
1096
- useSyncStatus: (source) => useSyncStatusFor(client, source),
1097
- useSchemaStatus: (source = "default") => useSchemaStatusFor(client, source),
1098
- useRepos: () => useReposFor(client),
1099
- useFiles: (query = {}, options = {}) => useFilesFor(client, query, options),
1100
- useStorageInfo: () => useStorageInfoFor(client),
1101
- useMounts: (query = {}) => useMountsFor(client, query),
1102
- useOutgoingShares: () => useOutgoingSharesFor(client)
1131
+ useCollection: (name, options = {}) => useCollectionFor(useBound(), name, options),
1132
+ useQuery: (collection, query = {}, options = {}) => useQueryFor(useBound(), collection, query, options),
1133
+ useSyncStatus: (source) => useSyncStatusFor(useBound(), source),
1134
+ useSchemaStatus: (source = "default") => useSchemaStatusFor(useBound(), source),
1135
+ useRepos: () => useReposFor(useBound()),
1136
+ useProjectProfile: (enabled) => useProjectProfileFor(useBound(), enabled),
1137
+ useFiles: (query = {}, options = {}) => useFilesFor(useBound(), query, options),
1138
+ useStorageInfo: () => useStorageInfoFor(useBound()),
1139
+ useMounts: (query = {}) => useMountsFor(useBound(), query),
1140
+ useOutgoingShares: () => useOutgoingSharesFor(useBound())
1103
1141
  };
1104
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 appearanceStyle(appearance) {
1154
+ return {
1155
+ ...appearance.accent ? { "--basic-accent": appearance.accent } : {},
1156
+ ...appearance.radius ? { "--basic-radius": appearance.radius } : {}
1157
+ };
1158
+ }
1159
+ function BasicUIProvider({
1160
+ appearance = {},
1161
+ children
1162
+ }) {
1163
+ const parent = (0, import_react13.useContext)(AppearanceContext);
1164
+ const value = { ...parent, ...appearance };
1165
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AppearanceContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1166
+ "div",
1167
+ {
1168
+ className: "basic-ui",
1169
+ "data-theme": value.theme ?? "light",
1170
+ "data-density": value.density ?? "comfortable",
1171
+ style: appearanceStyle(value),
1172
+ children
1173
+ }
1174
+ ) });
1175
+ }
1176
+ function useAppearanceProps() {
1177
+ const appearance = (0, import_react13.useContext)(AppearanceContext);
1178
+ return {
1179
+ "data-theme": appearance.theme ?? "light",
1180
+ "data-density": appearance.density ?? "comfortable",
1181
+ style: appearanceStyle(appearance)
1182
+ };
1183
+ }
1184
+ var BasicButton = (0, import_react13.forwardRef)(
1185
+ function BasicButton2({ variant = "outline", className = "", type = "button", ...props }, ref) {
1186
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1187
+ "button",
1188
+ {
1189
+ ...props,
1190
+ ref,
1191
+ type,
1192
+ className: `basic-button ${className}`,
1193
+ "data-variant": variant
1194
+ }
1195
+ );
1196
+ }
1197
+ );
1198
+ function useAction() {
1199
+ const [pending, setPending] = (0, import_react13.useState)(false);
1200
+ const [error, setError] = (0, import_react13.useState)(null);
1201
+ const busy = (0, import_react13.useRef)(false);
1202
+ const mounted = (0, import_react13.useRef)(true);
1203
+ (0, import_react13.useEffect)(() => {
1204
+ mounted.current = true;
1205
+ return () => {
1206
+ mounted.current = false;
1207
+ };
1208
+ }, []);
1209
+ async function run(action) {
1210
+ if (busy.current) return;
1211
+ busy.current = true;
1212
+ setPending(true);
1213
+ setError(null);
1214
+ try {
1215
+ await action();
1216
+ } catch (cause) {
1217
+ if (mounted.current)
1218
+ setError(
1219
+ 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."
1220
+ );
1221
+ } finally {
1222
+ busy.current = false;
1223
+ if (mounted.current) setPending(false);
1224
+ }
1225
+ }
1226
+ return { pending, error, run, clearError: () => setError(null) };
1227
+ }
1228
+ function AuthButton({
1229
+ auth: supplied,
1230
+ input,
1231
+ signOut = false,
1232
+ children,
1233
+ disabled,
1234
+ onClick,
1235
+ ...props
1236
+ }) {
1237
+ const live = useAuth();
1238
+ const auth = supplied ?? live;
1239
+ const action = useAction();
1240
+ const expired = auth.status === "expired";
1241
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-action", children: [
1242
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1243
+ BasicButton,
1244
+ {
1245
+ ...props,
1246
+ disabled: disabled || !auth.isReady || action.pending || (signOut ? !auth.isSignedIn && !expired : auth.isSignedIn && !expired),
1247
+ "aria-busy": action.pending,
1248
+ onClick: (event) => {
1249
+ onClick?.(event);
1250
+ if (!event.defaultPrevented)
1251
+ void action.run(
1252
+ () => signOut ? auth.signOut() : auth.signIn(input)
1253
+ );
1254
+ },
1255
+ children: action.pending ? "Please wait\u2026" : children ?? (signOut ? "Sign out" : expired ? "Sign in again" : "Sign in")
1256
+ }
1257
+ ),
1258
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ActionError, { error: action.error, onClose: action.clearError })
1259
+ ] });
1260
+ }
1261
+ function SignInButton(props) {
1262
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AuthButton, { ...props });
1263
+ }
1264
+ function SignOutButton(props) {
1265
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AuthButton, { ...props, signOut: true });
1266
+ }
1267
+ function UserAvatar({
1268
+ accounts,
1269
+ auth,
1270
+ projectProfile,
1271
+ allowAddAccount,
1272
+ ...avatarProps
1273
+ }) {
1274
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1275
+ UserMenu,
1276
+ {
1277
+ accounts,
1278
+ auth,
1279
+ projectProfile,
1280
+ allowAddAccount,
1281
+ sync: avatarProps.sync,
1282
+ showSyncBadge: avatarProps.showSyncBadge,
1283
+ avatarProps
1284
+ }
1285
+ );
1286
+ }
1287
+ function AccountAvatar({
1288
+ profile: supplied,
1289
+ size = 32,
1290
+ showSyncBadge,
1291
+ sync,
1292
+ className = "",
1293
+ style,
1294
+ ...props
1295
+ }) {
1296
+ const accounts = useAccounts();
1297
+ const client = useRequiredClient();
1298
+ const profile = supplied === void 0 ? accounts.activeAccount : supplied;
1299
+ const name = profile?.name || (profile?.kind === "anon" ? "Local account" : profile?.handle || profile?.email || "Guest");
1300
+ const initials = name.trim().split(/\s+/).slice(0, 2).map((part) => Array.from(part)[0]).join("").toUpperCase();
1301
+ const avatar = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1302
+ import_avatar.Avatar.Root,
1303
+ {
1304
+ ...props,
1305
+ className: `basic-avatar ${className}`,
1306
+ style: { width: size, height: size, ...style },
1307
+ role: "img",
1308
+ "aria-label": props["aria-label"] ?? name,
1309
+ children: [
1310
+ profile?.picture && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1311
+ import_avatar.Avatar.Image,
1312
+ {
1313
+ src: profile.picture,
1314
+ alt: "",
1315
+ className: "basic-avatar-image",
1316
+ referrerPolicy: "no-referrer"
1317
+ }
1318
+ ),
1319
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_avatar.Avatar.Fallback, { className: "basic-avatar-fallback", children: initials || "?" })
1320
+ ]
1321
+ }
1322
+ );
1323
+ return showSyncBadge ?? client.mode === "sync" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-avatar-container", children: [
1324
+ avatar,
1325
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SyncStatus, { sync, className: "basic-avatar-sync" })
1326
+ ] }) : avatar;
1327
+ }
1328
+ function AuthStatus({
1329
+ auth: supplied,
1330
+ className = "",
1331
+ ...props
1332
+ }) {
1333
+ const live = useAuth();
1334
+ const auth = supplied ?? live;
1335
+ const expired = auth.status === "expired";
1336
+ 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";
1337
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1338
+ "span",
1339
+ {
1340
+ ...props,
1341
+ role: "status",
1342
+ className: `basic-status ${className}`,
1343
+ "data-tone": expired || auth.error ? "warning" : auth.isSignedIn ? "success" : "neutral",
1344
+ children: [
1345
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "basic-dot" }),
1346
+ label
1347
+ ]
1348
+ }
1349
+ );
1350
+ }
1351
+ function SyncStatus({
1352
+ sync: supplied,
1353
+ source,
1354
+ className = "",
1355
+ ...props
1356
+ }) {
1357
+ const live = useSyncStatus(source);
1358
+ const client = useRequiredClient();
1359
+ const sync = supplied ?? live;
1360
+ if (client.mode === "rest") return null;
1361
+ const issues = sync.rejected.length + sync.conflicts.length;
1362
+ const labels = {
1363
+ idle: "Idle",
1364
+ bootstrapping: "Starting sync",
1365
+ connecting: "Connecting",
1366
+ online: "Synced",
1367
+ offline: "Offline",
1368
+ stopped: "Sync stopped",
1369
+ error: "Sync error",
1370
+ local: "Local only",
1371
+ stale: "Sync stale",
1372
+ ended: "Access ended"
1373
+ };
1374
+ const label = issues ? `${issues} sync ${issues === 1 ? "issue" : "issues"}` : sync.status === "online" && sync.pendingCount ? "Syncing" : labels[sync.status];
1375
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1376
+ "span",
1377
+ {
1378
+ ...props,
1379
+ role: "status",
1380
+ title: props.title ?? `${label}${sync.pendingCount > 0 ? ` \xB7 ${sync.pendingCount} pending` : ""}`,
1381
+ className: `basic-status ${className}`,
1382
+ "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",
1383
+ children: [
1384
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "basic-dot" }),
1385
+ label,
1386
+ sync.pendingCount > 0 && ` \xB7 ${sync.pendingCount} pending`
1387
+ ]
1388
+ }
1389
+ );
1390
+ }
1391
+ function displayHandle(handle) {
1392
+ return handle ? `@${handle.replace(/^@+/, "")}` : "";
1393
+ }
1394
+ function UserButton(props) {
1395
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UserMenu, { ...props, trigger: "button" });
1396
+ }
1397
+ function UserMenu({
1398
+ accounts: supplied,
1399
+ auth: suppliedAuth,
1400
+ sync,
1401
+ showSyncStatus = true,
1402
+ showSyncBadge,
1403
+ shape = "rounded",
1404
+ trigger = "avatar",
1405
+ avatarProps,
1406
+ projectProfile,
1407
+ allowAddAccount = true,
1408
+ className = "",
1409
+ accountSettingsUrl
1410
+ }) {
1411
+ const liveAccounts = useAccounts();
1412
+ const liveAuth = useAuth();
1413
+ const accounts = supplied ?? liveAccounts;
1414
+ const auth = suppliedAuth ?? liveAuth;
1415
+ const action = useAction();
1416
+ const [settingsOpen, setSettingsOpen] = (0, import_react13.useState)(false);
1417
+ const [clearAccountId, setClearAccountId] = (0, import_react13.useState)(null);
1418
+ const triggerRef = (0, import_react13.useRef)(null);
1419
+ const appearance = useAppearanceProps();
1420
+ const expired = auth.status === "expired";
1421
+ const active = accounts.activeAccount;
1422
+ const otherAccounts = accounts.accounts.filter(
1423
+ (account) => account.id !== active?.id
1424
+ );
1425
+ const name = active?.name || active?.kind !== "anon" && displayHandle(active?.handle) || "Local account";
1426
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: `basic-action ${className}`, children: [
1427
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_menu.Menu.Root, { children: [
1428
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1429
+ import_menu.Menu.Trigger,
1430
+ {
1431
+ ref: triggerRef,
1432
+ className: `basic-button basic-account-trigger basic-trigger-${trigger}`,
1433
+ "data-shape": shape,
1434
+ disabled: !auth.isReady || action.pending,
1435
+ "aria-label": "Open user menu",
1436
+ children: [
1437
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1438
+ AccountAvatar,
1439
+ {
1440
+ profile: accounts.activeAccount,
1441
+ sync,
1442
+ showSyncBadge,
1443
+ ...avatarProps
1444
+ }
1445
+ ),
1446
+ trigger === "button" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1447
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-identity", children: [
1448
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: name }),
1449
+ active?.kind !== "anon" && active?.handle && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { children: displayHandle(active.handle) })
1450
+ ] }),
1451
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1452
+ "svg",
1453
+ {
1454
+ className: "basic-chevron",
1455
+ width: "16",
1456
+ height: "16",
1457
+ viewBox: "0 0 24 24",
1458
+ fill: "none",
1459
+ stroke: "currentColor",
1460
+ strokeWidth: "2",
1461
+ strokeLinecap: "round",
1462
+ strokeLinejoin: "round",
1463
+ "aria-hidden": "true",
1464
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m6 9 6 6 6-6" })
1465
+ }
1466
+ )
1467
+ ] })
1468
+ ]
1469
+ }
1470
+ ),
1471
+ /* @__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: [
1472
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-menu-profile", children: [
1473
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1474
+ AccountAvatar,
1475
+ {
1476
+ profile: active,
1477
+ size: 48,
1478
+ sync,
1479
+ showSyncBadge: false
1480
+ }
1481
+ ),
1482
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-identity", children: [
1483
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: active ? name : "No active account" }),
1484
+ active?.kind !== "anon" && active?.handle && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { children: displayHandle(active.handle) }),
1485
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-account-statuses", children: [
1486
+ expired && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "basic-status", "data-tone": "warning", children: "Expired" }),
1487
+ showSyncStatus && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SyncStatus, { sync })
1488
+ ] })
1489
+ ] })
1490
+ ] }),
1491
+ expired && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1492
+ import_menu.Menu.Item,
1493
+ {
1494
+ className: "basic-menu-item basic-menu-reauth",
1495
+ disabled: action.pending,
1496
+ onClick: () => void action.run(() => auth.signIn()),
1497
+ children: "Sign in again"
1498
+ }
1499
+ ),
1500
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1501
+ import_menu.Menu.Item,
1502
+ {
1503
+ className: "basic-menu-item basic-manage-account",
1504
+ onClick: () => setSettingsOpen(true),
1505
+ children: [
1506
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1507
+ "svg",
1508
+ {
1509
+ className: "basic-menu-icon",
1510
+ width: "16",
1511
+ height: "16",
1512
+ viewBox: "0 0 24 24",
1513
+ fill: "none",
1514
+ stroke: "currentColor",
1515
+ strokeWidth: "1.75",
1516
+ strokeLinecap: "round",
1517
+ strokeLinejoin: "round",
1518
+ "aria-hidden": "true",
1519
+ children: [
1520
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "12", cy: "7", r: "4" }),
1521
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" })
1522
+ ]
1523
+ }
1524
+ ),
1525
+ "Manage account"
1526
+ ]
1527
+ }
1528
+ ),
1529
+ (auth.isSignedIn || expired || active?.kind === "anon") && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1530
+ import_menu.Menu.Item,
1531
+ {
1532
+ className: "basic-menu-item basic-menu-signout",
1533
+ disabled: action.pending,
1534
+ onClick: () => active?.kind === "anon" ? setClearAccountId(active.id) : void action.run(() => auth.signOut()),
1535
+ children: [
1536
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1537
+ "svg",
1538
+ {
1539
+ className: "basic-menu-icon",
1540
+ width: "16",
1541
+ height: "16",
1542
+ viewBox: "0 0 24 24",
1543
+ fill: "none",
1544
+ stroke: "currentColor",
1545
+ strokeWidth: "1.75",
1546
+ strokeLinecap: "round",
1547
+ strokeLinejoin: "round",
1548
+ "aria-hidden": "true",
1549
+ 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" })
1550
+ }
1551
+ ),
1552
+ active?.kind === "anon" ? "Clear account" : "Sign out"
1553
+ ]
1554
+ }
1555
+ ),
1556
+ otherAccounts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1557
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_menu.Menu.Separator, { className: "basic-separator" }),
1558
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "basic-menu-heading", children: "Switch accounts" })
1559
+ ] }),
1560
+ otherAccounts.map((account) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1561
+ import_menu.Menu.Item,
1562
+ {
1563
+ className: "basic-menu-item",
1564
+ disabled: action.pending,
1565
+ onClick: () => void action.run(() => accounts.switchAccount(account.id)),
1566
+ children: [
1567
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1568
+ AccountAvatar,
1569
+ {
1570
+ profile: account,
1571
+ size: 32,
1572
+ sync,
1573
+ showSyncBadge: false
1574
+ }
1575
+ ),
1576
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-identity", children: [
1577
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: account.name || account.kind !== "anon" && displayHandle(account.handle) || (account.kind === "anon" ? "Local account" : "Account") }),
1578
+ account.kind !== "anon" && account.handle && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { children: displayHandle(account.handle) })
1579
+ ] }),
1580
+ /* @__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 })
1581
+ ]
1582
+ },
1583
+ account.id
1584
+ )),
1585
+ (allowAddAccount || !auth.isSignedIn && !expired) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1586
+ import_menu.Menu.Item,
1587
+ {
1588
+ className: "basic-menu-item",
1589
+ disabled: action.pending,
1590
+ onClick: () => void action.run(
1591
+ () => allowAddAccount ? accounts.addAccount({ signIn: true }) : auth.signIn()
1592
+ ),
1593
+ children: "\uFF0B Add account"
1594
+ }
1595
+ )
1596
+ ] }) }) })
1597
+ ] }),
1598
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1599
+ ActionError,
1600
+ {
1601
+ error: action.error,
1602
+ onClose: action.clearError,
1603
+ finalFocus: triggerRef
1604
+ }
1605
+ ),
1606
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1607
+ Modal,
1608
+ {
1609
+ open: clearAccountId !== null,
1610
+ onOpenChange: (open) => {
1611
+ if (!open) setClearAccountId(null);
1612
+ },
1613
+ trigger: null,
1614
+ finalFocus: triggerRef,
1615
+ title: "Clear local account?",
1616
+ description: "This deletes this account\u2019s local data, including unsynced changes. This cannot be undone.",
1617
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-actions", children: [
1618
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1619
+ BasicButton,
1620
+ {
1621
+ disabled: action.pending,
1622
+ onClick: () => setClearAccountId(null),
1623
+ children: "Cancel"
1624
+ }
1625
+ ),
1626
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1627
+ BasicButton,
1628
+ {
1629
+ disabled: action.pending,
1630
+ onClick: () => {
1631
+ const id = clearAccountId;
1632
+ if (!id) return;
1633
+ setClearAccountId(null);
1634
+ void action.run(() => accounts.removeAccount(id));
1635
+ },
1636
+ children: "Clear account"
1637
+ }
1638
+ )
1639
+ ] })
1640
+ }
1641
+ ),
1642
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1643
+ AccountSettingsModal,
1644
+ {
1645
+ auth,
1646
+ accounts,
1647
+ open: settingsOpen,
1648
+ onOpenChange: setSettingsOpen,
1649
+ trigger: null,
1650
+ finalFocus: triggerRef,
1651
+ accountSettingsUrl,
1652
+ projectProfile,
1653
+ sync
1654
+ }
1655
+ )
1656
+ ] });
1657
+ }
1658
+ function ActionError({
1659
+ error,
1660
+ onClose,
1661
+ finalFocus
1662
+ }) {
1663
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1664
+ Modal,
1665
+ {
1666
+ open: !!error,
1667
+ onOpenChange: (open) => {
1668
+ if (!open) onClose();
1669
+ },
1670
+ trigger: null,
1671
+ finalFocus,
1672
+ title: "Unable to complete action",
1673
+ description: "Your request could not be completed.",
1674
+ children: [
1675
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "basic-error", children: error }),
1676
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BasicButton, { onClick: onClose, children: "Dismiss" })
1677
+ ]
1678
+ }
1679
+ );
1680
+ }
1681
+ function Modal({
1682
+ open,
1683
+ onOpenChange,
1684
+ trigger,
1685
+ finalFocus,
1686
+ title,
1687
+ description,
1688
+ header,
1689
+ sectionLabel,
1690
+ children
1691
+ }) {
1692
+ const appearance = useAppearanceProps();
1693
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_dialog.Dialog.Root, { open, onOpenChange, children: [
1694
+ 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 })),
1695
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_dialog.Dialog.Portal, { children: [
1696
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dialog.Dialog.Backdrop, { className: "basic-backdrop" }),
1697
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1698
+ import_dialog.Dialog.Popup,
1699
+ {
1700
+ ...appearance,
1701
+ finalFocus,
1702
+ className: "basic-ui basic-dialog",
1703
+ children: [
1704
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1705
+ "div",
1706
+ {
1707
+ className: `basic-dialog-heading${header ? " basic-dialog-heading-overlay" : ""}`,
1708
+ children: [
1709
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dialog.Dialog.Title, { className: header ? "basic-sr-only" : "basic-title", children: title }),
1710
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1711
+ import_dialog.Dialog.Close,
1712
+ {
1713
+ className: "basic-button",
1714
+ "aria-label": `Close ${title.toLowerCase()}`,
1715
+ children: "\u2715"
1716
+ }
1717
+ )
1718
+ ]
1719
+ }
1720
+ ),
1721
+ header,
1722
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1723
+ import_dialog.Dialog.Description,
1724
+ {
1725
+ className: header ? "basic-sr-only" : "basic-muted",
1726
+ children: description
1727
+ }
1728
+ ),
1729
+ sectionLabel && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "basic-modal-section", children: sectionLabel }),
1730
+ children
1731
+ ]
1732
+ }
1733
+ )
1734
+ ] })
1735
+ ] });
1736
+ }
1737
+ function AccountSettingsModal({
1738
+ auth: suppliedAuth,
1739
+ accounts: suppliedAccounts,
1740
+ accountSettingsUrl,
1741
+ projectProfile,
1742
+ sync,
1743
+ children,
1744
+ ...props
1745
+ }) {
1746
+ const liveAuth = useAuth();
1747
+ const liveAccounts = useAccounts();
1748
+ const auth = suppliedAuth ?? liveAuth;
1749
+ const accounts = suppliedAccounts ?? liveAccounts;
1750
+ const liveSync = useSyncStatus();
1751
+ const syncState = sync ?? liveSync;
1752
+ const client = useRequiredClient();
1753
+ const account = accounts.activeAccount;
1754
+ const copyAction = useAction();
1755
+ const [copied, setCopied] = (0, import_react13.useState)(null);
1756
+ const details = [
1757
+ [
1758
+ "Account DID",
1759
+ account?.kind === "anon" ? "Not assigned (local account)" : account?.did ?? auth.did ?? "Unavailable"
1760
+ ],
1761
+ [
1762
+ "PDS URL",
1763
+ account?.kind === "anon" ? "Not connected (local account)" : auth.user?.pds_url ?? "Unavailable"
1764
+ ],
1765
+ ["Local account ID", account?.id ?? "None"],
1766
+ ["Account kind", account?.kind ?? "None"],
1767
+ ["Storage prefix", account?.storagePrefix ?? "None"],
1768
+ ["Client mode", client.mode],
1769
+ ["Auth state", auth.status],
1770
+ ["Ready", auth.isReady ? "Yes" : "No"],
1771
+ ["Can write", auth.canWrite ? "Yes" : "No"],
1772
+ ["Read-only reason", auth.readOnlyReason ?? "None"],
1773
+ ["Auth error code", auth.error?.code ?? "None"],
1774
+ ["Sync state", syncState.status],
1775
+ ["Pending writes", String(syncState.pendingCount)],
1776
+ ["Rejected writes", String(syncState.rejected.length)],
1777
+ ["Conflicts", String(syncState.conflicts.length)]
1778
+ ];
1779
+ const diagnostics = JSON.stringify(Object.fromEntries(details), null, 2);
1780
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1781
+ Modal,
1782
+ {
1783
+ ...props,
1784
+ title: "Account settings",
1785
+ description: "Your identity and session on this device.",
1786
+ header: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AccountHeader, { account: accounts.activeAccount, sync }),
1787
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_tabs.Tabs.Root, { defaultValue: "profile", children: [
1788
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1789
+ import_tabs.Tabs.List,
1790
+ {
1791
+ className: "basic-tabs",
1792
+ "aria-label": "Account settings sections",
1793
+ children: [
1794
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tabs.Tabs.Tab, { value: "profile", children: "Profile" }),
1795
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tabs.Tabs.Tab, { value: "advanced", children: "Advanced" })
1796
+ ]
1797
+ }
1798
+ ),
1799
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_tabs.Tabs.Panel, { value: "profile", keepMounted: true, children: [
1800
+ auth.isSignedIn && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1801
+ ProjectProfileEditor,
1802
+ {
1803
+ profile: projectProfile,
1804
+ canWrite: auth.canWrite
1805
+ },
1806
+ accounts.activeAccount?.id ?? auth.did
1807
+ ),
1808
+ accountSettingsUrl && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { className: "basic-link", href: accountSettingsUrl, children: "Manage profile and security \u2197" }),
1809
+ children,
1810
+ !auth.isSignedIn && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "basic-actions", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SignInButton, { auth }) })
1811
+ ] }),
1812
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_tabs.Tabs.Panel, { value: "advanced", children: [
1813
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "basic-muted", children: "Read-only diagnostics for this account." }),
1814
+ /* @__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: [
1815
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dt", { children: label }),
1816
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("dd", { children: value })
1817
+ ] }, label)) }),
1818
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-actions", children: [
1819
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1820
+ BasicButton,
1821
+ {
1822
+ disabled: copyAction.pending,
1823
+ onClick: () => {
1824
+ setCopied(null);
1825
+ void copyAction.run(async () => {
1826
+ if (!navigator.clipboard?.writeText)
1827
+ throw new Error("Clipboard is unavailable in this browser.");
1828
+ await navigator.clipboard.writeText(diagnostics);
1829
+ setCopied(diagnostics);
1830
+ });
1831
+ },
1832
+ children: "Copy to clipboard"
1833
+ }
1834
+ ),
1835
+ copied === diagnostics && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { role: "status", className: "basic-muted", children: "Copied" })
1836
+ ] }),
1837
+ copyAction.error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "basic-error", children: copyAction.error })
1838
+ ] })
1839
+ ] })
1840
+ }
1841
+ );
1842
+ }
1843
+ function AccountHeader({
1844
+ account,
1845
+ sync
1846
+ }) {
1847
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-profile", children: [
1848
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1849
+ AccountAvatar,
1850
+ {
1851
+ profile: account,
1852
+ size: 72,
1853
+ sync,
1854
+ showSyncBadge: false
1855
+ }
1856
+ ),
1857
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "basic-identity", children: [
1858
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: account?.name || account?.kind !== "anon" && displayHandle(account?.handle) || "Local account" }),
1859
+ account?.kind !== "anon" && account?.handle && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { children: displayHandle(account.handle) }),
1860
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "basic-account-statuses", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SyncStatus, { sync }) })
1861
+ ] })
1862
+ ] });
1863
+ }
1864
+ function ProjectProfileEditor({
1865
+ profile: supplied,
1866
+ canWrite
1867
+ }) {
1868
+ const live = useProjectProfile(supplied === void 0);
1869
+ const profile = supplied ?? live;
1870
+ const action = useAction();
1871
+ const [draft, setDraft] = (0, import_react13.useState)({});
1872
+ const [saved, setSaved] = (0, import_react13.useState)(false);
1873
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1874
+ "form",
1875
+ {
1876
+ className: "basic-profile-editor",
1877
+ onSubmit: (event) => {
1878
+ event.preventDefault();
1879
+ if (!canWrite || !Object.keys(draft).length) return;
1880
+ void action.run(async () => {
1881
+ await profile.update(draft);
1882
+ setDraft({});
1883
+ setSaved(true);
1884
+ });
1885
+ },
1886
+ children: [
1887
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "basic-section-label", children: "Personal information" }),
1888
+ /* @__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." }),
1889
+ 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: [
1890
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "basic-error", children: profile.error.message }),
1891
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BasicButton, { onClick: profile.refresh, children: "Retry profile" })
1892
+ ] }) : profile.data && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("fieldset", { disabled: !canWrite || action.pending, children: [
1893
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "basic-field", children: [
1894
+ "Display name",
1895
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1896
+ "input",
1897
+ {
1898
+ className: "basic-input",
1899
+ type: "text",
1900
+ maxLength: 64,
1901
+ value: ("name" in draft ? draft.name : profile.data?.profile.name) ?? "",
1902
+ onChange: (event) => {
1903
+ setSaved(false);
1904
+ setDraft((current) => ({
1905
+ ...current,
1906
+ name: event.target.value || null
1907
+ }));
1908
+ }
1909
+ }
1910
+ )
1911
+ ] }),
1912
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-actions basic-modal-footer", children: [
1913
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1914
+ BasicButton,
1915
+ {
1916
+ variant: "ghost",
1917
+ onClick: () => {
1918
+ setDraft({});
1919
+ setSaved(false);
1920
+ },
1921
+ children: "Cancel"
1922
+ }
1923
+ ),
1924
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1925
+ BasicButton,
1926
+ {
1927
+ type: "submit",
1928
+ variant: "solid",
1929
+ disabled: !Object.keys(draft).length,
1930
+ children: "Save changes"
1931
+ }
1932
+ )
1933
+ ] })
1934
+ ] }),
1935
+ action.error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "basic-error", children: action.error }),
1936
+ saved && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "status", children: "Project profile saved." })
1937
+ ]
1938
+ }
1939
+ );
1940
+ }
1941
+ function SharesModal({
1942
+ auth: supplied,
1943
+ accounts: suppliedAccounts,
1944
+ sync,
1945
+ shares,
1946
+ scope,
1947
+ repo = "default",
1948
+ ...props
1949
+ }) {
1950
+ const live = useAuth();
1951
+ const liveAccounts = useAccounts();
1952
+ const auth = supplied ?? live;
1953
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1954
+ Modal,
1955
+ {
1956
+ ...props,
1957
+ title: "Shares",
1958
+ description: "Manage incoming invitations and share access to selected data.",
1959
+ header: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1960
+ AccountHeader,
1961
+ {
1962
+ account: (suppliedAccounts ?? liveAccounts).activeAccount,
1963
+ sync
1964
+ }
1965
+ ),
1966
+ 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: [
1967
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "basic-muted", children: "Sign in to share data." }),
1968
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SignInButton, { auth })
1969
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1970
+ SharesContent,
1971
+ {
1972
+ shares,
1973
+ scope,
1974
+ repo,
1975
+ canWrite: auth.canWrite
1976
+ },
1977
+ auth.did ?? "account"
1978
+ )
1979
+ }
1980
+ );
1981
+ }
1982
+ function SharesContent({
1983
+ shares: supplied,
1984
+ scope,
1985
+ repo,
1986
+ canWrite
1987
+ }) {
1988
+ const live = useOutgoingShares();
1989
+ const shares = supplied ?? live;
1990
+ const action = useAction();
1991
+ const [recipient, setRecipient] = (0, import_react13.useState)("");
1992
+ const [role, setRole] = (0, import_react13.useState)("viewer");
1993
+ const [confirmation, setConfirmation] = (0, import_react13.useState)(null);
1994
+ const [message, setMessage] = (0, import_react13.useState)("");
1995
+ const scopeValid = scope.length > 0 && scope.every(
1996
+ (item) => item.table.trim() && (item.recordIds === void 0 || item.recordIds.length > 0)
1997
+ );
1998
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_tabs.Tabs.Root, { defaultValue: "outgoing", className: "basic-shares", children: [
1999
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_tabs.Tabs.List, { className: "basic-tabs", "aria-label": "Share direction", children: [
2000
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tabs.Tabs.Tab, { value: "outgoing", children: "Outgoing" }),
2001
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tabs.Tabs.Tab, { value: "incoming", children: "Incoming invitations" })
2002
+ ] }),
2003
+ /* @__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: [
2004
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "basic-title", children: "Incoming invitations" }),
2005
+ /* @__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." }),
2006
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { className: "basic-link", href: shares.manageUrl(), children: "Open incoming invitations in Basic ID \u2197" })
2007
+ ] }) }),
2008
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_tabs.Tabs.Panel, { value: "outgoing", children: [
2009
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "basic-muted", children: "Revoking access stops future requests. It cannot retract data the recipient already downloaded." }),
2010
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-scope", children: [
2011
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "New invitation permissions" }),
2012
+ scope.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
2013
+ item.table,
2014
+ " \xB7",
2015
+ " ",
2016
+ item.recordIds ? `${item.recordIds.length} selected records` : "all records"
2017
+ ] }, index))
2018
+ ] }),
2019
+ !canWrite && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "basic-error", children: "This session is read only. Sharing changes are disabled." }),
2020
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2021
+ "form",
2022
+ {
2023
+ className: "basic-share-form",
2024
+ onSubmit: (event) => {
2025
+ event.preventDefault();
2026
+ if (!recipient.trim() || !scopeValid || !canWrite) return;
2027
+ void action.run(async () => {
2028
+ await shares.create({
2029
+ repo,
2030
+ scope,
2031
+ role,
2032
+ ...recipient.trim().startsWith("did:") ? { recipientDid: recipient.trim() } : { recipientHandle: recipient.trim().replace(/^@+/, "") }
2033
+ });
2034
+ setRecipient("");
2035
+ setMessage("Invitation sent.");
2036
+ shares.refresh();
2037
+ });
2038
+ },
2039
+ children: [
2040
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "basic-field", children: [
2041
+ "Recipient handle or DID",
2042
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2043
+ "input",
2044
+ {
2045
+ className: "basic-input",
2046
+ value: recipient,
2047
+ onChange: (event) => setRecipient(event.target.value),
2048
+ placeholder: "@alex.basic.id",
2049
+ required: true,
2050
+ disabled: action.pending || !canWrite
2051
+ }
2052
+ )
2053
+ ] }),
2054
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "basic-field", children: [
2055
+ "Permission",
2056
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2057
+ "select",
2058
+ {
2059
+ className: "basic-input",
2060
+ value: role,
2061
+ onChange: (event) => setRole(event.target.value),
2062
+ disabled: action.pending || !canWrite,
2063
+ children: [
2064
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "viewer", children: "Can view" }),
2065
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "editor", children: "Can edit" })
2066
+ ]
2067
+ }
2068
+ )
2069
+ ] }),
2070
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2071
+ BasicButton,
2072
+ {
2073
+ type: "submit",
2074
+ variant: "solid",
2075
+ disabled: action.pending || !canWrite || !scopeValid || !recipient.trim(),
2076
+ children: action.pending ? "Please wait\u2026" : "Send invitation"
2077
+ }
2078
+ )
2079
+ ]
2080
+ }
2081
+ ),
2082
+ !scopeValid && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "basic-error", children: "Select at least one table or record to share." }),
2083
+ action.error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", className: "basic-error", children: action.error }),
2084
+ message && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "status", className: "basic-muted", children: message }),
2085
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-section-heading", children: [
2086
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "basic-title", children: "Outgoing shares \xB7 all permissions" }),
2087
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2088
+ BasicButton,
2089
+ {
2090
+ disabled: action.pending || shares.isLoading,
2091
+ onClick: shares.refresh,
2092
+ children: "Refresh"
2093
+ }
2094
+ )
2095
+ ] }),
2096
+ 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: [
2097
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-identity", children: [
2098
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: share.display.shareName || share.recipientDid }),
2099
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("small", { children: [
2100
+ share.role === "viewer" ? "Can view" : "Can edit",
2101
+ " \xB7",
2102
+ " ",
2103
+ share.effectiveState,
2104
+ " \xB7",
2105
+ " ",
2106
+ share.scope.map((item) => item.table).join(", ")
2107
+ ] })
2108
+ ] }),
2109
+ share.state !== "ended" && (confirmation === share.id ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "basic-actions", children: [
2110
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Remove access?" }),
2111
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2112
+ BasicButton,
2113
+ {
2114
+ disabled: action.pending || !canWrite,
2115
+ onClick: () => void action.run(async () => {
2116
+ await (share.state === "pending" ? shares.cancel(share.id) : shares.revoke(share.id));
2117
+ setConfirmation(null);
2118
+ setMessage(
2119
+ share.state === "pending" ? "Invitation canceled." : "Access revoked."
2120
+ );
2121
+ shares.refresh();
2122
+ }),
2123
+ children: [
2124
+ "Confirm",
2125
+ " ",
2126
+ share.state === "pending" ? "cancel" : "revoke"
2127
+ ]
2128
+ }
2129
+ ),
2130
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2131
+ BasicButton,
2132
+ {
2133
+ disabled: action.pending,
2134
+ onClick: () => setConfirmation(null),
2135
+ children: "Keep access"
2136
+ }
2137
+ )
2138
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2139
+ BasicButton,
2140
+ {
2141
+ disabled: action.pending || !canWrite,
2142
+ onClick: () => setConfirmation(share.id),
2143
+ children: share.state === "pending" ? "Cancel invitation" : "Revoke access"
2144
+ }
2145
+ ))
2146
+ ] }, share.id)) })
2147
+ ] })
2148
+ ] });
2149
+ }
1105
2150
  // Annotate the CommonJS export names for ESM import in node:
1106
2151
  0 && (module.exports = {
2152
+ AccountSettingsModal,
2153
+ AuthStatus,
2154
+ BasicButton,
1107
2155
  BasicProvider,
2156
+ BasicUIProvider,
1108
2157
  BrowserKeyValueStorage,
1109
2158
  BrowserTokenStore,
1110
2159
  PersistenceStore,
2160
+ SharesModal,
2161
+ SignInButton,
2162
+ SignOutButton,
2163
+ SyncStatus,
2164
+ UserAvatar,
2165
+ UserButton,
2166
+ UserMenu,
1111
2167
  browserCurrentUrl,
1112
2168
  browserNavigate,
1113
2169
  browserReplaceUrl,
@@ -1125,6 +2181,7 @@ function createBasic(config) {
1125
2181
  useFiles,
1126
2182
  useMounts,
1127
2183
  useOutgoingShares,
2184
+ useProjectProfile,
1128
2185
  useQuery,
1129
2186
  useRepos,
1130
2187
  useSchemaStatus,