@streamoid/settings 0.3.7 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # @streamoid/settings
2
2
 
3
- Shared Settings module (Account, Workspace, Team, Billing, API Keys, Referral).
3
+ Shared Settings module (Account, Workspace, Organization, Billing, API Keys,
4
+ Referral).
4
5
  The host application provides auth, workspace, API, navigation, toast, and
5
6
  image-upload implementations through a single **adapter** object — the package
6
7
  contains no host-specific code.
@@ -58,7 +59,9 @@ function MySettingsPage() {
58
59
  revokeToken: (id) => fetch(`/tokens/${id}`, { method: "DELETE" }).then(() => undefined),
59
60
  },
60
61
  navigation: {
61
- navigateToTab: (tab) => router.push(`/settings/${TAB_TO_URL[tab]}`),
62
+ // `replace` matters once you wire up `onClose` below — otherwise a
63
+ // history-based close walks back through every tab the user visited.
64
+ navigateToTab: (tab) => router.replace(`/settings/${TAB_TO_URL[tab]}`),
62
65
  openExternal: (url) => window.open(url, "_blank", "noopener"),
63
66
  },
64
67
  toast: {
@@ -75,11 +78,66 @@ function MySettingsPage() {
75
78
  <SettingsContent
76
79
  activeTab={resolveSettingsTabFromPath(location.pathname)}
77
80
  adapters={adapters}
81
+ onClose={() => router.back()}
78
82
  />
79
83
  );
80
84
  }
81
85
  ```
82
86
 
87
+ ## Closing settings
88
+
89
+ Settings is a full page in every host, so the package cannot decide what
90
+ "closed" means — pass `onClose` (or `adapters.navigation.close`) and the shell
91
+ renders a × button in the header and dismisses on `Escape`. Pass neither and no
92
+ close affordance appears.
93
+
94
+ Escape defers to anything stacked on top of the panel. `overlay-registry.ts`
95
+ keeps an ordered stack of open modals — only the frontmost one acts on a press,
96
+ and the shell acts only once the stack is empty. The billing **Plans** sub-view
97
+ steps back to billing before the panel itself closes.
98
+
99
+ Modals added to this package should call `useOverlayOpen(open, onClose)` at the
100
+ top of the component. That is what registers them in the stack; skip it and
101
+ Escape will close the whole panel out from under the modal.
102
+
103
+ ## Navigation is scope-first (0.4.0)
104
+
105
+ Destinations are grouped by *whose* settings they are. `workspace/*` tabs act
106
+ on the workspace you are currently in; `organization/*` tabs act on the org
107
+ above it:
108
+
109
+ | Group | Tabs | URL |
110
+ |---|---|---|
111
+ | — | `profile` | `/account` |
112
+ | Workspace *(named)* | `workspace`, `workspaceMembers`, `workspaceList` | `/workspace/general`, `/workspace/members`, `/workspace/all` |
113
+ | Organization *(named)* | `organization`, `organizationWorkspaces`, `organizationDomains` | `/organization/people`, `/organization/workspaces`, `/organization/domains` |
114
+ | — | `billing`, `apikey` | `/billing`, `/api-keys` |
115
+
116
+ The group headings carry the entity's own name, so no leaf label repeats the
117
+ word "Workspace" or "Organization" — and "Team", which named a workspace's
118
+ member list without saying which workspace, is gone.
119
+
120
+ **Host routing.** Scoped slugs have two segments, so a host matching
121
+ `/settings/:tab` needs a second route for `/settings/:tab/:sub`.
122
+ `resolveSettingsTabFromPath` prefers the two-segment match and still resolves
123
+ the pre-0.4 slugs `team`, `workspace` and `organization`, so old links keep
124
+ working.
125
+
126
+ **Organizations are optional.** When `organization.current` is `null` the whole
127
+ group collapses to one `Organization` row leading to the create/join screen,
128
+ rather than a heading with no name and three empty pages under it.
129
+
130
+ **Breaking:** the `"team"` member of `SettingsTab` is now `"workspaceMembers"`,
131
+ and `WorkspaceTab` is renamed `WorkspaceListTab` (the old name stays as a
132
+ deprecated alias).
133
+
134
+ ## Explaining the tabs
135
+
136
+ Every sub-nav destination carries a hover/focus tooltip sourced from the
137
+ exported `TAB_DESCRIPTIONS` map. Override the copy in your host by rendering
138
+ your own nav, or edit the map here so all hosts stay consistent — the latter is
139
+ usually what you want.
140
+
83
141
  ## Adapter surface
84
142
 
85
143
  | Adapter | Purpose |
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { SVGProps, ReactNode } from 'react';
1
+ import * as react from 'react';
2
+ import react__default, { SVGProps, ReactNode } from 'react';
3
3
 
4
4
  /**
5
5
  * Settings tab identifiers and URL mapping helpers.
@@ -8,19 +8,67 @@ import { SVGProps, ReactNode } from 'react';
8
8
  * resolved tab into <SettingsContent activeTab={...} />. These helpers exist
9
9
  * so consumers don't have to re-implement tab/URL conversion if they don't
10
10
  * want to.
11
+ *
12
+ * ## Scope-first navigation
13
+ *
14
+ * Destinations are grouped by *whose* settings they are, not by feature. The
15
+ * data model is Organization → Workspaces → Members, and the nav now says so:
16
+ * `workspace/*` tabs act on one workspace, `organization/*` tabs act on the
17
+ * org above it. The old flat trio — Workspace / Team / Organization — read as
18
+ * three peers and left "Team" scoped to nothing the user could see.
19
+ *
20
+ * Pre-0.4 URLs (`/settings/team`, `/settings/workspace`, `/settings/organization`)
21
+ * still resolve, so existing links and bookmarks keep working.
11
22
  */
