UNPKG

sanity

Version:

Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches

1,443 lines 609 kB
import * as react from "react"; import { CSSProperties, Component, ComponentProps, ComponentType, Dispatch, ElementType, ErrorInfo, FC, FocusEvent, FocusEventHandler, FormEvent, FormEventHandler, HTMLAttributes, HTMLProps, KeyboardEvent, MutableRefObject, PropsWithChildren, PureComponent, ReactElement, ReactNode, Ref, RefAttributes, RefObject, SVGProps, SetStateAction } from "react"; import * as _sanity_types0 from "@sanity/types"; import { ArraySchemaType, AssetMetadataType, AssetSource, AssetSourceSpec, BlockDecoratorDefinition, BlockListDefinition, BlockStyleDefinition, BooleanSchemaType, ConditionalProperty, CrossDatasetReferenceSchemaType, CrossDatasetReferenceValue, CrossDatasetType, CurrentUser, DeprecatedProperty, FieldGroup, File as File$1, FileAsset, FileSchemaType, FileValue, FormNodeValidation, GeopointValue, GlobalDocumentReferenceType, I18nTextRecord, Image, ImageAsset, ImageSchemaType, ImageUrlFitMode, ImageValue, IndexTuple, InitialValueProperty, InitialValueResolverContext, IntrinsicTypeName, KeyedObject, KeyedSegment, MendozaEffectPair, NumberSchemaType, ObjectField, ObjectFieldType, ObjectSchemaType, PatchOperations, Path, PathSegment, PortableTextBlock, PortableTextObject, PortableTextTextBlock, PrepareViewOptions, PreviewValue, Reference, ReferenceSchemaType, ReferenceValue, Role, RuleClass, SanityDocument, SanityDocumentLike, Schema, SchemaType, SchemaTypeDefinition, SearchStrategy, SlugSchemaType, SlugValue, SortOrdering, StrictVersionLayeringOptions, StringSchemaType, TextSchemaType, TransactionLogEventWithEffects, TransactionLogEventWithMutations, UploadState, User, ValidationMarker } from "@sanity/types"; import { BifurClient } from "@sanity/bifur-client"; import * as _sanity_client0 from "@sanity/client"; import { ClientConfig, ClientPerspective, QueryParams, ReconnectEvent, ReleaseDocument, ReleaseDocument as ReleaseDocument$1, ReleaseType, ResetEvent, SanityClient, SanityDocument as SanityDocument$1, SingleActionResult, SingleMutationResult, StackablePerspective, WelcomeBackEvent, WelcomeEvent } from "@sanity/client"; import * as _sanity_ui0 from "@sanity/ui"; import { AvatarPosition, AvatarProps, AvatarSize, AvatarStatus, BadgeProps, BadgeTone, BoxProps, ButtonProps, ButtonTone, CardProps, DialogProps, HotkeysProps, MenuButtonProps, MenuItem, Placement, PopoverProps, ResponsivePaddingProps, ResponsiveWidthProps, Text, TextProps, ThemeColorSchemeKey, ToastParams, TooltipProps } from "@sanity/ui"; import { FlatNamespace, KeyPrefix, Namespace, TFunction, TFunction as TFunction$1, i18n as i18n$1 } from "i18next"; import { MonoTypeOperatorFunction, Observable, OperatorFunction, Subject } from "rxjs"; import { IntentLinkProps, IntentParameters, Router, RouterState, SearchParam } from "sanity/router"; import { ScrollToOptions } from "@tanstack/react-virtual"; import * as _sanity_telemetry0 from "@sanity/telemetry"; import { DRAFTS_FOLDER, DraftId, PublishedId, VERSION_FOLDER, getDraftId, getPublishedId, getVersionFromId, getVersionId, isDraftId, isPublishedId, isVersionId } from "@sanity/client/csm"; import * as sanity__singletons0 from "sanity/_singletons"; import { DocumentDivergencesContextValue, DocumentLimitUpsellContextValue, FieldActionsContextValue, HoveredFieldContextValue, LocaleContextValue, SchedulesContext, SingleDocReleaseContextValue } from "sanity/_singletons"; import { Mutation } from "@sanity/mutator"; import { CanvasResource, FrameMessages, MediaResource, StudioResource, WindowMessages } from "@sanity/message-protocol"; import { DocumentHandle } from "@sanity/sdk"; import { FallbackNs } from "react-i18next"; import { BrowserHistory, HashHistory, History, MemoryHistory } from "history"; import { RootTheme, ThemeColorSchemeKey as ThemeColorSchemeKey$1 } from "@sanity/ui/theme"; import { EditorSelection, HotkeyOptions, InvalidValueResolution, OnCopyFn, OnPasteResultOrPromise, PasteData, Patch, PortableTextEditor, RangeDecoration, RangeDecorationOnMovedDetails, RenderBlockFunction } from "@portabletext/editor"; import { ColorHueKey, ColorTintKey, ColorTints } from "@sanity/color"; import { Subscriber } from "nano-pubsub"; import { ArrayDiff, BooleanDiff, Diff, ItemDiff, NullDiff, NumberDiff, ObjectDiff, StringDiff, StringSegmentChanged, StringSegmentUnchanged, TypeChangeDiff } from "@sanity/diff"; import * as styled_components0 from "styled-components"; import { CSSProperties as CSSProperties$1, ExecutionProps } from "styled-components"; import * as date_fns_formatRelative0 from "date-fns/formatRelative"; import { ResizeObserverEntry } from "@juggle/resize-observer"; import { ThrottleSettings } from "lodash-es/throttle.js"; import { DEFAULT_ANNOTATIONS, DEFAULT_DECORATORS } from "@sanity/schema"; import * as styled_components_dist_types0 from "/home/runner/work/sanity/sanity/node_modules/.pnpm/@sanity+styled-components@6.1.24_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/@sanity/styled-components/dist/types.js"; import { PortableTextMemberSchemaTypes } from "@portabletext/sanity-bridge"; import { ImageUrlBuilder, ImageUrlBuilder as ImageUrlBuilder$1 } from "@sanity/image-url"; import { MarkdownShortcutsPluginProps } from "@portabletext/plugin-markdown-shortcuts"; import { PasteLinkPluginProps } from "@portabletext/plugin-paste-link"; import { TypographyPluginProps } from "@portabletext/plugin-typography"; import { Node } from "@sanity/comlink"; interface CreateSanityMediaLibrarySourceProps { i18nKey?: string; icon?: React.ComponentType; libraryId: string | null; name?: string; } /** * Create a new image asset source for the Media Library * * @beta */ declare function createSanityMediaLibraryImageSource(props: CreateSanityMediaLibrarySourceProps): AssetSource; /** * Create a new file asset source for the Media Library * * @beta */ declare function createSanityMediaLibraryFileSource(props: CreateSanityMediaLibrarySourceProps): AssetSource; interface SharedProps$1 { children?: ReactNode; header: string; width: ResponsiveWidthProps['width']; } interface DialogProps$2 extends SharedProps$1 { type: 'dialog'; id?: string; autofocus?: boolean; onClose?: () => void; } interface PopoverProps$3 extends SharedProps$1 { type: 'popover'; legacy_referenceElement: HTMLElement | null; onClose: () => void; } /** * @beta * Creates a dialog or a popover for editing content. * Handles presence and virtual scrolling. */ declare function EditPortal(props: PopoverProps$3 | DialogProps$2): React.JSX.Element; interface SharedProps { children?: ReactNode; header: string; width: ResponsiveWidthProps['width']; } interface DialogProps$1 extends SharedProps { type: 'dialog'; id?: string; autofocus?: boolean; onClose?: () => void; } interface PopoverProps$2 extends SharedProps { type: 'popover'; id?: string; legacy_referenceElement: HTMLElement | null; onClose: () => void; } /** * @beta * Creates a dialog or a popover for editing content. * Handles presence and virtual scrolling. * * When multiple dialogs are open, only the top-most dialog is visible. * Non-top dialogs are hidden via CSS while preserving their state. */ declare function EnhancedObjectDialog(props: PopoverProps$2 | DialogProps$1): React.JSX.Element; type JsonObject = { [Key in string]: KeyValueStoreValue } & { [Key in string]?: KeyValueStoreValue | undefined }; type JsonArray = KeyValueStoreValue[] | readonly KeyValueStoreValue[]; type JsonPrimitive = string | number | boolean | null; /** @internal */ type KeyValueStoreValue = JsonPrimitive | JsonObject | JsonArray; /** @internal */ interface KeyValueStore { getKey(key: string): Observable<KeyValueStoreValue | null>; setKey(key: string, value: KeyValueStoreValue): Promise<KeyValueStoreValue>; } /** @internal */ declare function createKeyValueStore(options: { client: SanityClient; }): KeyValueStore; /** * The interface used by the Studio that produces a `SanityClient` and * `CurrentUser` that gets passed to the resulting `Workspace`s and `Source`s. * * NOTE: This interface is primarily for internal use. Refer to * `createAuthStore` instead. * * @beta * @hidden */ interface AuthStore { /** * Emits `AuthState`s. This should update when the user's auth state changes. * E.g. After a login, a new `AuthState` could be emitted with a non-null * `currentUser` and `authenticated: true` * * NOTE: all auth store implementations should emit on subscribe using * something like shareReplay(1) to ensure all new subscribers get an * `AuthState` value on subscribe */ state: Observable<AuthState>; /** * Emits auth tokens, or `null` if not configured to use them or they do not exist */ token?: Observable<string | null>; /** * Custom auth stores are expected to implement a UI that initiates the user's * authentication. For the typical case in `createAuthStore`, this means * loading the providers and showing them as options to the user. */ LoginComponent?: ComponentType<LoginComponentProps>; /** * Custom auth stores can implement a function that runs when the user logs * out. The implementation is expected to remove all credentials both locally * and on the server. */ logout?: () => void; /** * Custom auth stores can implement a function that is designated to run when * the Studio loads (e.g. to trade a session ID for a token in cookie-less * mode). Within the Studio, this is called within the `AuthBoundary`. */ handleCallbackUrl?: () => Promise<HandleCallbackResult>; } /** * The unit an `AuthStore` emits to determine the user's authentication state. * * @beta * @hidden */ interface AuthState { /** * Similar to a logged-in flag. This state is used in places like the * `AuthBoundary` to determine whether or not it should render the * `NotAuthenticatedComponent`. Implementers may choose to set this to `true` * while also also emitting a `currentUser` of `null` if a `null` user is * accepted (e.g. a project that doesn't require a login) */ authenticated: boolean; /** * The value of the user logged in or `null` if none is provided */ currentUser: CurrentUser | null; /** * A client that is expected to be pre-configured to allow for any downstream * requests in the Studio */ client: SanityClient; } /** * @beta * @hidden */ type LoginComponentProps = { projectId: string; /** @deprecated use redirectPath instead */ basePath: string; redirectPath?: string; } | { projectId: string; redirectPath: string; /** @deprecated use redirectPath instead */ basePath?: string; }; /** * Result returned from `handleCallbackUrl` describing what happened during * the auth callback flow. Used for telemetry and diagnostics. * * @internal */ interface HandleCallbackResult { /** The login method configured for this auth store (e.g. `'cookie'` or `'token'`). */ loginMethod: LoginMethod; /** * Which auth flow was taken: * - `'already-authenticated'`: User was already authenticated; no exchange needed. * - `'cookie-auth'`: Attempted cookie-based authentication via `/users/me`. * - `'token-exchange'`: Traded a session ID for a persistent token. */ flow: 'already-authenticated' | 'cookie-auth' | 'token-exchange'; /** Whether the auth flow completed successfully. */ success: boolean; /** Total wall-clock time for the callback handling, in milliseconds. */ durationMs: number; /** Time spent on the session-to-token exchange specifically. Only set for `'token-exchange'` flow. */ tokenExchangeDurationMs?: number; /** Human-readable reason for failure. Only set when `success` is `false`. */ failureReason?: string; } /** @internal */ interface AuthStoreOptions extends AuthConfig { clientFactory?: (options: ClientConfig) => SanityClient; projectId: string; dataset: string; } /** * @internal */ declare function _createAuthStore({ clientFactory: clientFactoryOption, projectId, dataset, apiHost, loginMethod, ...providerOptions }: AuthStoreOptions): AuthStore; /** * @internal */ declare const createAuthStore: typeof _createAuthStore; /** @internal */ interface MockAuthStoreOptions { currentUser: CurrentUser | null; client: SanityClient; } /** * Creates a mock `AuthStore` (for testing) that emits an `AuthState` derived * from the `client` and `currentUser` given. * * @internal */ declare function createMockAuthStore({ client, currentUser }: MockAuthStoreOptions): AuthStore; /** @internal */ declare function getProviderTitle(provider?: string): string | undefined; /** * Duck-type check for whether or not this looks like an auth store * * @param maybeStore - Item to check if matches the AuthStore interface * @returns True if auth store, false otherwise * @internal */ declare function isAuthStore(maybeStore: unknown): maybeStore is AuthStore; /** * Check whether the provided login method is compatible with cookieless auth, e.g. whether any * authentication token found in localStorage should be acknowledged. * * @internal */ declare function isCookielessCompatibleLoginMethod(loginMethod: LoginMethod): loginMethod is CookielessCompatibleLoginMethod; /** @internal */ interface ConnectionStatusStore { connectionStatus$: Observable<ConnectionStatus>; } /** @internal */ type ConnectingStatus = { type: 'connecting'; }; /** @internal */ type ErrorStatus = { type: 'error'; error: Error; attemptNo: number; isOffline: boolean; retryAt: Date; }; /** @internal */ type RetryingStatus = { type: 'retrying'; }; /** @internal */ type ConnectedStatus = { type: 'connected'; lastHeartbeat: Date; }; /** @internal */ declare const CONNECTING: ConnectingStatus; /** @internal */ type ConnectionStatus = ConnectingStatus | ErrorStatus | ConnectedStatus | RetryingStatus; /** @internal */ declare const onRetry: () => void; /** @internal */ interface ConnectionStatusStoreOptions { bifur: BifurClient; } /** * This is the beginning of what should be the data store tracking connection status in the Sanity studio. * * @internal */ declare function createConnectionStatusStore({ bifur }: ConnectionStatusStoreOptions): ConnectionStatusStore; /** @internal */ interface CorsOriginErrorOptions { projectId?: string; isStaging: boolean; } /** @internal */ declare class CorsOriginError extends Error { projectId?: string; isStaging: boolean; constructor({ projectId, isStaging }: CorsOriginErrorOptions); } /** @internal */ type BetaBadgeProps = Omit<BadgeProps, 'mode' | 'tone'>; /** @internal */ declare function BetaBadge(props: BetaBadgeProps & Omit<HTMLProps<HTMLDivElement>, 'ref'>): react.JSX.Element; /** @internal */ type CommandListElementType = 'input' | 'list'; /** @internal */ type CommandListGetItemDisabledCallback = (virtualIndex: number) => boolean; /** @internal */ type CommandListGetItemKeyCallback = (virtualIndex: number) => number | string; /** @internal */ type CommandListGetItemSelectedCallback = (virtualIndex: number) => boolean; /** @internal */ type CommandListItemContext = { activeIndex: number | null; disabled?: boolean; selected?: boolean; virtualIndex: number; }; /** @internal */ type CommandListRenderItemCallback<T> = (item: T, context: CommandListItemContext) => ReactNode; /** @internal */ interface CommandListHandle { focusInputElement: () => void; focusListElement: () => void; getTopIndex: () => number; scrollToIndex: (index: number) => void; } /** @internal */ interface CommandListProps<T = any> extends ResponsivePaddingProps { /** The data attribute to apply to any active virtual list items */ activeItemDataAttr?: string; /** `aria-label` to apply to the virtual list container element */ ariaLabel: string; /** Whether `aria-multiselectable` is enabled on the virtual list container element */ ariaMultiselectable?: boolean; /** Automatically focus the input or virtual list */ autoFocus?: CommandListElementType; /** Whether the virtual list can receive focus */ canReceiveFocus?: boolean; /** Pixel offset of the virtual list focus ring. Negative values will cause the focus ring to appear inset */ focusRingOffset?: number; /** Force a fixed height for all virtual list children and skip measurement (faster). */ fixedHeight?: boolean; /** Custom function to map disabled items */ getItemDisabled?: CommandListGetItemDisabledCallback; /** Custom function to map virtual list items to custom keys */ getItemKey?: CommandListGetItemKeyCallback; /** Custom function to map selected items */ getItemSelected?: CommandListGetItemSelectedCallback; /** Scroll alignment of the initial active index */ initialScrollAlign?: ScrollToOptions['align']; /** Initial active index on mount */ initialIndex?: number; /** Input element to associate with this virtual list. Associated inputs will receive focus and handle key events */ inputElement?: HTMLInputElement | null; /** Estimated height for each list item */ itemHeight: number; /** Virtual list item values, accessible to all rendered item components */ items: T[]; /** Callback fired when the virtual list is within `onEndReachedIndexThreshold` of rendered content */ onEndReached?: () => void; /** Number of items from the end of the virtual list before which `onEndReached` is triggered */ onEndReachedIndexOffset?: number; /** Only show selection state when the virtual list is active (is hovered or has focus) */ onlyShowSelectionWhenActive?: boolean; /** Number of items to render above and below the visible area*/ overscan?: number; /** Rendered component in virtual lists */ renderItem: CommandListRenderItemCallback<T>; /** `data-testid` to apply to outermost container */ testId?: string; /** Allow wraparound keyboard navigation between first and last items */ wrapAround?: boolean; } /** * Renders a Command List with support for the following: * * - Keyboard navigation (↑ / ↓ / ENTER) to children with a specified container (`childContainerRef`) * - Focus redirection when clicking child elements * - Pointer blocking when navigating with arrow keys (to ensure that only one active state is visible at any given time) * - ARIA attributes to define a `combobox` input that controls a separate `listbox` * * @internal */ declare const CommandList: react.NamedExoticComponent<CommandListProps<any> & react.RefAttributes<CommandListHandle>>; type BaseButtonProps = Pick<ButtonProps, 'as' | 'icon' | 'iconRight' | 'justify' | 'loading' | 'mode' | 'paddingY' | 'paddingLeft' | 'selected' | 'tone' | 'type' | 'width'> & { size?: 'default' | 'large'; radius?: 'full'; }; type ButtonWithText = { text: string; tooltipProps?: TooltipProps$1 | null; icon?: ButtonProps['icon']; }; type IconButton = { text?: undefined; icon?: ButtonProps['icon']; /** * When using a button with an icon, tooltipProps are required to enforce consistency in UI. */ tooltipProps: TooltipProps$1 | null; }; /** @internal */ type ButtonProps$1 = BaseButtonProps & (ButtonWithText | IconButton); /** * Customized Sanity UI <Button> with pre-defined layout options. * * @internal */ declare const Button: react.ForwardRefExoticComponent<(Omit<Pick<ButtonProps, "as" | "icon" | "iconRight" | "justify" | "loading" | "mode" | "paddingLeft" | "paddingY" | "selected" | "tone" | "type" | "width"> & { size?: "default" | "large" | undefined; radius?: "full" | undefined; } & ButtonWithText & Omit<HTMLProps<HTMLButtonElement>, "as" | "size" | "title">, "ref"> | Omit<Pick<ButtonProps, "as" | "icon" | "iconRight" | "justify" | "loading" | "mode" | "paddingLeft" | "paddingY" | "selected" | "tone" | "type" | "width"> & { size?: "default" | "large" | undefined; radius?: "full" | undefined; } & IconButton & Omit<HTMLProps<HTMLButtonElement>, "as" | "size" | "title">, "ref">) & react.RefAttributes<HTMLButtonElement>>; /** @internal */ type MenuButtonProps$1 = Omit<MenuButtonProps, 'popover'> & { popover?: Omit<PopoverProps, 'animate' | 'content' | 'open'>; }; /** @internal */ type TooltipProps$1 = Omit<TooltipProps, 'arrow' | 'padding' | 'shadow'> & { hotkeys?: HotkeysProps['keys']; }; /** @internal */ type PopoverProps$1 = PopoverProps; type ContextMenuButtonProps = Pick<ButtonProps$1, 'mode' | 'selected' | 'size' | 'tone' | 'tooltipProps' | 'loading'>; /** * Simple context menu button (with horizontal ellipsis icon) with shared localization. * * @internal */ declare const ContextMenuButton: react.ForwardRefExoticComponent<ContextMenuButtonProps & Pick<HTMLProps<HTMLButtonElement>, "disabled" | "hidden" | "onClick"> & react.RefAttributes<HTMLButtonElement>>; /** * Indicates the type of document variant, either `draft`, `version` or `published`. * Draft documents are prefixed with `drafts.`. * Version documents are prefixed with `versions.<versionName>` * The rest are considered published documents. * @public */ type DocumentVariantType = 'draft' | 'version' | 'published'; /** * Takes a document id and returns the variant type for that document * If it's a document that starts with `version.` it's a `version` document. * If it's a document that starts with `drafts.` it's a `draft` document. * Otherwise, it's a `published` document. * @public * */ declare function getDocumentVariantType(documentId: string): DocumentVariantType; /** * @internal */ declare const Chip: react.ForwardRefExoticComponent<Omit<Omit<_sanity_ui0.ButtonProps & Omit<react.HTMLProps<HTMLButtonElement>, "as" | "width">, "ref"> & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<unknown>>; /** * * Checks if the document ID `documentId` has the same ID as `equalsDocumentId`, * ignoring the draft prefix. * * @public * * @param documentId - The document ID to check * @param equalsDocumentId - The document ID to check against * * @example * Draft vs published document ID, but representing the same document: * ``` * // Prints "true": * console.log(documentIdEquals('drafts.agot', 'agot')); * ``` * @example * Different documents: * ``` * // Prints "false": * console.log(documentIdEquals('hp-tcos', 'hp-hbp')); * ``` * * @returns `true` if the document IDs are equal, `false` otherwise */ declare function documentIdEquals(documentId: string, equalsDocumentId: string): boolean; /** @internal */ declare function isDraft(document: SanityDocumentLike): boolean; /** * TODO: Improve return type based on presence of `version` option. * * @internal */ declare function getIdPair(id: string, { version }?: { version?: string; }): { draftId: DraftId; publishedId: PublishedId; versionId?: string; }; /** * System bundles are sets of documents owned by the system. * * - Draft documents contain data that has not yet been published. These documents all exist in the "drafts" path. * - Published documents contain data that has been published. These documents all exist in the root path. * * These differ to user bundles, which are created when a user establishes a custom set of documents * (e.g. by creating a release). * * @public */ declare const systemBundles: readonly ["drafts", "published"]; /** * System bundles are sets of documents owned by the system. * * - Draft documents contain data that has not yet been published. These documents all exist in the "drafts" path. * - Published documents contain data that has been published. These documents all exist in the root path. * * These differ to user bundles, which are created when a user establishes a custom set of documents * (e.g. by creating a release). * * @public */ type SystemBundle = 'drafts' | 'published'; /** @internal */ declare function isSystemBundle(maybeSystemBundle: unknown): maybeSystemBundle is SystemBundle; /** @internal */ type SystemBundleName = 'draft' | 'published'; /** * `isSystemBundle` should be preferred, but some parts of the codebase currently use the singular * "draft" name instead of the plural "drafts". * * @internal */ declare function isSystemBundleName(maybeSystemBundleName: unknown): maybeSystemBundleName is SystemBundleName; /** * @internal * Given a perspective stack and a document id, returns true if the document id matches any of the provided perspectives * e.g. `idMatchesPerspective('['summer'], 'versions.summer.foo') === true` * e.g. `idMatchesPerspective('['drafts', 'summer'], 'versions.summer.foo') === true` * e.g. `idMatchesPerspective('['drafts'], 'versions.summer.foo') === false` * e.g. `idMatchesPerspective('['drafts', 'summer'], 'versions.winter.foo') === false` * * Note: a published id will match any perspective * e.g. `idMatchesPerspective('['drafts', 'summer'], 'foo') === true` */ declare function idMatchesPerspective(perspectiveStack: StackablePerspective[], documentId: string): boolean; /** @internal */ declare function createDraftFrom(document: SanityDocument): SanityDocument; /** @internal */ declare function newDraftFrom(document: SanityDocument): SanityDocument; /** @internal */ declare function createPublishedFrom(document: SanityDocument): SanityDocument; /** * Takes a list of documents and collates draft/published pairs into single entries * `{id: <published id>, draft?: <draft document>, published?: <published document>}` * * Note: because Map is ordered by insertion key the resulting array will be ordered by whichever * version appeared first * * @internal */ interface CollatedHit<T extends { _id: string; } = { _id: string; }> { id: string; type: string; draft?: T; published?: T; versions: T[]; } /** @internal */ declare function collate<T extends { _id: string; _type: string; }>(documents: T[]): CollatedHit<T>[]; /** @internal */ declare function removeDupes(documents: SanityDocumentLike[]): SanityDocumentLike[]; /** * @beta */ type ReleaseId = string; /** * A value representing a perspective, including the data describing it. This is either the name of a * system bundle, or a document describing a release. * * @public */ type TargetPerspective = ReleaseDocument | SystemBundle | string; /** * @beta * @deprecated Use `TargetPerspective` instead. */ type SelectedPerspective = TargetPerspective; /** * @beta */ type PerspectiveStack = ExtractArray<ClientPerspective>; /** * @beta */ interface PerspectiveContextValue { selectedPerspectiveName: 'published' | ReleaseId | undefined; /** * The releaseId as `r<string>`; it will be undefined if the selected perspective is `published` or `drafts` */ selectedReleaseId: ReleaseId | undefined; selectedPerspective: TargetPerspective; /** * The stacked array of perspectives ids ordered chronologically to represent the state of documents at the given point in time. * It can be used as the perspective param in the client to get the correct view of the documents. * @returns ["published"] | ["drafts"] | ["releaseId2", "releaseId1", "drafts"] */ perspectiveStack: PerspectiveStack; excludedPerspectives: string[]; } /** * @internal */ type ExtractArray<Union> = Union extends unknown[] ? Union : never; /** * @internal */ type ReleasesNavMenuItemPropsGetter = (content: { perspective: TargetPerspective; }) => Partial<ComponentProps<typeof MenuItem>>; /** * @internal */ declare const VersionChip: react.NamedExoticComponent<{ disabled?: boolean | undefined; selected: boolean; tooltipContent?: ReactNode; onClick: () => void; text: string; contextMenuPortal?: boolean | undefined; tone: "caution" | "critical" | "default" | "neutral" | "positive" | "primary" | "suggest"; locked?: boolean | undefined; onCopyToDraftsNavigate: () => void; contextValues: { documentId: string; documentType: string; releases: ReleaseDocument[]; releasesLoading: boolean; bundleId: string; isVersion: boolean; disabled?: boolean | undefined; isGoingToUnpublish?: boolean | undefined; release?: ReleaseDocument | undefined; }; }>; /** @internal */ type ReleaseAvatarIconProps = { release: TargetPerspective; tone?: never; releaseType?: never; } | { releaseType: ReleaseType; tone?: never; release?: never; } | { /** * @deprecated - Prefer `release` or `releaseType`. */ tone: BadgeTone; release?: never; releaseType?: never; }; declare const ReleaseAvatarIcon: ({ tone, release, releaseType }: ReleaseAvatarIconProps) => react.JSX.Element; declare function ReleaseAvatar({ fontSize, padding, ...iconProps }: ReleaseAvatarIconProps & { fontSize?: number; padding?: number; }): React.JSX.Element; /** @internal */ interface ReleaseTitleDetails { displayTitle: string; fullTitle: string; isTruncated: boolean; } /** @internal */ interface ReleaseTitleProps { title: string | undefined; fallback: string; enableTooltip?: boolean; tooltipMaxWidth?: string; children?: (details: ReleaseTitleDetails) => ReactElement; textProps?: Omit<TextProps, 'children'> & { style?: CSSProperties; }; } /** @internal */ declare function ReleaseTitle(props: ReleaseTitleProps): ReactNode; /** * @internal */ declare const VersionInlineBadge: ({ children, $tone }: PropsWithChildren<{ $tone?: "caution" | "critical" | "default" | "neutral" | "positive" | "primary" | "suggest" | undefined; }>) => react.JSX.Element; /** * @internal */ declare const getVersionInlineBadge: (release?: TargetPerspective | undefined) => FC<{ children?: react.ReactNode; }>; interface ObserveDocumentAPIConfig { dataset?: string; projectId?: string; apiVersion?: string; } type DocumentIdSetObserverState = { status: 'reconnecting' | 'connected'; documentIds: string[]; }; /** @internal */ type Id = string; /** * @hidden * @beta */ type Previewable = ({ _id: string; } | { _type: string; } | { _system?: { delete: boolean; }; } | { _ref: string; _dataset?: string; _projectId?: string; }) & { /** * optional object used to attach meta data to the prepared result. * currently used to add a flag for the invalid preview error fallback and * insufficient permissions fallback * @internal */ _internalMeta?: { type?: string; }; }; /** * TODO: unify with content path from `@sanity/types` * * * @hidden * @beta */ type PreviewPath = FieldName[]; /** @internal */ type Selection = [id: Id, fields: FieldName[]]; /** * @hidden * @beta */ type FieldName = string; /** @internal */ interface AvailabilityResponse { omitted: { id: string; reason: 'existence' | 'permission'; }[]; } /** @internal */ type AvailabilityReason = 'READABLE' | 'PERMISSION_DENIED' | 'NOT_FOUND'; /** * @hidden * @beta */ type PreviewableType = SchemaType | CrossDatasetType | GlobalDocumentReferenceType; /** * @hidden * @beta */ interface ApiConfig { projectId: string; dataset: string; } /** * @hidden * @beta */ type DocumentAvailability = { available: true; reason: 'READABLE'; } | { available: false; reason: 'PERMISSION_DENIED' | 'NOT_FOUND' | 'VERSION_DELETED'; }; /** * @hidden * @beta */ interface DraftsModelDocumentAvailability { /** * document readability for the published document */ published: DocumentAvailability; /** * document readability for the draft document */ draft: DocumentAvailability; /** * document readability for the version document */ version?: DocumentAvailability; } /** * @hidden * @beta */ interface DocumentStackAvailability { /** * Document id */ id: string; /** * Availability for the document in this stack */ availability: DocumentAvailability; } /** * @hidden * @beta */ interface DraftsModelDocument<T extends SanityDocumentLike = SanityDocumentLike> { id: string; type: string | null; draft: { availability: DocumentAvailability; snapshot: T | undefined; }; published: { availability: DocumentAvailability; snapshot: T | undefined; }; version?: { availability: DocumentAvailability; snapshot: T | undefined; }; } /** * Event emitted to notify preview subscribers when they need to refetch a document being previewed * - 'connected' will happen when the store is connected to the invalidation channel, both initially and after a reconnect after a connection loss * - 'mutation' will happen when a document has been mutated and the store needs to refetch a document * @hidden * @beta */ type InvalidationChannelEvent = { type: 'connected'; } | { type: 'mutation'; documentId: string; visibility: string; }; /** * @hidden * @beta */ interface PreparedSnapshot { type?: PreviewableType; snapshot: PreviewValue | null | undefined; } /** @internal */ type ObserveDocumentTypeFromIdFn = (id: string, apiConfig?: ApiConfig, perspective?: StackablePerspective[]) => Observable<string | undefined>; /** * @hidden * @beta */ interface ObservePathsFn { (value: Previewable, paths: (string | PreviewPath)[], apiConfig?: ApiConfig, perspective?: StackablePerspective[]): Observable<PreviewValue | SanityDocumentLike | Reference | string | null>; } /** * @hidden * @beta */ interface ObserveDocumentAvailabilityFn { (id: string, options?: { version?: string; }): Observable<{ draft: DocumentAvailability; published: DocumentAvailability; version?: DocumentAvailability; }>; } /** * @hidden * @beta */ type ObserveForPreviewFn = (value: Previewable, type: PreviewableType, options?: { viewOptions?: PrepareViewOptions; perspective?: StackablePerspective[]; apiConfig?: ApiConfig; }) => Observable<PreparedSnapshot>; /** * The document preview store supports subscribing to content for previewing purposes. * Documents observed by this store will be kept in sync and receive real-time updates from all collaborators, * but has no support for optimistic updates, so any local edits will require a server round-trip before becoming visible, * which means this store is less suitable for real-time editing scenarios. * * @hidden * @beta */ interface DocumentPreviewStore { observePaths: ObservePathsFn; observeForPreview: ObserveForPreviewFn; observeDocumentTypeFromId: (id: string, apiConfig?: ApiConfig, perspective?: StackablePerspective[]) => Observable<string | undefined>; /** * * @hidden * @beta */ unstable_observeDocumentPairAvailability: (id: string, options?: { version?: string; }) => Observable<DraftsModelDocumentAvailability>; /** * * @hidden * @beta */ unstable_observeDocumentStackAvailability: (id: string, perspectiveStack: StackablePerspective[]) => Observable<DocumentStackAvailability[]>; unstable_observePathsDocumentPair: <T extends SanityDocument = SanityDocument>(id: string, paths: PreviewPath[], options?: { version?: string; }) => Observable<DraftsModelDocument<T>>; /** * Observes a set of document IDs that matches the given groq-filter. The document ids are returned in ascending order and will update in real-time * Whenever a document appears or disappears from the set, a new array with the updated set of IDs will be pushed to subscribers. * The query is performed once, initially, and thereafter the set of ids are patched based on the `appear` and `disappear` * transitions on the received listener events. * This provides a lightweight way of subscribing to a list of ids for simple cases where you just want to subscribe to a set of documents ids * that matches a particular filter. * @hidden * @beta * @param filter - A groq filter to use for the document set * @param params - Parameters to use with the groq filter * @param options - Options for the observer * @param apiVersion - Specify the API version to use for the query */ unstable_observeDocumentIdSet: (filter: string, params?: QueryParams, options?: { /** * Where to insert new items into the set. Defaults to 'sorted' which is based on the lexicographic order of the id */ insert?: 'sorted' | 'prepend' | 'append'; apiVersion?: string; }) => Observable<DocumentIdSetObserverState>; /** * Observe a complete document with the given ID * @hidden * @beta */ unstable_observeDocument: (id: string, clientConfig?: ObserveDocumentAPIConfig) => Observable<SanityDocument | undefined>; /** * Observe a list of complete documents with the given IDs * @hidden * @beta */ unstable_observeDocuments: (ids: string[], clientConfig?: ObserveDocumentAPIConfig) => Observable<(SanityDocument | undefined)[]>; } /** @internal */ interface DocumentPreviewStoreOptions { client: SanityClient; } /** @internal */ declare function createDocumentPreviewStore({ client }: DocumentPreviewStoreOptions): DocumentPreviewStore; interface DocumentPerspectiveProps { documentId: string; } interface DocumentPerspectiveState { data: string[]; error?: unknown; loading: boolean; } /** * Fetches the document versions for a given document * @param props - document Id of the document (might include release id) * @returns - data: document versions, loading, errors * @hidden * @beta */ declare function useDocumentVersions(props: DocumentPerspectiveProps): DocumentPerspectiveState; interface useDocumentVersionTypeSortedListState { sortedDocumentList: ReleaseDocument[]; } /** * Fetches the document versions for a given document and sorts them by release type * * @param documentId - document id related to the document version list * @returns object with sortedDocumentList * * @beta */ declare const useDocumentVersionTypeSortedList: ({ documentId }: { documentId: string; }) => useDocumentVersionTypeSortedListState; /** @internal */ declare const useIsReleaseActive: () => boolean; /** * Returns a boolean if the document has only versions * * @param documentId - document id related to the document version list * @returns if the document has only versions * * @beta */ declare const useOnlyHasVersions: ({ documentId }: { documentId: string; }) => boolean; interface VersionOperationsValue { createVersion: (releaseId: ReleaseId, documentId: string) => Promise<void>; discardVersion: (releaseId: string, documentId: string) => Promise<SingleActionResult>; unpublishVersion: (documentId: string) => Promise<SingleActionResult>; revertUnpublishVersion: (documentId: string) => Promise<SingleActionResult>; } /** @internal */ declare function useVersionOperations(): VersionOperationsValue; /** * Sorts releases by their release type and created date. * @internal */ declare function sortReleases(releases?: ReleaseDocument[]): ReleaseDocument[]; /** * This is used to draw the bar that wraps the diff components in the changes panel * * @internal */ declare const ChangeFieldWrapper: (props: { path: Path; children: ReactNode; hasRevertHover: boolean; }) => react.JSX.Element; /** @internal */ interface ChangeIndicatorProps { path: Path; hasFocus: boolean; isChanged: boolean; withHoverEffect?: boolean; } /** @internal */ declare function ChangeIndicator(props: ChangeIndicatorProps & Omit<HTMLProps<HTMLDivElement>, 'as'>): react.JSX.Element; /** @internal */ interface ConnectorContextValue { isReviewChangesOpen: boolean; onOpenReviewChanges: () => void | undefined; onSetFocus: (nextPath: Path) => void | undefined; isInteractive?: boolean; } /** @internal */ interface ChangeConnectorRootProps { children: ReactNode; className?: string; isReviewChangesOpen: boolean; onOpenReviewChanges: () => void; onSetFocus: (path: Path) => void; } /** @internal */ declare function ChangeConnectorRoot({ children, className, isReviewChangesOpen, onOpenReviewChanges, onSetFocus, ...restProps }: ChangeConnectorRootProps): react.JSX.Element; /** @internal */ type Reported<Value> = [string, Value]; /** @internal */ type ReporterHook<Payload> = (id: string | null, value: () => Payload, isEqual?: IsEqualFunction<Payload>) => void; /** @internal */ type IsEqualFunction<Value> = (a: Value | null, b: Value | null) => boolean; /** @internal */ interface TrackerContextStore<Value> { add: (id: string, value: Value) => void; update: (id: string, value: Value) => void; remove: (id: string) => void; } /** @internal */ type TrackerContextGetSnapshot<Value> = [string, Value][]; /** @internal */ declare function useTrackerStore<Value>(): { store: TrackerContextStore<Value>; snapshot: TrackerContextGetSnapshot<Value>; }; /** @internal */ declare function useTrackerStoreReporter<Value>(store: TrackerContextStore<Value> | null, id: string | null, value: () => Value, isEqual?: IsEqualFunction<Value>): void; /** @internal */ interface TrackedChange { element: HTMLElement | null; path: Path; isChanged: boolean; hasFocus: boolean; hasHover: boolean; hasRevertHover: boolean; zIndex: number; } /** @internal */ interface TrackedArea { element: HTMLElement | null; } /** @internal */ type ChangeIndicatorTrackerContextValue = TrackedChange; declare function ChangeIndicatorsTrackerComponent(props: { children: React.ReactNode; }): react.JSX.Element; /** * @internal */ declare const ChangeIndicatorsTracker: react.MemoExoticComponent<typeof ChangeIndicatorsTrackerComponent>; /** * @internal */ declare function useChangeIndicatorsReportedValues(): TrackerContextGetSnapshot<ChangeIndicatorTrackerContextValue>; /** * @internal */ declare const useChangeIndicatorsReporter: ReporterHook<ChangeIndicatorTrackerContextValue>; /** * @beta * @hidden */ interface CommentDeleteDialogProps { commentId: string; error: Error | null; isParent: boolean; loading: boolean; onClose: () => void; onConfirm: (id: string) => void; } /** * @beta * @hidden */ declare function CommentDeleteDialog(props: CommentDeleteDialogProps): react.JSX.Element; /** * @internal */ declare const CommentDisabledIcon: react.ForwardRefExoticComponent<Omit<SVGProps<SVGSVGElement>, "ref"> & react.RefAttributes<SVGSVGElement>>; /** * * @deprecated Calling `useClient()` without specifying an API version is deprecated - specify a date to prevent breaking changes, e.g. `useClient({apiVersion: "2025-02-07"})`. * * React hook that returns a configured Sanity client instance based on the given configuration. * Automatically uses the correct project and dataset based on the current active workspace. * * @public * @returns A configured Sanity client instance * @remarks The client instance is automatically memoized based on API version * @remarks The client will fallback to `v2025-02-07` of the API * @example Instantiating a client * ```ts * function MyComponent() { * const client = useClient({apiVersion: '2021-06-07'}) * // ... do something with client instance ... * } * ``` */ declare function useClient(): SanityClient; /** * React hook that returns a configured Sanity client instance based on the given configuration. * Automatically uses the correct project and dataset based on the current active workspace. * * @public * @param clientOptions - Options for the client. Specifying * {@link https://www.sanity.io/docs/api-versioning | apiVersion} is required in order to * prevent breaking changes if studio changes the API version used in other places. * See {@link SourceClientOptions} * @returns A configured Sanity client instance * @remarks The client instance is automatically memoized based on API version * @example Instantiating a client * ```ts * function MyComponent() { * const client = useClient({apiVersion: '2021-06-07'}) * // ... do something with client instance ... * } * ``` */ declare function useClient(clientOptions: SourceClientOptions): SanityClient; /** * Workaround to support conditional toast (e.g. a toast that is visible as long as a condition holds true) * @hidden * @internal */ declare function useConditionalToast(params: ToastParams & { id: string; enabled?: boolean; delay?: number; }): void; /** @internal */ type ConnectionState = 'connecting' | 'reconnecting' | 'connected'; /** @internal */ declare function useConnectionState(publishedDocId: string, docTypeName: string, version?: string): ConnectionState; /** * React hook that returns the name of the current dataset * * @public * @returns The name of the current dataset * @example Using the `useDataset` hook * ```ts * function MyComponent() { * const dataset = useDataset() * // ... do something with the dataset name ... * } * ``` */ declare function useDataset(): string; /** * Options for the `useDateTimeFormat` hook * * @public */ type UseDateTimeFormatOptions = Omit<Intl.DateTimeFormatOptions, 'fractionalSecondDigits'>; /** * Returns an instance of `Intl.DateTimeFormat` that uses the currently selected locale, * and enables locale and culture-sensitive date formatting. * * @param options - Optional options for the date/time formatter * @returns Instance of `Intl.DateTimeFormat` * @public */ declare function useDateTimeFormat(options?: UseDateTimeFormatOptions): Intl.DateTimeFormat; /** * Hook to register a dialog in the stack and check if it's the top-most one. * * @beta */ declare function useDialogStack({ path }?: { path?: Path; }): { /** Unique ID for this dialog instance */dialogId: string; /** The current top dialog entry */ topEntry: sanity__singletons0.DialogStackEntry | null; /** The full stack of dialog entries (each has id and path) */ stack: sanity__singletons0.DialogStackEntry[]; /** Check if this dialog is on top */ isTop: boolean; /** Close dialogs */ close: (options?: { toParent?: boolean | undefined; } | undefined) => void; /** Navigate to a specific path, updating the form path and cleaning up the stack */ navigateTo: (path: Path) => void; }; /** @internal */ type CommitFunction = (mutation: Mutation['params']) => Promise<unknown>; /** * @hidden * @beta */ interface DocumentRebaseEvent { type: 'rebase'; document: SanityDocument; remoteMutations: MutationPayload[]; localMutations: MutationPayload[]; } /** * @hidden * @beta */ interface DocumentMutationEvent { type: 'mutation'; document: SanityDocument; mutations: MutationPayload[]; origin: 'local' | 'remote'; } /** * @hidden * @beta */ interface SnapshotEvent { type: 'snapshot'; document: SanityDocument; } /** * @hidden * @beta */ interface CommittedEvent { type: 'committed'; } /** * @hidden * @beta */ interface DocumentRemoteMutationEvent { type: 'remoteMutation'; head: SanityDocument; transactionId: string; author: string; timestamp: Date; effects: { apply: unknown; revert: unknown; }; } /** * @hidden * @beta */ type RemoteSnapshotEvent = DocumentRemoteMutationEvent | SnapshotEvent; /** * @hidden * @beta */ interface MutationPayload { create?: any; createIfNotExists?: any; createOrReplace?: any; delete?: any; patch?: any; } /** @internal */ interface MutationEvent { type: 'mutation'; documentId: string; transactionId: string; mutations: MutationPayload[]; effects: { apply: unknown; revert: unknown; }; previousRev: string; resultRev: string; transactionTotalEvents: number; transactionCurrentEvent: number; messageReceivedAt: string; visibility: 'transaction' | 'query'; transition: 'update' | 'appear' | 'disappear'; } /** @internal */ interface PendingMutationsEvent { type: 'pending'; phase: 'begin' | 'end'; } /** @internal */ interface IdPair { draftId: string; publishedId: string; versionId?: string; } interface ListenerSequenceState { /** * Tracks the latest revision from the server that can be applied locally * Once we receive a mutation event that has a `previousRev` that equals `base.revision` * we will move `base.revision` to the event's `resultRev` * `base.revision` will be undefined if document doesn't exist. * `base` is `undefined` until the snapshot event is received */ base: { revision: string | undefined; } | undefined; /** * Array of events to pass on to the stream, e.g. when mutation applies to current head revision, or a chain is complete */ emitEvents: ListenerEvent[]; /** * Buffer to keep track of events that doesn't line up in a [previousRev, resultRev] -- [previousRev, resultRev] sequence * This can happen if events arrive out of order, or if an event in the middle for some reason gets lost */ buffer: MutationEvent[]; } /** * Takes an input observable of listener events that might arrive out of order, and emits them in sequence * If we receive mutation events that doesn't line up in [previousRev, resultRev] pairs we'll put them in a buffer and * check if we have an unbroken chain every time we receive a new event * * If the buffer grows beyond `maxBufferSize`, or if `resolveChainDeadline` milliseconds passes before the chain resolves * an OutOfSyncError will be thrown on the stream * * @internal */ declare class OutOfSyncError extends Error { /** * Attach state to the error for debugging/reporting */ state: ListenerSequenceState; constructor(message: string, state: ListenerSequenceState); } /** @internal */ interface InitialSnapshotEvent { type: 'snapshot'; documentId: string; document: SanityDocument | null; } /** * @internal */ interface LatencyReportEvent { shard?: string; latencyMs: number; transactionId: string; } /** @internal */ interface DocumentPairLoadedEvent { durationMs: number; fromCache: boolean; hasPublished: boolean; hasDraft: boolean; hasVersion: boolean; } /** @internal */ interface DocumentStoreExtraOptions { tag?: string; /** * Called when we recover from sync error * Meant for error tracking / telemetry purposes * @param error - the {@link OutOfSyncError} recovered from */ onSyncErrorRecovery?(error: OutOfSyncError): void; onReportLatency?: (event: LatencyReportEvent) => void; onSlowCommit?: () => void; onDocumentPairLoaded?: (event: DocumentPairLoadedEvent) => void; } /** @internal */ type ListenerEvent = MutationEvent | ReconnectEvent | InitialSnapshotEvent | PendingMutation