@cosmoops/connect-sdk 0.9.0 → 0.16.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/CHANGELOG.md +566 -0
- package/README.md +113 -42
- package/dist/cjs/cli/doctor.js +3 -3
- package/dist/cjs/cli/init.js +3 -3
- package/dist/cjs/client/components/access-gate.js +20 -1
- package/dist/cjs/client/components/ai-screens.js +73 -0
- package/dist/cjs/client/components/ai-widgets.js +37 -0
- package/dist/cjs/client/components/app-shell.js +75 -41
- package/dist/cjs/client/components/apps-grid.js +3 -2
- package/dist/cjs/client/components/ask-ai.js +50 -5
- package/dist/cjs/client/components/confirm-dialog.js +40 -0
- package/dist/cjs/client/components/cursor-pagination.js +22 -0
- package/dist/cjs/client/components/filter-tabs.js +24 -0
- package/dist/cjs/client/components/grievance-notice.js +30 -0
- package/dist/cjs/client/components/link-button.js +17 -10
- package/dist/cjs/client/components/logo.js +4 -3
- package/dist/cjs/client/components/nav.js +41 -0
- package/dist/cjs/client/components/plan-pricing.js +27 -0
- package/dist/cjs/client/components/plans.js +1 -1
- package/dist/cjs/client/components/platform-gate.js +48 -0
- package/dist/cjs/client/components/shell-context.js +149 -0
- package/dist/cjs/client/components/side-nav.js +49 -23
- package/dist/cjs/client/components/sidebar.js +127 -0
- package/dist/cjs/client/components/subscribe-dialog.js +2 -2
- package/dist/cjs/client/components/subscription.js +1 -1
- package/dist/cjs/client/components/user-menu.js +96 -37
- package/dist/cjs/client/components/workspace-switcher.js +100 -0
- package/dist/cjs/client/index.js +72 -2
- package/dist/cjs/client/provider.js +57 -2
- package/dist/cjs/client/use-checkout.js +9 -5
- package/dist/cjs/errors.js +1 -1
- package/dist/cjs/index.js +16 -1
- package/dist/cjs/mcp/index.js +90 -0
- package/dist/cjs/mcp/tools.js +369 -0
- package/dist/cjs/next/index.js +2 -2
- package/dist/cjs/server/client.js +25 -2
- package/dist/cjs/server/handler.js +203 -18
- package/dist/cjs/server/http.js +6 -2
- package/dist/cjs/server/resources/acting-as.js +16 -0
- package/dist/cjs/server/resources/ai.js +22 -2
- package/dist/cjs/server/resources/data.js +374 -0
- package/dist/cjs/server/resources/identity.js +7 -3
- package/dist/cjs/server/resources/kv.js +84 -0
- package/dist/cjs/server/resources/platform.js +43 -0
- package/dist/cjs/server/resources/sessions.js +1 -1
- package/dist/cjs/server/resources/workspaces.js +74 -0
- package/dist/cjs/store-schema.js +66 -0
- package/dist/cjs/store.js +152 -0
- package/dist/cjs/ui/empty-state.js +28 -0
- package/dist/cjs/ui/index.js +44 -0
- package/dist/cjs/ui/page-header.js +27 -0
- package/dist/cjs/ui/page-shell.js +44 -0
- package/dist/cjs/ui/section.js +20 -0
- package/dist/cjs/ui/setting-row.js +14 -0
- package/dist/cjs/ui/status-chip.js +17 -0
- package/dist/esm/cli/doctor.js +3 -3
- package/dist/esm/cli/init.js +3 -3
- package/dist/esm/client/components/access-gate.js +20 -1
- package/dist/esm/client/components/ai-screens.js +69 -0
- package/dist/esm/client/components/ai-widgets.js +37 -1
- package/dist/esm/client/components/app-shell.js +81 -47
- package/dist/esm/client/components/apps-grid.js +3 -2
- package/dist/esm/client/components/ask-ai.js +51 -6
- package/dist/esm/client/components/confirm-dialog.js +37 -0
- package/dist/esm/client/components/cursor-pagination.js +19 -0
- package/dist/esm/client/components/filter-tabs.js +21 -0
- package/dist/esm/client/components/grievance-notice.js +27 -0
- package/dist/esm/client/components/link-button.js +17 -10
- package/dist/esm/client/components/logo.js +4 -3
- package/dist/esm/client/components/nav.js +40 -0
- package/dist/esm/client/components/plan-pricing.js +25 -0
- package/dist/esm/client/components/plans.js +2 -2
- package/dist/esm/client/components/platform-gate.js +45 -0
- package/dist/esm/client/components/shell-context.js +141 -0
- package/dist/esm/client/components/side-nav.js +48 -21
- package/dist/esm/client/components/sidebar.js +120 -0
- package/dist/esm/client/components/subscribe-dialog.js +3 -3
- package/dist/esm/client/components/subscription.js +2 -2
- package/dist/esm/client/components/user-menu.js +95 -38
- package/dist/esm/client/components/workspace-switcher.js +97 -0
- package/dist/esm/client/index.js +47 -4
- package/dist/esm/client/provider.js +53 -2
- package/dist/esm/client/use-checkout.js +9 -5
- package/dist/esm/errors.js +1 -1
- package/dist/esm/index.js +4 -0
- package/dist/esm/mcp/index.js +85 -0
- package/dist/esm/mcp/tools.js +366 -0
- package/dist/esm/next/index.js +2 -2
- package/dist/esm/server/client.js +25 -2
- package/dist/esm/server/handler.js +203 -18
- package/dist/esm/server/http.js +6 -2
- package/dist/esm/server/resources/acting-as.js +13 -0
- package/dist/esm/server/resources/ai.js +22 -2
- package/dist/esm/server/resources/data.js +369 -0
- package/dist/esm/server/resources/identity.js +7 -3
- package/dist/esm/server/resources/kv.js +80 -0
- package/dist/esm/server/resources/platform.js +39 -0
- package/dist/esm/server/resources/sessions.js +1 -1
- package/dist/esm/server/resources/workspaces.js +70 -0
- package/dist/esm/store-schema.js +62 -0
- package/dist/esm/store.js +141 -0
- package/dist/esm/ui/empty-state.js +25 -0
- package/dist/esm/ui/index.js +34 -0
- package/dist/esm/ui/page-header.js +24 -0
- package/dist/esm/ui/page-shell.js +41 -0
- package/dist/esm/ui/section.js +17 -0
- package/dist/esm/ui/setting-row.js +11 -0
- package/dist/esm/ui/status-chip.js +14 -0
- package/dist/types/client/components/ai-screens.d.ts +25 -0
- package/dist/types/client/components/ai-widgets.d.ts +34 -1
- package/dist/types/client/components/app-shell.d.ts +65 -27
- package/dist/types/client/components/apps-grid.d.ts +11 -2
- package/dist/types/client/components/ask-ai.d.ts +47 -1
- package/dist/types/client/components/confirm-dialog.d.ts +34 -0
- package/dist/types/client/components/cursor-pagination.d.ts +27 -0
- package/dist/types/client/components/filter-tabs.d.ts +26 -0
- package/dist/types/client/components/grievance-notice.d.ts +31 -0
- package/dist/types/client/components/link-button.d.ts +32 -9
- package/dist/types/client/components/logo.d.ts +18 -2
- package/dist/types/client/components/nav.d.ts +24 -0
- package/dist/types/client/components/plan-pricing.d.ts +10 -0
- package/dist/types/client/components/platform-gate.d.ts +53 -0
- package/dist/types/client/components/shell-context.d.ts +116 -0
- package/dist/types/client/components/side-nav.d.ts +27 -13
- package/dist/types/client/components/sidebar.d.ts +95 -0
- package/dist/types/client/components/user-menu.d.ts +68 -22
- package/dist/types/client/components/workspace-switcher.d.ts +49 -0
- package/dist/types/client/index.d.ts +29 -5
- package/dist/types/client/provider.d.ts +109 -6
- package/dist/types/client/use-checkout.d.ts +8 -4
- package/dist/types/errors.d.ts +1 -1
- package/dist/types/index.d.ts +6 -0
- package/dist/types/mcp/index.d.ts +74 -0
- package/dist/types/mcp/tools.d.ts +107 -0
- package/dist/types/next/index.d.ts +1 -1
- package/dist/types/server/client.d.ts +25 -2
- package/dist/types/server/http.d.ts +8 -2
- package/dist/types/server/index.d.ts +4 -0
- package/dist/types/server/resources/acting-as.d.ts +11 -0
- package/dist/types/server/resources/ai.d.ts +20 -2
- package/dist/types/server/resources/data.d.ts +258 -0
- package/dist/types/server/resources/kv.d.ts +63 -0
- package/dist/types/server/resources/platform.d.ts +32 -0
- package/dist/types/server/resources/workspaces.d.ts +55 -0
- package/dist/types/store-schema.d.ts +52 -0
- package/dist/types/store.d.ts +96 -0
- package/dist/types/types.d.ts +369 -16
- package/dist/types/ui/empty-state.d.ts +34 -0
- package/dist/types/ui/index.d.ts +40 -0
- package/dist/types/ui/page-header.d.ts +34 -0
- package/dist/types/ui/page-shell.d.ts +39 -0
- package/dist/types/ui/section.d.ts +26 -0
- package/dist/types/ui/setting-row.d.ts +18 -0
- package/dist/types/ui/status-chip.d.ts +36 -0
- package/package.json +15 -2
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export interface ConnectConfirmDialogProps {
|
|
3
|
+
/** The control that opens it. Rendered inside `Modal.Trigger`. */
|
|
4
|
+
trigger: ReactNode;
|
|
5
|
+
title: ReactNode;
|
|
6
|
+
/** What will happen, in the user's words. Name the thing being acted on. */
|
|
7
|
+
description?: ReactNode;
|
|
8
|
+
confirmLabel?: string;
|
|
9
|
+
cancelLabel?: string;
|
|
10
|
+
/** `danger` for anything that destroys data. */
|
|
11
|
+
tone?: "danger" | "primary";
|
|
12
|
+
onConfirm: () => void | Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The confirmation in front of a destructive action.
|
|
16
|
+
*
|
|
17
|
+
* **It closes on confirm, not on response.** Holding the modal open until the
|
|
18
|
+
* server answers makes every delete feel like a form submission, and the error
|
|
19
|
+
* path already has somewhere to go - a toast, or the row reappearing. A dialog
|
|
20
|
+
* that stays open to report failure is right only where the failure is
|
|
21
|
+
* *expected* and correctable in place (a seat cap, a last-admin invariant),
|
|
22
|
+
* and that is a blocking form, not this.
|
|
23
|
+
*
|
|
24
|
+
* `onConfirm` may return a promise. It is not awaited before closing, but a
|
|
25
|
+
* rejection is caught here rather than escaping - an error thrown out of an
|
|
26
|
+
* async transition reaches the nearest error boundary and takes the page down.
|
|
27
|
+
*
|
|
28
|
+
* The anatomy is HeroUI's: `Modal.Backdrop` owns the open state,
|
|
29
|
+
* `Modal.Container` the sizing, `Modal.Dialog` the focus trap. The trigger
|
|
30
|
+
* goes inside `Modal.Trigger`, which *is* a React Aria button - so pass a
|
|
31
|
+
* plain element, never a `<Button>`, or the nested button swallows the press
|
|
32
|
+
* and the dialog silently never opens.
|
|
33
|
+
*/
|
|
34
|
+
export declare function ConnectConfirmDialog({ trigger, title, description, confirmLabel, cancelLabel, tone, onConfirm, }: Readonly<ConnectConfirmDialogProps>): import("react").JSX.Element;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface ConnectCursorPaginationProps {
|
|
2
|
+
/** How many rows the current page is showing. Used for the live-region count. */
|
|
3
|
+
shown: number;
|
|
4
|
+
/** The cursor for the next page, or `null` when this is the last one. */
|
|
5
|
+
nextCursor: string | null;
|
|
6
|
+
/** Whether a previous page exists - the caller owns the cursor history. */
|
|
7
|
+
hasPrevious: boolean;
|
|
8
|
+
onNext: (cursor: string) => void;
|
|
9
|
+
onPrevious: () => void;
|
|
10
|
+
isPending?: boolean;
|
|
11
|
+
/** Singular/plural noun for the count, e.g. `["contact", "contacts"]`. */
|
|
12
|
+
noun?: readonly [string, string];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Next / previous for a cursor-paginated list.
|
|
16
|
+
*
|
|
17
|
+
* Cursor rather than page numbers, and the component shape follows from that:
|
|
18
|
+
* there is no "page 7 of 42" because a keyset-paginated list does not know how
|
|
19
|
+
* many pages there are without a second count query over the same filter -
|
|
20
|
+
* which is a billed index scan for a number nobody acts on. What a user does
|
|
21
|
+
* act on is "more" and "back", and those are exact.
|
|
22
|
+
*
|
|
23
|
+
* The count is announced in a live region so a screen-reader user learns that
|
|
24
|
+
* filtering or paging changed the result set. Without it the table silently
|
|
25
|
+
* swaps its contents.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ConnectCursorPagination({ shown, nextCursor, hasPrevious, onNext, onPrevious, isPending, noun, }: Readonly<ConnectCursorPaginationProps>): import("react").JSX.Element;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface ConnectFilterTabsOption<TValue extends string> {
|
|
2
|
+
value: TValue | null;
|
|
3
|
+
label: string;
|
|
4
|
+
/** Shown as a count beside the label. Omit where a count would need its own query. */
|
|
5
|
+
count?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface ConnectFilterTabsProps<TValue extends string> {
|
|
8
|
+
options: ReadonlyArray<ConnectFilterTabsOption<TValue>>;
|
|
9
|
+
value: TValue | null;
|
|
10
|
+
onChange: (value: TValue | null) => void;
|
|
11
|
+
/** Names the group for assistive technology - "Filter contacts by lifecycle". */
|
|
12
|
+
label: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A single-select filter strip - the "All / Open / Won / Lost" row above a
|
|
16
|
+
* list.
|
|
17
|
+
*
|
|
18
|
+
* Real radio semantics rather than a row of buttons: it is a single choice
|
|
19
|
+
* from a closed set, so arrow keys should move between options and the
|
|
20
|
+
* selected one should be announced as selected. A group of `<button>`s gets
|
|
21
|
+
* neither, and that is the usual hand-rolled shape.
|
|
22
|
+
*
|
|
23
|
+
* Scrolls horizontally rather than wrapping on a narrow viewport - a filter
|
|
24
|
+
* strip that wraps to three lines pushes the list itself off the screen.
|
|
25
|
+
*/
|
|
26
|
+
export declare function ConnectFilterTabs<TValue extends string>({ options, value, onChange, label, }: Readonly<ConnectFilterTabsProps<TValue>>): import("react").JSX.Element;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface ConnectGrievanceNoticeProps {
|
|
3
|
+
/**
|
|
4
|
+
* Heading text. `null` renders none, for embedding inside a page that
|
|
5
|
+
* already has one.
|
|
6
|
+
*/
|
|
7
|
+
title?: ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* What this application calls itself in the sentence naming the processor
|
|
10
|
+
* relationship. Omit to leave that sentence out entirely.
|
|
11
|
+
*/
|
|
12
|
+
applicationName?: string;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The DPDP s.13 grievance channel, rendered.
|
|
17
|
+
*
|
|
18
|
+
* Every application on the platform is a Data Processor under one notice, so
|
|
19
|
+
* the wording lives here rather than being retyped per application - a user
|
|
20
|
+
* comparing two applications' privacy pages should not find two different
|
|
21
|
+
* accounts of who their Data Fiduciary is.
|
|
22
|
+
*
|
|
23
|
+
* Renders nothing at all while loading and nothing on failure, rather than a
|
|
24
|
+
* skeleton or an error. That is unusual here and deliberate: this component
|
|
25
|
+
* is almost always inside a larger privacy page that has its own content, and
|
|
26
|
+
* a red error box in the middle of a legal notice reads as the notice itself
|
|
27
|
+
* being broken. The address is also on the public web either way. Pass
|
|
28
|
+
* `useConnectCompanyProfile()` directly to your own layout if you want to
|
|
29
|
+
* handle those states yourself.
|
|
30
|
+
*/
|
|
31
|
+
export declare function ConnectGrievanceNotice({ title, applicationName, className, }: Readonly<ConnectGrievanceNoticeProps>): import("react").JSX.Element | null;
|
|
@@ -1,20 +1,43 @@
|
|
|
1
1
|
import { type ButtonProps } from "@heroui/react";
|
|
2
|
+
import type { ReactElement, ReactNode } from "react";
|
|
2
3
|
export type ConnectLinkButtonProps = Omit<ButtonProps, "render"> & {
|
|
3
4
|
href: string;
|
|
5
|
+
/**
|
|
6
|
+
* The host's router link, if it has one.
|
|
7
|
+
*
|
|
8
|
+
* Without it this renders a plain `<a href>`, which navigates under every
|
|
9
|
+
* router but costs a **full document load** - in an App Router app that
|
|
10
|
+
* throws away the client cache and re-runs the whole tree, which is very
|
|
11
|
+
* visible on a button sitting inside a page the user is working in.
|
|
12
|
+
*
|
|
13
|
+
* ```tsx
|
|
14
|
+
* <ConnectLinkButton href="/deals" renderLink={(props) => <Link {...props} />}>
|
|
15
|
+
* Open board
|
|
16
|
+
* </ConnectLinkButton>
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Same shape as `AppShell`'s `renderLink`, so a host declares its router
|
|
20
|
+
* once and passes the same function to both. This package imports nothing
|
|
21
|
+
* from `next` - see the `./next` entry's doc comment for why that is a hard
|
|
22
|
+
* rule - so handing the link component in is the only way it can be a client
|
|
23
|
+
* transition.
|
|
24
|
+
*/
|
|
25
|
+
renderLink?: (props: {
|
|
26
|
+
href: string;
|
|
27
|
+
className?: string;
|
|
28
|
+
children: ReactNode;
|
|
29
|
+
}) => ReactElement;
|
|
4
30
|
};
|
|
5
31
|
/**
|
|
6
|
-
* A HeroUI `Button` that renders a
|
|
32
|
+
* A HeroUI `Button` that renders a link.
|
|
7
33
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* rule), so it cannot know which router - if any - the host app uses. An
|
|
11
|
-
* `<a href>` navigates under all of them, and a host that wants client-side
|
|
12
|
-
* routing can pass its own element via `render` on the underlying `Button`.
|
|
34
|
+
* HeroUI v3's `Button` has no `as` prop, so `<Button as={Link}>` does not type
|
|
35
|
+
* check and does not work - this is the supported route, via `render`.
|
|
13
36
|
*
|
|
14
37
|
* The cast is the same one HeroUI's own "Render Function" example needs:
|
|
15
38
|
* `render` types its argument as the props of the element `Button` would have
|
|
16
|
-
* emitted, which is a `<button
|
|
39
|
+
* emitted, which is a `<button>`, including a `ref` typed to
|
|
17
40
|
* `HTMLButtonElement`. Spreading that onto an anchor is sound at runtime and
|
|
18
|
-
* unrepresentable in the type, which is
|
|
41
|
+
* unrepresentable in the type, which is what the cast is for.
|
|
19
42
|
*/
|
|
20
|
-
export declare function ConnectLinkButton({ href, ...props }: Readonly<ConnectLinkButtonProps>): import("react").JSX.Element;
|
|
43
|
+
export declare function ConnectLinkButton({ href, renderLink, ...props }: Readonly<ConnectLinkButtonProps>): import("react").JSX.Element;
|
|
@@ -14,7 +14,23 @@ export interface ConnectLogoProps {
|
|
|
14
14
|
* Falls back to the Connect rings when omitted.
|
|
15
15
|
*/
|
|
16
16
|
icon?: ReactNode;
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Which halves of the lockup to draw.
|
|
19
|
+
*
|
|
20
|
+
* - `"full"` - badge and wordmark, the default.
|
|
21
|
+
* - `"mark"` - the badge alone, for a collapsed rail or a favicon-sized slot.
|
|
22
|
+
* - `"wordmark"` - the words alone, for a layout that already draws the
|
|
23
|
+
* badge somewhere fixed. The sidebar header uses this: the badge stays put
|
|
24
|
+
* while the words fade, and rendering a second badge only to hide it with
|
|
25
|
+
* a CSS child selector is how that kind of layout quietly rots.
|
|
26
|
+
*/
|
|
27
|
+
variant?: "full" | "mark" | "wordmark";
|
|
28
|
+
/**
|
|
29
|
+
* Mark only, no wordmark.
|
|
30
|
+
*
|
|
31
|
+
* @deprecated Pass `variant="mark"`. Kept because it is the published 0.11
|
|
32
|
+
* API; `variant` wins when both are given.
|
|
33
|
+
*/
|
|
18
34
|
collapsed?: boolean;
|
|
19
35
|
className?: string;
|
|
20
36
|
}
|
|
@@ -32,4 +48,4 @@ export interface ConnectLogoProps {
|
|
|
32
48
|
* as `text-sm`, with the badge, gap and tracking all in proportion. That is
|
|
33
49
|
* why there is no `size` prop.
|
|
34
50
|
*/
|
|
35
|
-
export declare function ConnectLogo({ name, icon, collapsed, className }: ConnectLogoProps): import("react").JSX.Element;
|
|
51
|
+
export declare function ConnectLogo({ name, icon, variant, collapsed, className }: ConnectLogoProps): import("react").JSX.Element;
|
|
@@ -33,6 +33,21 @@ export interface ConnectNavItem {
|
|
|
33
33
|
* step with this one.
|
|
34
34
|
*/
|
|
35
35
|
gateExempt?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Who this route is for. Omit - the default - and it renders for everyone,
|
|
38
|
+
* which is what every route on an ordinary application is.
|
|
39
|
+
*
|
|
40
|
+
* - `"staff"` shows it only to a Connect platform staff session; your
|
|
41
|
+
* operator console goes here.
|
|
42
|
+
* - `"member"` hides it *from* staff. Reach for it on anything that reads
|
|
43
|
+
* the workspace - billing, plans, usage, team - since a staff session has
|
|
44
|
+
* no workspace and those routes can only fail for it.
|
|
45
|
+
*
|
|
46
|
+
* Filtering here is presentation, not access: it decides which links a
|
|
47
|
+
* person sees, and a link is not a permission. The route itself must still
|
|
48
|
+
* check `staff` on your server - see `<ConnectPlatformGate>`.
|
|
49
|
+
*/
|
|
50
|
+
audience?: "staff" | "member";
|
|
36
51
|
}
|
|
37
52
|
/** A titled group of items. Untitled groups render as a plain divider-free block. */
|
|
38
53
|
export interface ConnectNavSection {
|
|
@@ -106,5 +121,14 @@ export declare function resolveActivePath(pathname: string, nav: ConnectNav): st
|
|
|
106
121
|
* lights up on every app's home route. External items are never active.
|
|
107
122
|
*/
|
|
108
123
|
export declare function isNavItemActive(item: ConnectNavItem, activeHref: string | null): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* `nav` with every item the current session should not see removed - see
|
|
126
|
+
* `ConnectNavItem.audience`.
|
|
127
|
+
*
|
|
128
|
+
* Applied to nested `items` too, and a parent whose children all disappear is
|
|
129
|
+
* dropped along with them: a section header pointing at nothing reads as a
|
|
130
|
+
* broken link rather than as a hidden one.
|
|
131
|
+
*/
|
|
132
|
+
export declare function filterNavForAudience(nav: ConnectNav, isStaff: boolean): ConnectNav;
|
|
109
133
|
/** Hrefs declared `gateExempt` - the routes `AppShell` renders outside its `ConnectAccessGate`. */
|
|
110
134
|
export declare function gateExemptPaths(nav: ConnectNav): string[];
|
|
@@ -24,6 +24,16 @@ export declare function formatPrice(paise: number): string;
|
|
|
24
24
|
* plan reads as an upgrade over every monthly one.
|
|
25
25
|
*/
|
|
26
26
|
export declare function monthlyOf(price: number, billingInterval: Plan["billingInterval"]): number;
|
|
27
|
+
export declare function intervalLabel(billingInterval: Plan["billingInterval"]): {
|
|
28
|
+
per: string;
|
|
29
|
+
short: string;
|
|
30
|
+
adverb: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* `/month`, `/year` - and nothing at all for a one-time plan, where a price
|
|
34
|
+
* with no slash is the honest rendering.
|
|
35
|
+
*/
|
|
36
|
+
export declare function pricePerLabel(billingInterval: Plan["billingInterval"]): string;
|
|
27
37
|
export declare function discountLabel(discount: AppliedDiscount): string;
|
|
28
38
|
/**
|
|
29
39
|
* The minimum a plan-like object has to expose to be grouped or compared -
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface ConnectPlatformGateProps {
|
|
3
|
+
/**
|
|
4
|
+
* Restrict to these platform roles. Omit to accept any staff session, which
|
|
5
|
+
* is the common case - your application already chose which roles it accepts
|
|
6
|
+
* when a platform admin turned staff access on for it, and repeating that
|
|
7
|
+
* list here is a second copy to keep in sync.
|
|
8
|
+
*
|
|
9
|
+
* Pass one only when your own console has tiers: a `developer` seeing the
|
|
10
|
+
* read-only half of what a `platform_admin` can edit.
|
|
11
|
+
*/
|
|
12
|
+
roles?: string[];
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
/**
|
|
15
|
+
* Rendered for an ordinary member session. Defaults to `null` - hiding the
|
|
16
|
+
* subtree, which is what this gate is normally for. An operator console is
|
|
17
|
+
* usually better hidden than explained.
|
|
18
|
+
*/
|
|
19
|
+
fallback?: ReactNode;
|
|
20
|
+
/** Shown until the session read settles. Defaults to nothing. */
|
|
21
|
+
loading?: ReactNode;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Renders `children` only for a Connect platform staff session.
|
|
25
|
+
*
|
|
26
|
+
* ```tsx
|
|
27
|
+
* <ConnectPlatformGate>
|
|
28
|
+
* <LinkMasterConsole />
|
|
29
|
+
* </ConnectPlatformGate>
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* Staff are Connect's own operators - `platform_admin`, `platform_manager`,
|
|
33
|
+
* `developer` - signing into *your* application. They belong to no workspace,
|
|
34
|
+
* so a staff session carries no `workspaceId`, no subscription and no member
|
|
35
|
+
* role; see `SessionAccess.staff`. Staff access is off by default and turned on
|
|
36
|
+
* per application by a Connect platform admin, so this gate renders nothing
|
|
37
|
+
* until that happens.
|
|
38
|
+
*
|
|
39
|
+
* **This is a UX gate, not a security boundary** - the same caveat every gate
|
|
40
|
+
* in this package carries, and it matters more here than anywhere else,
|
|
41
|
+
* because what is behind this one is usually an operator console. The browser
|
|
42
|
+
* can ignore this component entirely. Every route it reveals must re-check
|
|
43
|
+
* `staff` on your own server:
|
|
44
|
+
*
|
|
45
|
+
* ```ts
|
|
46
|
+
* const { staff, role } = await client.identity.getUser(sessionToken);
|
|
47
|
+
* if (!staff) return forbidden();
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* Renders `loading` - not `fallback` - while the session is unknown, so an
|
|
51
|
+
* operator never flickers through the customer layout on the way in.
|
|
52
|
+
*/
|
|
53
|
+
export declare function ConnectPlatformGate({ roles, children, fallback, loading, }: ConnectPlatformGateProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { ConnectLinkRenderer } from "./nav.js";
|
|
3
|
+
/** A plain anchor - correct anywhere, and a full page load. See `ConnectLinkRenderer`. */
|
|
4
|
+
export declare const defaultRenderLink: ConnectLinkRenderer;
|
|
5
|
+
/**
|
|
6
|
+
* The rail's two widths, in pixels, and the one place they are written down.
|
|
7
|
+
*
|
|
8
|
+
* They are numbers rather than Tailwind classes because the rail animates
|
|
9
|
+
* between them - `motion` interpolates a number and cannot interpolate
|
|
10
|
+
* `w-16` into `w-64`.
|
|
11
|
+
*
|
|
12
|
+
* **The pairing is load-bearing, not arbitrary.** Every row in the sidebar is
|
|
13
|
+
* laid out so its glyph sits exactly `RAIL_GUTTER + ROW_GUTTER + 10px` from
|
|
14
|
+
* the rail's left edge - 32px, which is also `RAIL_COLLAPSED / 2`. So the
|
|
15
|
+
* collapsed rail centres every icon *without a single centring rule*, and
|
|
16
|
+
* nothing moves horizontally while the width animates. Change either width
|
|
17
|
+
* and that identity breaks: the icons drift sideways during the transition,
|
|
18
|
+
* which is the exact stutter this geometry exists to avoid.
|
|
19
|
+
*/
|
|
20
|
+
export declare const RAIL_COLLAPSED = 64;
|
|
21
|
+
export declare const RAIL_EXPANDED = 264;
|
|
22
|
+
/** Horizontal padding inside the rail, on every region. Tailwind `px-3`. */
|
|
23
|
+
export declare const RAIL_GUTTER = 12;
|
|
24
|
+
/**
|
|
25
|
+
* The row shape every sidebar control shares - nav items, the workspace tile,
|
|
26
|
+
* the launcher, the user button.
|
|
27
|
+
*
|
|
28
|
+
* `overflow-hidden` + `whitespace-nowrap` is what makes the collapse smooth:
|
|
29
|
+
* the label is *clipped* by the shrinking rail rather than re-wrapped or
|
|
30
|
+
* re-measured, so a width animation costs no reflow. Fading the label with
|
|
31
|
+
* `SidebarLabel` on top of that hides the clip itself.
|
|
32
|
+
*/
|
|
33
|
+
export declare const SIDEBAR_ROW = "group/row relative flex h-10 w-full shrink-0 items-center justify-start gap-3 overflow-hidden whitespace-nowrap rounded-lg pe-2 text-sm font-normal transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus";
|
|
34
|
+
/**
|
|
35
|
+
* Leading inset for a row whose glyph is 20px wide (a nav icon, the launcher).
|
|
36
|
+
* `10 + 10 = 20`, and `RAIL_GUTTER + 20 = 32`. See `RAIL_COLLAPSED`.
|
|
37
|
+
*/
|
|
38
|
+
export declare const SIDEBAR_ROW_ICON = "ps-[10px]";
|
|
39
|
+
/**
|
|
40
|
+
* Leading inset for a row whose glyph is 32px wide (the avatar, the workspace
|
|
41
|
+
* tile). `4 + 16 = 20`, landing on the same 32px centre as `SIDEBAR_ROW_ICON`.
|
|
42
|
+
*/
|
|
43
|
+
export declare const SIDEBAR_ROW_TILE = "ps-[4px]";
|
|
44
|
+
/**
|
|
45
|
+
* The class list for one sidebar row, in one place.
|
|
46
|
+
*
|
|
47
|
+
* Three different elements need it - a plain `<button>` (`ConnectSidebarRow`),
|
|
48
|
+
* a rendered link (`ConnectSidebarNav`), and a HeroUI `<Button>` acting as a
|
|
49
|
+
* `Modal`/`Dropdown` trigger (the account row, the launcher, the workspace
|
|
50
|
+
* tile). They cannot share a component, because a React Aria overlay has to
|
|
51
|
+
* own its own trigger element - so they share this instead. A second copy of
|
|
52
|
+
* the string is a row that drifts off the 32px centre and takes the collapse
|
|
53
|
+
* animation's smoothness with it.
|
|
54
|
+
*
|
|
55
|
+
* On the HeroUI trigger: these are all Tailwind *utilities*, and HeroUI's
|
|
56
|
+
* `.button` is a component class, so the utility layer wins - which is what
|
|
57
|
+
* lets a `w-fit`, centred, `px-`-padded button take this shape at all.
|
|
58
|
+
*/
|
|
59
|
+
export declare function sidebarRowClass(options?: Readonly<{
|
|
60
|
+
/** The glyph is 32px (an avatar, a workspace tile) rather than 20px. */
|
|
61
|
+
tile?: boolean;
|
|
62
|
+
/** Paint the active treatment. */
|
|
63
|
+
active?: boolean;
|
|
64
|
+
className?: string;
|
|
65
|
+
}>): string;
|
|
66
|
+
export interface ConnectShellContextValue {
|
|
67
|
+
/** Icon-only rail. Always `false` inside the mobile drawer - see `AppShell`. */
|
|
68
|
+
collapsed: boolean;
|
|
69
|
+
/** Whether a collapse control should be offered at all. */
|
|
70
|
+
collapsible: boolean;
|
|
71
|
+
setCollapsed: (collapsed: boolean) => void;
|
|
72
|
+
renderLink: ConnectLinkRenderer;
|
|
73
|
+
/** The host router's current path, if it supplied one. */
|
|
74
|
+
activePath?: string;
|
|
75
|
+
/** Called after any sidebar link is pressed - the mobile drawer closes itself with this. */
|
|
76
|
+
onNavigate?: () => void;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Shared state for every part of the shell, so `ConnectSidebarNav`,
|
|
80
|
+
* `ConnectWorkspaceSwitcher` and `ConnectUserButton` all know whether the rail
|
|
81
|
+
* is collapsed without the host threading a prop through three layers.
|
|
82
|
+
*
|
|
83
|
+
* This is the piece that makes the shell *composable* rather than only
|
|
84
|
+
* configurable: the parts are exported and can be rearranged, and they still
|
|
85
|
+
* agree about collapse, routing and the mobile drawer because they read one
|
|
86
|
+
* context instead of one another's props.
|
|
87
|
+
*/
|
|
88
|
+
export declare function ConnectShellProvider({ value, children, }: Readonly<{
|
|
89
|
+
value: ConnectShellContextValue;
|
|
90
|
+
children: ReactNode;
|
|
91
|
+
}>): import("react").JSX.Element;
|
|
92
|
+
/**
|
|
93
|
+
* The shell state a sidebar part is rendering inside.
|
|
94
|
+
*
|
|
95
|
+
* Falls back to "expanded, not collapsible, plain anchors" rather than
|
|
96
|
+
* throwing, because every part is also exported for use *outside* a shell -
|
|
97
|
+
* a host dropping `ConnectSidebarNav` into a layout it already owns should
|
|
98
|
+
* not have to mount a provider to get a nav column.
|
|
99
|
+
*/
|
|
100
|
+
export declare function useConnectShell(): ConnectShellContextValue;
|
|
101
|
+
/**
|
|
102
|
+
* A sidebar row's text, faded out as the rail collapses.
|
|
103
|
+
*
|
|
104
|
+
* Opacity only - never width, height or margin. The rail's own width
|
|
105
|
+
* animation already moves the clip edge past this text; animating the text's
|
|
106
|
+
* box as well would make two things fight over the same pixels and is what
|
|
107
|
+
* makes a collapsing sidebar look like it stutters.
|
|
108
|
+
*
|
|
109
|
+
* Asymmetric timing on purpose. Collapsing, the label leaves *first* (no
|
|
110
|
+
* delay, quick) so the rail never appears to squeeze text; expanding, it
|
|
111
|
+
* arrives *after* the rail has opened enough to hold it.
|
|
112
|
+
*/
|
|
113
|
+
export declare function SidebarLabel({ children, className, }: Readonly<{
|
|
114
|
+
children: ReactNode;
|
|
115
|
+
className?: string;
|
|
116
|
+
}>): import("react").JSX.Element;
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
+
import { defaultRenderLink } from "./shell-context.js";
|
|
1
2
|
import { type ConnectLinkRenderer, type ConnectNav } from "./nav.js";
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
export interface ConnectSideNavProps {
|
|
3
|
+
export { defaultRenderLink };
|
|
4
|
+
export interface ConnectSidebarNavProps {
|
|
5
5
|
/** Items, sections, or a mix - see `ConnectNav`. */
|
|
6
6
|
nav: ConnectNav;
|
|
7
7
|
/**
|
|
8
|
-
* The current path. Pass your router's own (`usePathname()` in Next)
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* never has to do.
|
|
8
|
+
* The current path. Pass your router's own (`usePathname()` in Next).
|
|
9
|
+
* Inherited from `AppShell` when omitted; without either, the nav
|
|
10
|
+
* reads `window.location` and patches `history` to hear about client-side
|
|
11
|
+
* navigations - which works, but is guesswork the router never has to do.
|
|
12
|
+
* See `useActivePath`.
|
|
12
13
|
*/
|
|
13
14
|
activePath?: string;
|
|
14
|
-
/** See `ConnectLinkRenderer`.
|
|
15
|
+
/** See `ConnectLinkRenderer`. Inherited from the shell; defaults to a plain `<a>`. */
|
|
15
16
|
renderLink?: ConnectLinkRenderer;
|
|
16
|
-
/** Icon-only rail.
|
|
17
|
+
/** Icon-only rail. Inherited from the shell when omitted. */
|
|
17
18
|
collapsed?: boolean;
|
|
18
19
|
/** Called after any nav link is pressed - the mobile drawer closes itself with this. */
|
|
19
20
|
onNavigate?: () => void;
|
|
@@ -24,8 +25,21 @@ export interface ConnectSideNavProps {
|
|
|
24
25
|
* children, and the active highlight.
|
|
25
26
|
*
|
|
26
27
|
* `AppShell` renders this inside its rail and its mobile drawer, and it
|
|
27
|
-
* is exported for a host that wants the shell's navigation without its
|
|
28
|
-
*
|
|
29
|
-
*
|
|
28
|
+
* is exported for a host that wants the shell's navigation without its chrome:
|
|
29
|
+
* the same items, the same active resolution, dropped into a layout you
|
|
30
|
+
* already have.
|
|
31
|
+
*
|
|
32
|
+
* Every prop is optional except `nav`, because inside a shell they are all
|
|
33
|
+
* inherited from it. Passing one wins over what the shell says - which is how
|
|
34
|
+
* a second nav column (see `secondaryNav`) can share the rail's collapse state
|
|
35
|
+
* while keeping its own items.
|
|
36
|
+
*/
|
|
37
|
+
export declare function ConnectSidebarNav({ nav, activePath, renderLink, collapsed, onNavigate, className, }: ConnectSidebarNavProps): import("react").JSX.Element;
|
|
38
|
+
/**
|
|
39
|
+
* @deprecated Renamed to `ConnectSidebarNav` in 0.12 - the rail is a
|
|
40
|
+
* `ConnectSidebar` now, and its pieces are named after it. Identical
|
|
41
|
+
* behaviour; this alias will be removed in a later minor.
|
|
30
42
|
*/
|
|
31
|
-
export declare
|
|
43
|
+
export declare const ConnectSideNav: typeof ConnectSidebarNav;
|
|
44
|
+
/** @deprecated Renamed to `ConnectSidebarNavProps`. */
|
|
45
|
+
export type ConnectSideNavProps = ConnectSidebarNavProps;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
2
|
+
export interface ConnectSidebarProps {
|
|
3
|
+
/**
|
|
4
|
+
* The rail's contents, top to bottom. `AppShell` composes the default
|
|
5
|
+
* set; pass your own to rearrange them.
|
|
6
|
+
*/
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
/** Accessible name for the `<aside>`. Defaults to `"Sidebar"`. */
|
|
9
|
+
label?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The application rail: a fixed-width column that animates between an
|
|
14
|
+
* icon-only 64px and a labelled 264px.
|
|
15
|
+
*
|
|
16
|
+
* **Why width, and nothing else, animates.** Every row inside puts its glyph
|
|
17
|
+
* on the same 32px centre in both states (see `RAIL_COLLAPSED`), and every
|
|
18
|
+
* label is clipped rather than re-measured (see `SIDEBAR_ROW`). So the only
|
|
19
|
+
* property in flight is this element's width: no child moves, no text
|
|
20
|
+
* re-wraps, and there is no per-frame layout pass on the rows. That is why the
|
|
21
|
+
* collapse looks smooth rather than merely fast.
|
|
22
|
+
*
|
|
23
|
+
* Hidden below `md`. The mobile drawer renders the same children with
|
|
24
|
+
* `collapsed: false`, because a 64px icon rail on a phone is a worse drawer,
|
|
25
|
+
* not a smaller one.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ConnectSidebar({ children, label, className }: ConnectSidebarProps): import("react").JSX.Element;
|
|
28
|
+
export interface ConnectSidebarHeaderProps {
|
|
29
|
+
/** This application's name, in the `cosmo·ops VOICE` lockup. See `ConnectLogo`. */
|
|
30
|
+
name: string;
|
|
31
|
+
/** This application's glyph, drawn on the CosmoOps badge. */
|
|
32
|
+
icon?: ReactNode;
|
|
33
|
+
/** Where the lockup links when the rail is expanded. Defaults to `/`. */
|
|
34
|
+
homeHref?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The brand row, and the rail's own expand/collapse control.
|
|
38
|
+
*
|
|
39
|
+
* **Two states, one DOM.** The badge is mounted once and never re-created; the
|
|
40
|
+
* wordmark fades beside it and the collapse button fades at the trailing edge.
|
|
41
|
+
* Swapping which *element* renders the brand would remount it halfway through
|
|
42
|
+
* the width animation and flicker.
|
|
43
|
+
*
|
|
44
|
+
* Collapsed, hovering or focusing the badge swaps it for the expand glyph, so
|
|
45
|
+
* the rail needs no permanent control eating a row. Expanded, the control sits
|
|
46
|
+
* at the header's trailing edge, where it can be aimed at without covering the
|
|
47
|
+
* brand. The swap is pure CSS on a `group` - hovering re-renders nothing,
|
|
48
|
+
* which is what keeps it instant.
|
|
49
|
+
*
|
|
50
|
+
* The trade this makes, deliberately: **collapsed, the lockup is no longer a
|
|
51
|
+
* link home.** It has become the expand control, and one target that navigates
|
|
52
|
+
* on click but expands on click-after-hover would be worse than either. Put
|
|
53
|
+
* home in the nav; every application already does.
|
|
54
|
+
*/
|
|
55
|
+
export declare function ConnectSidebarHeader({ name, icon, homeHref }: ConnectSidebarHeaderProps): import("react").JSX.Element;
|
|
56
|
+
/**
|
|
57
|
+
* The rail's scrolling region, for the primary navigation. Everything else in
|
|
58
|
+
* the sidebar is `shrink-0`, so this is the only part that ever gives way.
|
|
59
|
+
*/
|
|
60
|
+
export declare function ConnectSidebarBody({ children }: Readonly<{
|
|
61
|
+
children: ReactNode;
|
|
62
|
+
}>): import("react").JSX.Element;
|
|
63
|
+
/**
|
|
64
|
+
* A pinned region at the foot of the rail - the secondary nav, the launcher,
|
|
65
|
+
* the account row.
|
|
66
|
+
*
|
|
67
|
+
* `separated` draws the hairline above it. The account row wants one; a
|
|
68
|
+
* secondary nav sitting directly on top of the account row does not, or the
|
|
69
|
+
* rail ends in two rules a few pixels apart.
|
|
70
|
+
*/
|
|
71
|
+
export declare function ConnectSidebarFooter({ children, separated, }: Readonly<{
|
|
72
|
+
children: ReactNode;
|
|
73
|
+
separated?: boolean;
|
|
74
|
+
}>): import("react").JSX.Element;
|
|
75
|
+
export type ConnectSidebarRowProps = Readonly<{
|
|
76
|
+
/** The glyph. 20px by default; 32px when `tile`. */
|
|
77
|
+
icon: ReactNode;
|
|
78
|
+
/** The row's text, and - when it is a string - its accessible name. */
|
|
79
|
+
label: ReactNode;
|
|
80
|
+
/** Overrides the accessible name. Required when `label` is not a string. */
|
|
81
|
+
"aria-label"?: string;
|
|
82
|
+
/** The glyph is 32px (an avatar, a workspace tile) rather than 20px. */
|
|
83
|
+
tile?: boolean;
|
|
84
|
+
/** Trailing content, e.g. a chevron. Clipped with the label while collapsed. */
|
|
85
|
+
trailing?: ReactNode;
|
|
86
|
+
}> & Omit<ComponentPropsWithoutRef<"button">, "aria-label">;
|
|
87
|
+
/**
|
|
88
|
+
* A pressable row in the rail that is not a nav item - the launcher, the
|
|
89
|
+
* account button, anything a host adds to the footer.
|
|
90
|
+
*
|
|
91
|
+
* Exported so a host's own row lines up with the SDK's. It applies the same
|
|
92
|
+
* 32px glyph centre and the same label fade, which is what stops a partner's
|
|
93
|
+
* "Help" row drifting sideways while every row above it holds still.
|
|
94
|
+
*/
|
|
95
|
+
export declare function ConnectSidebarRow({ icon, label, tile, trailing, className, "aria-label": ariaLabel, ...props }: ConnectSidebarRowProps): import("react").JSX.Element;
|