12
- type SettingsTab = "profile" | "workspace" | "referral" | "team" | "organization" | "billing" | "apikey";
13
- /** Internal tab id → URL slug. */
23
+ type SettingsTab = "profile"
24
+ /** Workspace › General — name, image, org affiliation, leave/delete. */
25
+ | "workspace"
26
+ /** Workspace › Members — was the top-level "Team" tab. */
27
+ | "workspaceMembers"
28
+ /** Workspace › All workspaces — the switch/create list. */
29
+ | "workspaceList"
30
+ /** Organization › People. */
31
+ | "organization"
32
+ /** Organization › Workspaces. */
33
+ | "organizationWorkspaces"
34
+ /** Organization › Domains & join requests. */
35
+ | "organizationDomains" | "referral" | "billing" | "apikey";
36
+ /** Which entity a tab acts on. Drives the nav grouping and the breadcrumb. */
37
+ type SettingsScope = "account" | "workspace" | "organization" | "global";
38
+ declare const TAB_SCOPE: Record<SettingsTab, SettingsScope>;
39
+ /** Fallback scope names, used before the entity's real name has loaded. */
40
+ declare const SCOPE_LABELS: Record<SettingsScope, string>;
41
+ /** Internal tab id → URL slug. Scoped tabs get a two-segment slug. */
14
42
  declare const TAB_TO_URL: Record<SettingsTab, string>;
15
- /** URL slug → internal tab id. */
43
+ /**
44
+ * URL slug → internal tab id. Two-segment slugs are matched first by
45
+ * `resolveSettingsTabFromPath`, so the bare `workspace` / `organization`
46
+ * entries below only catch pre-0.4 links.
47
+ */
16
48
  declare const URL_TO_TAB: Record<string, SettingsTab>;
17
- /** Human-readable label for each tab (used for breadcrumbs etc.). */
49
+ /**
50
+ * Human-readable label for each tab. These are *leaf* labels — the scope they
51
+ * belong to supplies the other half ("Acme Retail › Members"), so no label
52
+ * needs to repeat the word "Workspace" or "Organization".
53
+ */
18
54
  declare const TAB_LABELS: Record<SettingsTab, string>;
19
55
  /**
20
- * Resolve a `SettingsTab` from a URL pathname. Looks for the last segment that
21
- * matches a known slug; falls back to `"profile"` (the default Account tab).
56
+ * One-line explanation of what each destination is for, shown on hover over the
57
+ * settings sub-nav. Kept next to `TAB_LABELS` so a new tab can't get a label
58
+ * without also getting an explanation — `Record<SettingsTab, string>` makes
59
+ * omitting one a type error.
60
+ */
61
+ declare const TAB_DESCRIPTIONS: Record<SettingsTab, string>;
62
+ /**
63
+ * Resolve a `SettingsTab` from a URL pathname. Two-segment slugs
64
+ * (`workspace/members`) win over single ones, so `/settings/workspace/members`
65
+ * resolves to the member list rather than to the workspace's General tab.
66
+ * Falls back to `"profile"` (the default Account tab).
22
67
  *
23
- * Example: `/settings/billing` → `"billing"`.
68
+ * Examples:
69
+ * `/settings/billing` → `"billing"`
70
+ * `/settings/workspace/members`→ `"workspaceMembers"`
71
+ * `/settings/team` → `"workspaceMembers"` (legacy)
24
72
  */
