import type { AssetsResultProps } from '@grapesjs/react/dist/AssetsProvider'; import type { Asset, Editor } from 'grapesjs'; import { StudioLayoutComponentsConfig } from '../components/public/types'; import type { AssetManagerBaseProps } from '../components/public/types/StudioPanelAssetsSchema'; import { BaseAssetProvider } from './assetsSchema'; import type { WithEditorProps } from './common'; import type { RootLayoutConfig } from './layout'; export type { AssetManagerContentProps, AssetTypeOption } from '../components/public/types/StudioPanelAssetsSchema'; export declare enum AssetStorageType { self = "self", cloud = "cloud" } export interface AssetProps { /** * The asset ID. */ id: string; /** * The asset URL. */ src: string; /** * Custom asset name. * @example 'image.jpg' */ name?: string; /** * The asset mime type, eg. `image/jpeg`. */ mimeType?: string; /** * The asset type. If not present, it's extracted from mimeType, otherwise, defaults to `image`. */ type?: string; /** * Size of the assets in bytes. */ size?: number; /** * Used to convert this back to grapes.Asset */ asset?: Asset; /** * You may add custom extra properties here as needed. */ customData?: Record; } export interface LoadAssetsProps { clearExisting?: boolean; } export type InputAssetProps = Omit & { id?: string; }; export type OnDeleteAssetsProps = { /** * Assets to be deleted. */ assets: Asset[]; /** * Assets to be deleted in a simplified format. */ assetProps: AssetProps[]; /** * Call this function to reload your assets after delete. */ loadAssets: (props?: LoadAssetsProps) => Promise; } & WithEditorProps; export type OnDeleteAssets = (props: OnDeleteAssetsProps) => Promise; export type OnLoadAssets = (props: WithEditorProps) => Promise; export interface AssetPage { /** * Items in this page. */ items: T[]; /** * Set to true to stop loading more pages. * @default false */ isLastPage?: boolean; /** * Pass data to the next onLoad call. Useful for token based pagination. */ nextPageCustomData?: Record; } export type OnLoadProviderAssets = (props: WithEditorProps & { /** * The status of the asset type filter in asset manager. */ assetTypeFilter?: string; /** * Page index starting from 0. */ pageIndex: number; /** * The current value of the search input of the asset manager. * Consider setting AssetProvider.search.reloadOnInput to true before using this prop. */ searchValue: string; /** * When using pagination, this has the object returned by last page's nextPageCustomData prop, undefined otherwise. Useful for token based pagination. */ pageCustomData?: Record; }) => Promise | Promise | Promise> | Promise>; export type ItemLayout = (props: WithEditorProps & { asset: Asset; assetProps: AssetProps; /** * Use it to select an asset in your custom layout. */ onSelect: (assetOrAssetProps: Asset | AssetProps) => void; /** * Use it to delete an asset in your custom layout. * Optional. */ onDelete?: (assetOrAssetProps: Asset | AssetProps) => void; }) => RootLayoutConfig; export declare enum AssetType { image = "image", video = "video" } export interface AssetProvider extends Omit { /** * Asset types supported by this provider. * Only providers that support the current asset type show up in the asset provider filter. * @example * types: 'image', * // Or an array of types * types: ['image', 'video'] */ types: string | string[]; /** * Label to display in the asset provider filter. * You may use a function instead to translate this string. * * @examples * 'My asset provider' * * ({ editor }) => editor.I18n.t('myProviderLabel') */ label: string | ((props: WithEditorProps) => string); /** * Icon to display in the asset provider filter. */ icon?: string; /** * Define how to fetch these assets. * Return an array of assets. * You may return an array of Page objects to enable endless scrolling, you can rely on the pageIndex argument for this. * * @examples * async () => { * // Simple asset array * return [ * { src: 'https://www.example.com/items/1' }, * { src: 'https://www.example.com/items/2' }, * { src: 'https://www.example.com/items/3' } * ] * } * * async ({ pageIndex }) => { * // Offset based pagination * const pageSize = 20; * const params = new URLSearchParams({ page: pageIndex, pageSize }) * const response = await fetch(`https://www.example.com/items?${params}`) * const page = await response.json() * const itemCount = pageSize * pageIndex + page.items.length * return { * items: page.items, * isLastPage: itemCount >= page.total * } * } * * async ({ pageCustomData }) => { * // Token based pagination * const params = new URLSearchParams({ pageToken: pageCustomData?.token }) * const response = await fetch(`https://www.example.com/items?${params}`) * const page = await response.json() * return { * items: page.items, * nextPageCustomData: { token: page.nextPageToken }, * isLastPage: !page.nextPageToken * } * } */ onLoad: OnLoadProviderAssets; /** * Custom layout for rendering an asset item in the AssetManager. * @example * itemLayout: ({ assetProps, onSelect }) => ({ * type: 'column', * style: { height: 150 }, * onClick: () => onSelect(assetProps), * children: [ * { type: 'custom', render: () => `` }, * { type: 'text', style: { width: '100%' }, content: assetProps.name ?? '' } * ] * }) */ itemLayout?: ItemLayout; /** * Define how to delete these assets. * If not defined, the delete button is hidden. */ onDelete?: OnDeleteAssets; } export type GetAssetProviders = (props: { providers: AssetProvider[]; }) => AssetProvider[]; /** * Props for an instance of the AssetManager. * An sdk consumer may pass these via `AssetManager.open(assetManagerProps)`, * or in the layout config of a StudioPanelAssets using the layout system via `{ id: 'panelAssets', ...assetManagerProps }`. * @example * AssetManager.open(assetManagerProps) * * @example * { id: 'panelAssets', ...assetManagerProps } */ export interface AssetManagerProps extends Omit { /** * A custom array of assets. Overrides any other configured onLoad or providers. * @examples * assets: [ * { * type: 'image', * url: 'https://example.com/image.jpg', * } * ] */ assets?: Asset[] | InputAssetProps[]; /** * Callback when an asset is selected. * @examples * onSelect: ({ asset, editor }) => { * editor.AssetManager.add(asset); * } */ onSelect?: (props: { asset: Asset; assetProps: AssetProps; } & WithEditorProps) => void; /** * Custom layout configuration for additional header content in the asset manager. * @example * layoutAfterHeader: ({ editor }) => ({ * type: 'row', * style: { padding: '8px 16px', borderBottom: '1px solid #e0e0e0' }, * children: [ * { * type: 'button', * variant: 'outline', * content: 'Custom Action', * onClick: () => editor.runCommand('custom:action') * } * ] * }) */ layoutAfterHeader?: ({ editor }: { editor: Editor; }) => StudioLayoutComponentsConfig; } export type CustomAssetManagerProps = AssetsResultProps & Omit & { open?: (props: any) => void; close?: (props: any) => void; }; export interface AssetsConfig extends Pick { /** * Choose between hosting assets on: * - 'self': your own self-hosted infrastructure * - 'cloud': using our asset cloud provider. * * To use 'cloud' you must provide an identity.id for your users and a project.id for your project in config. * @default 'self' */ storageType?: `${AssetStorageType}` | AssetStorageType; /** * Provide a custom upload handler for assets. * The handler should return an array of uploaded assets. * @example * onUpload: async ({ files }) => { * const body = new FormData(); * for (const file of files) { * body.append('files', file); * } * const response = await fetch('ASSETS_UPLOAD_URL', { method: 'POST', body }); * const result = await response.json(); * // The expected result should be an array of assets, eg. * // [{ src: 'ASSET_URL' }] * return result; * }, */ onUpload?: (props: { files: File[]; } & WithEditorProps) => Promise; /** * Provide a custom handler for loading project assets. * The handler should return an array of uploaded assets. * With this handler enabled, asset references won't be stored in the project JSON. * * @example * onLoad: async () => { * // Load assets from your server * const response = await fetch('ASSETS_LOAD_URL'); * const result = await response.json(); * // you can also provide default assets here * return [ { src: 'ASSET_URL' }, ...result ]; * } */ onLoad?: OnLoadAssets; /** * Provide a custom handler for deleting assets. * If the handler doesn't throw any error, the assets will be removed from the asset manager. * * @example * onDelete: async ({ assets }) => { * const body = JSON.stringify(assets); * await fetch('ASSETS_DELETE_URL', { method: 'DELETE', body }); * } */ onDelete?: OnDeleteAssets; /** * Asset provider options that show up in the asset provider filter in asset manager. * Only one provider is loaded at once in the same AssetManager instance. * The array version of this prop is prepended by default providers depending on configuration (e.g. AssetsConfig.storageType = 'cloud' adds a default cloud provider for images). * To remove these default providers, or reorder them, you can use the function version of this prop. * * @example * providers: [ * { * id: 'unsplash' * type: [AssetType.image], * label: 'Unsplash images', * onLoad: async () => { * const response = await fetch('https://api.unsplash.com/photos/?client_id=YOUR_ACCESS_KEY'); * const data = await response.json(); * return data.map(image => ({ src: image.urls.regular })); * }, * itemLayout: ({ editor, assetProps, etc... }) => ({ type: 'column' }), * } * ] * * @example * providers: ({ providers }) => [ * // default providers * ...providers, * { * id: 'youtube' * type: [AssetType.image], * label: 'YouTube video thumbnails', * onLoad: async () => { * const response = await fetch('https://www.googleapis.com/youtube/v3/videos?key=YOUR_ACCESS_KEY'); * const data = await response.json(); * return data.map(image => ({ src: video.snippet.thumbnails.default.url })); * }, * itemLayout: ({ editor, assetProps, etc... }) => ({ type: 'column' }), * } * ] */ providers?: AssetProvider[] | GetAssetProviders; }