25
73
  declare function resolveSettingsTabFromPath(path: string): SettingsTab;
26
74
 
@@ -702,6 +750,13 @@ interface SettingsNavigationAdapter {
702
750
  getCheckoutReturnUrl?: (kind: "success" | "cancel") => string;
703
751
  /** Imperative navigate to another settings tab. */
704
752
  navigateToTab: (tab: SettingsTab) => void;
753
+ /**
754
+ * Leave settings entirely. Supplying this makes the shell render a close (×)
755
+ * button and dismiss on Escape. Hosts that would rather pass a callback
756
+ * directly can use the `onClose` prop on `<SettingsContent>` instead — it
757
+ * takes precedence over this.
758
+ */
759
+ close?: () => void;
705
760
  /** External-link navigate (e.g. for "What's new" or referral promo links). */
706
761
  openExternal: (url: string) => void;
707
762
  }
@@ -729,29 +784,93 @@ type WorkspaceInfo = SettingsWorkspaceListItem & {
729
784
  plan?: string;
730
785
  ownerEmail?: string;
731
786
  };
732
- declare function ProfileTab(): react_jsx_runtime.JSX.Element;
733
- declare function WorkspaceTab({ workspaces, loading, onCreateClick: _onCreateClick, onEditClick, onSwitchClick, onLeaveClick, }: {
787
+ declare function ProfileTab(): react.JSX.Element;
788
+ /**
789
+ * Workspace › All workspaces — every workspace you belong to, for switching
790
+ * between them and starting new ones.
791
+ *
792
+ * This was the whole of the old "Workspace" tab, which is why that tab never
793
+ * looked like settings: it is a picker. It keeps the per-row Settings action
794
+ * (opening `WorkspaceModal`) because from here you may well be editing a
795
+ * workspace you are not currently inside — the current one has its own
796
+ * General page.
797
+ */
798
+ declare function WorkspaceListTab({ workspaces, loading, onCreateClick: _onCreateClick, onEditClick, onSwitchClick, onLeaveClick, }: {
734
799
  workspaces: WorkspaceInfo[];
735
800
  loading: boolean;
736
801
  onCreateClick: () => void;
737
802
  onEditClick: (ws: WorkspaceInfo) => void;
738
803
  onSwitchClick: (ws: WorkspaceInfo) => void;
739
804
  onLeaveClick: (ws: WorkspaceInfo) => void;
740
- }): react_jsx_runtime.JSX.Element;
741
- declare function ReferralTab(): react_jsx_runtime.JSX.Element;
805
+ }): react.JSX.Element;
806
+ /**
807
+ * @deprecated Renamed to `WorkspaceListTab` in 0.4.0 — the tab is a workspace
808
+ * picker, not the settings of a workspace. Kept as an alias so consumers on
809
+ * the old name keep compiling.
810
+ */
811
+ declare const WorkspaceTab: typeof WorkspaceListTab;
812
+ declare function ReferralTab(): react.JSX.Element;
742
813
  interface SettingsContentProps {
743
814
  adapters: SettingsAdapters;
744
815
  /** Currently active tab. The host owns routing and resolves this from the URL. */
745
816
  activeTab?: SettingsTab;
817
+ /**
818
+ * Leave settings. When supplied, the shell renders a close (×) button in the
819
+ * header and dismisses on Escape; the host decides where "closed" goes
820
+ * (settings is a full route in most hosts, not an overlay).
821
+ *
822
+ * Falls back to `adapters.navigation.close` so hosts that already build an
823
+ * adapter object don't have to thread a second prop through. Omit both and
824
+ * no close affordance is rendered — that is the pre-0.3.8 behaviour.
825
+ */
826
+ onClose?: () => void;
827
+ }
828
+ declare function SettingsContent({ adapters, activeTab, onClose, }: SettingsContentProps): react.JSX.Element;
829
+
830
+ interface WorkspaceData {
831
+ id: string;
832
+ name: string;
833
+ initials: string;
834
+ role: string;
835
+ plan: string;
836
+ ownerEmail: string;
837
+ isCurrent: boolean;
838
+ imageUrl?: string;
839
+ imageName?: string;
840
+ }
841
+ interface WorkspaceModalProps {
842
+ open: boolean;
843
+ mode: "create" | "update";
844
+ workspace?: WorkspaceData | null;
845
+ onClose: () => void;
846
+ onCreate?: (name: string, imageFile: File | null) => void | boolean | Promise<void | boolean>;
847
+ onUpdate?: (name: string, imageFile: File | null, imageRemoved: boolean) => void | boolean | Promise<void | boolean>;
848
+ onLeave?: () => void | boolean | Promise<void | boolean>;
849
+ onDelete?: () => void | boolean | Promise<void | boolean>;
850
+ }
851
+ declare function WorkspaceModal({ open, mode, workspace, onClose, onCreate, onUpdate, onLeave, onDelete, }: WorkspaceModalProps): react.JSX.Element | null;
852
+
853
+ interface WorkspaceGeneralTabProps {
854
+ /** The workspace being edited — always the currently active one. */
855
+ workspace: WorkspaceData | null;
856
+ loading: boolean;
857
+ /** Members in this workspace, when the host has counted them. */
858
+ memberCount?: number | null;
859
+ /** Name of the parent organization, when the workspace has joined one. */
860
+ organizationName?: string | null;
861
+ saving: boolean;
862
+ onSave: (name: string, imageFile: File | null, imageRemoved: boolean) => Promise<boolean>;
863
+ onLeave: () => void;
864
+ onDelete: () => void;
746
865
  }
747
- declare function SettingsContent({ adapters, activeTab }: SettingsContentProps): react_jsx_runtime.JSX.Element;
866
+ declare function WorkspaceGeneralTab({ workspace, loading, memberCount, organizationName, saving, onSave, onLeave, onDelete, }: WorkspaceGeneralTabProps): react.JSX.Element;
748
867
 
749
868
  type IconProps = Omit<SVGProps<SVGSVGElement>, 'color' | 'strokeWidth' | 'width' | 'height'> & {
750
869
  color?: string;
751
870
  strokeWidth?: number | string;
752
871
  size?: number | string;
753
872
  };
754
- declare const SiconKey: ({ color, strokeWidth, size, ...props }: IconProps) => react_jsx_runtime.JSX.Element;
873
+ declare const SiconKey: ({ color, strokeWidth, size, ...props }: IconProps) => react.JSX.Element;
755
874
 
756
875
  declare function BillingContent({ embedded, showPlans: showPlansProp, onShowPlansChange, }?: {
757
876
  embedded?: boolean;
@@ -759,19 +878,41 @@ declare function BillingContent({ embedded, showPlans: showPlansProp, onShowPlan
759
878
  * wrapper) owns it so it can hide the sub-nav + show the Plans breadcrumb. */
760
879
  showPlans?: boolean;
761
880
  onShowPlansChange?: (open: boolean) => void;
762
- }): react_jsx_runtime.JSX.Element;
881
+ }): react__default.JSX.Element;
763
882
 
764
- declare function TeamsContent({ embedded, onInviteOpen, onInviteOpenChange, }?: {
883
+ declare function TeamsContent({ embedded, onInviteOpen, onInviteOpenChange, workspaceName, workspaceImageUrl, organizationName, }?: {
765
884
  embedded?: boolean;
766
885
  onInviteOpen?: boolean;
767
886
  onInviteOpenChange?: (open: boolean) => void;
768
- }): react_jsx_runtime.JSX.Element;
887
+ /**
888
+ * The workspace these members belong to. Supplied by the settings shell so
889
+ * the page can name its own subject — without it this screen was a list of
890
+ * people with no indication of which workspace they were in, and switching
891
+ * workspaces silently changed the contents.
892
+ */
893
+ workspaceName?: string | null;
894
+ workspaceImageUrl?: string;
895
+ /** Parent organization, when the workspace has joined one. */
896
+ organizationName?: string | null;
897
+ }): react.JSX.Element;
769
898
 
770
- declare function OrganizationContent({ embedded, onInviteOpen, onInviteOpenChange, }?: {
899
+ /**
900
+ * Which slice of the organization to show. The tab used to stack all three on
901
+ * one scrolling page, so the members table, the workspace list and the join
902
+ * requests competed for the same screen and the sections below the table were
903
+ * easy to miss entirely.
904
+ *
905
+ * `people` and `domains` split invites by kind on purpose: an email invite is
906
+ * a person you are expecting, a domain invite is a standing rule. They were
907
+ * interleaved in one "Pending" list, where a row could be either.
908
+ */
909
+ type OrganizationView = "people" | "workspaces" | "domains";
910
+ declare function OrganizationContent({ embedded, view, onInviteOpen, onInviteOpenChange, }?: {
771
911
  embedded?: boolean;
912
+ view?: OrganizationView;
772
913
  onInviteOpen?: boolean;
773
914
  onInviteOpenChange?: (open: boolean) => void;
774
- }): react_jsx_runtime.JSX.Element;
915
+ }): react.JSX.Element;
775
916
 
776
917
  declare function TokensContent({ embedded, showRevokedOverride, onShowRevokedChange: _onShowRevokedChange, createOpenOverride, onCreateOpenChange, }?: {
777
918
  embedded?: boolean;
@@ -779,7 +920,7 @@ declare function TokensContent({ embedded, showRevokedOverride, onShowRevokedCha
779
920
  onShowRevokedChange?: (v: boolean) => void;
780
921
  createOpenOverride?: boolean;
781
922
  onCreateOpenChange?: (v: boolean) => void;
782
- }): react_jsx_runtime.JSX.Element;
923
+ }): react.JSX.Element;
783
924
 
784
925
  interface ProfileAvatarProps {
785
926
  name: string;
@@ -792,30 +933,103 @@ interface ProfileAvatarProps {
792
933
  * Renders a profile/workspace avatar using ScDp.
793
934
  * Automatically shows image or initials fallback.
794
935
  */
795
- declare function ProfileAvatar({ name, profileImage, size, initialsClassName, borderRadius, }: ProfileAvatarProps): react_jsx_runtime.JSX.Element;
936
+ declare function ProfileAvatar({ name, profileImage, size, initialsClassName, borderRadius, }: ProfileAvatarProps): react.JSX.Element;
796
937
 
797
- interface WorkspaceData {
798
- id: string;
799
- name: string;
800
- initials: string;
801
- role: string;
802
- plan: string;
803
- ownerEmail: string;
804
- isCurrent: boolean;
938
+ interface ScopeHeaderProps {
939
+ /** Which level of the hierarchy this page acts on. */
940
+ kind: "workspace" | "organization";
941
+ /** The entity's own name. Falls back to the kind when still loading. */
942
+ name?: string | null;
805
943
  imageUrl?: string;
806
- imageName?: string;
944
+ /** The viewer's role in this entity. */
945
+ role?: "admin" | "member" | string | null;
946
+ /**
947
+ * Short factual phrases about the entity — member counts, parent org,
948
+ * workspace counts. Rendered as a single "·"-separated line; empty and
949
+ * nullish entries are dropped so callers can pass conditionals inline.
950
+ */
951
+ facts?: Array<string | null | undefined | false>;
952
+ /** Optional trailing control (e.g. a "Manage" button). */
953
+ action?: ReactNode;
807
954
  }
808
- interface WorkspaceModalProps {
809
- open: boolean;
810
- mode: "create" | "update";
811
- workspace?: WorkspaceData | null;
812
- onClose: () => void;
813
- onCreate?: (name: string, imageFile: File | null) => void | boolean | Promise<void | boolean>;
814
- onUpdate?: (name: string, imageFile: File | null, imageRemoved: boolean) => void | boolean | Promise<void | boolean>;
815
- onLeave?: () => void | boolean | Promise<void | boolean>;
816
- onDelete?: () => void | boolean | Promise<void | boolean>;
955
+ declare function ScopeHeader({ kind, name, imageUrl, role, facts, action, }: ScopeHeaderProps): react.JSX.Element;
956
+ /** `"1 member"` / `"12 members"` — keeps the plural out of every call site. */
957
+ declare function countLabel(n: number, singular: string, plural?: string): string;
958
+
959
+ type MemberListTab = "active" | "pending";
960
+ interface MemberListToolbarProps {
961
+ activeTab: MemberListTab;
962
+ onTabChange: (tab: MemberListTab) => void;
963
+ /** Label for the left tab — "Active" for a workspace, "Members" for an org. */
964
+ activeLabel: string;
965
+ /** Row counts, appended to each tab label. Pass `null` while still loading. */
966
+ activeCount: number | null;
967
+ pendingCount: number | null;
968
+ searchQuery: string;
969
+ onSearchChange: (value: string) => void;
970
+ /** Optional trailing control, e.g. an Invite button on the page itself. */
971
+ action?: ReactNode;
972
+ }
973
+ declare function MemberListToolbar({ activeTab, onTabChange, activeLabel, activeCount, pendingCount, searchQuery, onSearchChange, action, }: MemberListToolbarProps): react.JSX.Element;
974
+ interface MemberListFrameProps {
975
+ /** Column labels, pinned while the rows scroll under them. */
976
+ header?: ReactNode;
977
+ /** Shown in place of the rows when `isEmpty`. */
978
+ emptyText: string;
979
+ isEmpty: boolean;
980
+ /**
981
+ * `"fill"` claims the remaining height and scrolls internally — right for a
982
+ * page whose only content is the list. `"cap"` stops at `maxHeight` so
983
+ * sections below it stay reachable.
984
+ */
985
+ grow?: "fill" | "cap";
986
+ maxHeight?: number;
987
+ /**
988
+ * Minimum width of the rows. Member rows are a flexible identity column plus
989
+ * several fixed ones, so on a narrow screen the identity column is what
990
+ * collapses — leaving an avatar and a role chip with no name or email beside
991
+ * them. Holding the content to a minimum makes the frame scroll sideways
992
+ * instead, which keeps every column readable.
993
+ */
994
+ contentMinWidth?: number;
995
+ children?: ReactNode;
996
+ }
997
+ declare function MemberListFrame({ header, emptyText, isEmpty, grow, maxHeight, contentMinWidth, children, }: MemberListFrameProps): react.JSX.Element;
998
+ /**
999
+ * A small pill marking a workspace member who is *also* a member of the
1000
+ * organization above this workspace.
1001
+ *
1002
+ * It answers a question neither list used to acknowledge: removing someone
1003
+ * here may not remove all their access. Per the org contract, admins of the
1004
+ * parent organization keep implicit access to its workspaces, and a workspace
1005
+ * set to organization-wide visibility is readable by every org member.
1006
+ *
1007
+ * Derived by intersecting this workspace's members with the organization's, so
1008
+ * it states a fact both APIs already report — it is not a guess at an
1009
+ * "inherited permission" flag, which no endpoint exposes.
1010
+ */
1011
+ declare function OrgMembershipTag({ organizationName, isOrgAdmin, }: {
1012
+ organizationName?: string | null;
1013
+ isOrgAdmin?: boolean;
1014
+ }): react.JSX.Element;
1015
+
1016
+ type SettingsTooltipPlacement = "right" | "top" | "bottom";
1017
+ interface SettingsTooltipProps {
1018
+ /** Explanation shown on hover / keyboard focus. Falsy renders the child bare. */
1019
+ content?: ReactNode;
1020
+ /** Preferred side. Flips to the opposite side when it would overflow. */
1021
+ placement?: SettingsTooltipPlacement;
1022
+ /** Milliseconds to hover before the tooltip opens. Closing is immediate. */
1023
+ delay?: number;
1024
+ children: ReactNode;
1025
+ className?: string;
1026
+ /**
1027
+ * The wrapper defaults to `display: block` so full-width nav rows keep their
1028
+ * width. Set this for triggers that sit inside a flex row (buttons, chips).
1029
+ */
1030
+ inline?: boolean;
817
1031
  }
818
- declare function WorkspaceModal({ open, mode, workspace, onClose, onCreate, onUpdate, onLeave, onDelete, }: WorkspaceModalProps): react_jsx_runtime.JSX.Element | null;
1032
+ declare function SettingsTooltip({ content, placement, delay, children, className, inline, }: SettingsTooltipProps): react.JSX.Element;
819
1033
 
820
1034
  interface OrganizationData {
821
1035
  id: string;
@@ -835,7 +1049,7 @@ interface OrganizationModalProps {
835
1049
  onUpdate?: (name: string, imageFile: File | null, imageRemoved: boolean) => void | boolean | Promise<void | boolean>;
836
1050
  onDelete?: () => void | boolean | Promise<void | boolean>;
837
1051
  }
838
- declare function OrganizationModal({ open, mode, organization, onClose, onCreate, onUpdate, onDelete, }: OrganizationModalProps): react_jsx_runtime.JSX.Element | null;
1052
+ declare function OrganizationModal({ open, mode, organization, onClose, onCreate, onUpdate, onDelete, }: OrganizationModalProps): react.JSX.Element | null;
839
1053
 
840
1054
  type ModalMode$1 = "invite" | "update";
841
1055
  interface OrganizationInviteModalProps {
@@ -864,7 +1078,7 @@ interface OrganizationInviteModalProps {
864
1078
  }) => void;
865
1079
  onRemove?: () => void;
866
1080
  }
867
- declare function OrganizationInviteModal({ open, mode, userEmail, initialRole, initialInviteAccess, allowSubmitWithoutChanges, canRemove, onClose, onInviteEmail, onInviteDomain, onUpdate, onRemove, }: OrganizationInviteModalProps): react_jsx_runtime.JSX.Element | null;
1081
+ declare function OrganizationInviteModal({ open, mode, userEmail, initialRole, initialInviteAccess, allowSubmitWithoutChanges, canRemove, onClose, onInviteEmail, onInviteDomain, onUpdate, onRemove, }: OrganizationInviteModalProps): react.JSX.Element | null;
868
1082
 
869
1083
  interface ConfirmLeaveModalProps {
870
1084
  open: boolean;
@@ -876,7 +1090,7 @@ interface ConfirmLeaveModalProps {
876
1090
  /** Called when user clicks "Go to Teams" in the sole admin variant */
877
1091
  onGoToTeams?: () => void;
878
1092
  }
879
- declare function ConfirmLeaveModal({ open, workspaceName, isSoleAdmin, onClose, onConfirm, onGoToTeams, }: ConfirmLeaveModalProps): react_jsx_runtime.JSX.Element | null;
1093
+ declare function ConfirmLeaveModal({ open, workspaceName, isSoleAdmin, onClose, onConfirm, onGoToTeams, }: ConfirmLeaveModalProps): react.JSX.Element | null;
880
1094
 
881
1095
  interface ConfirmDeleteModalProps {
882
1096
  open: boolean;
@@ -884,7 +1098,7 @@ interface ConfirmDeleteModalProps {
884
1098
  onClose: () => void;
885
1099
  onConfirm: () => void | Promise<void>;
886
1100
  }
887
- declare function ConfirmDeleteModal({ open, workspaceName, onClose, onConfirm, }: ConfirmDeleteModalProps): react_jsx_runtime.JSX.Element | null;
1101
+ declare function ConfirmDeleteModal({ open, workspaceName, onClose, onConfirm, }: ConfirmDeleteModalProps): react.JSX.Element | null;
888
1102
 
889
1103
  interface BuyCreditsModalProps {
890
1104
  currencySymbol?: string;
@@ -892,7 +1106,7 @@ interface BuyCreditsModalProps {
892
1106
  onClose: () => void;
893
1107
  onBuy: (credits: number, price: number) => void;
894
1108
  }
895
- declare function BuyCreditsModal({ currencySymbol, country, onClose, onBuy, }: BuyCreditsModalProps): react_jsx_runtime.JSX.Element;
1109
+ declare function BuyCreditsModal({ currencySymbol, country, onClose, onBuy, }: BuyCreditsModalProps): react.JSX.Element;
896
1110
 
897
1111
  interface UserPermissions {
898
1112
  artifax: boolean;
@@ -940,19 +1154,19 @@ interface InviteUpdateModalProps {
940
1154
  /** Called only in invite mode; receives (permissions, email) */
941
1155
  onInvite?: (permissions: UserPermissions, email: string) => void;
942
1156
  }
943
- declare function InviteUpdateModal({ open, mode, userEmail, stores, allowSubmitWithoutChanges, initialPermissions, onClose, onSave, onRemove, canRemove, onInvite, }: InviteUpdateModalProps): react_jsx_runtime.JSX.Element | null;
1157
+ declare function InviteUpdateModal({ open, mode, userEmail, stores, allowSubmitWithoutChanges, initialPermissions, onClose, onSave, onRemove, canRemove, onInvite, }: InviteUpdateModalProps): react.JSX.Element | null;
944
1158
 
945
1159
  interface ExportDateModalProps {
946
1160
  title: string;
947
1161
  onClose: () => void;
948
1162
  onExport: (startDate: Date, endDate: Date) => void;
949
1163
  }
950
- declare function ExportDateModal({ title, onClose, onExport, }: ExportDateModalProps): react_jsx_runtime.JSX.Element;
1164
+ declare function ExportDateModal({ title, onClose, onExport, }: ExportDateModalProps): react.JSX.Element;
951
1165
 
952
1166
  declare function SettingsAdaptersProvider({ adapters, children, }: {
953
1167
  adapters: SettingsAdapters;
954
1168
  children: ReactNode;
955
- }): react_jsx_runtime.JSX.Element;
1169
+ }): react.JSX.Element;
956
1170
  /**
957
1171
  * Read the host-provided adapters from anywhere inside <SettingsContent>.
958
1172
  * Throws at runtime if used outside the provider — which only happens if a
@@ -960,4 +1174,4 @@ declare function SettingsAdaptersProvider({ adapters, children, }: {
960
1174
  */
961
1175
  declare function useSettingsAdapters(): SettingsAdapters;
962
1176
 
963
- export { type ApiToken, type AvailableCreditsResponse, BillingContent, type BillingEventPayload, type BillingProduct, type BillingSubscription, BuyCreditsModal, type BuyCreditsPayload, type BuyCreditsResponse, ConfirmDeleteModal, ConfirmLeaveModal, type CreatedToken, type CustomCreditInfo, type CustomCreditResponse, DEFAULT_PERMISSIONS, ExportDateModal, InviteUpdateModal, type InvoicePdfResponse, type MemberPermissionsPayload, OrganizationContent, type OrganizationData, type OrganizationInvite, OrganizationInviteModal, type OrganizationInviteModalProps, type OrganizationJoinRequest, type OrganizationMember, OrganizationModal, type OrganizationWorkspaceItem, type Price, type PriceMetadata, type ProductsResponse, ProfileAvatar, ProfileTab, ReferralTab, type ServiceItem, type SettingsAdapters, SettingsAdaptersProvider, type SettingsApiAdapter, type SettingsAuthAdapter, type SettingsAuthUser, SettingsContent, type SettingsContentProps, type SettingsImageUploadAdapter, type SettingsNavigationAdapter, type SettingsOrganizationAdapter, type SettingsOrganizationCurrent, type SettingsOrganizationListItem, type SettingsTab, type SettingsToastAdapter, type SettingsWorkspaceAdapter, type SettingsWorkspaceCurrent, type SettingsWorkspaceListItem, SiconKey, type StoreItem, type SubscriptionPlan, type SubscriptionResponse, TAB_LABELS, TAB_TO_URL, type TeamMember, TeamsContent, type TokenExpiry, TokensContent, URL_TO_TAB, type UpdateSubscriptionPayload, type UpdateSubscriptionResponse, type UsageHistoryItem, type UsageHistoryResponse, type UserPermissions, type WorkspaceData, type WorkspaceInvite, type WorkspaceMember, WorkspaceModal, WorkspaceTab, resolveSettingsTabFromPath, useSettingsAdapters };
1177
+ export { type ApiToken, type AvailableCreditsResponse, BillingContent, type BillingEventPayload, type BillingProduct, type BillingSubscription, BuyCreditsModal, type BuyCreditsPayload, type BuyCreditsResponse, ConfirmDeleteModal, ConfirmLeaveModal, type CreatedToken, type CustomCreditInfo, type CustomCreditResponse, DEFAULT_PERMISSIONS, ExportDateModal, InviteUpdateModal, type InvoicePdfResponse, MemberListFrame, type MemberListFrameProps, type MemberListTab, MemberListToolbar, type MemberListToolbarProps, type MemberPermissionsPayload, OrgMembershipTag, OrganizationContent, type OrganizationData, type OrganizationInvite, OrganizationInviteModal, type OrganizationInviteModalProps, type OrganizationJoinRequest, type OrganizationMember, OrganizationModal, type OrganizationView, type OrganizationWorkspaceItem, type Price, type PriceMetadata, type ProductsResponse, ProfileAvatar, ProfileTab, ReferralTab, SCOPE_LABELS, ScopeHeader, type ScopeHeaderProps, type ServiceItem, type SettingsAdapters, SettingsAdaptersProvider, type SettingsApiAdapter, type SettingsAuthAdapter, type SettingsAuthUser, SettingsContent, type SettingsContentProps, type SettingsImageUploadAdapter, type SettingsNavigationAdapter, type SettingsOrganizationAdapter, type SettingsOrganizationCurrent, type SettingsOrganizationListItem, type SettingsScope, type SettingsTab, type SettingsToastAdapter, SettingsTooltip, type SettingsTooltipPlacement, type SettingsTooltipProps, type SettingsWorkspaceAdapter, type SettingsWorkspaceCurrent, type SettingsWorkspaceListItem, SiconKey, type StoreItem, type SubscriptionPlan, type SubscriptionResponse, TAB_DESCRIPTIONS, TAB_LABELS, TAB_SCOPE, TAB_TO_URL, type TeamMember, TeamsContent, type TokenExpiry, TokensContent, URL_TO_TAB, type UpdateSubscriptionPayload, type UpdateSubscriptionResponse, type UsageHistoryItem, type UsageHistoryResponse, type UserPermissions, type WorkspaceData, WorkspaceGeneralTab, type WorkspaceGeneralTabProps, type WorkspaceInvite, WorkspaceListTab, type WorkspaceMember, WorkspaceModal, WorkspaceTab, countLabel, resolveSettingsTabFromPath, useSettingsAdapters };