Customize The Asset Library
In this example, we will show you how to customize the asset library in CreativeEditor SDK.
Explore a full code sample of the integration on CodeSandbox or view the code on GitHub.
The asset library is used to find assets to insert them into a scene or replace a currently selected asset. By default, we have already added a configuration of entries shown in the dock panel for images, text, stickers, shapes, and more. You can add and remove every entry or change the appearance of any entry.
First, every entry has a couple of configuration options to determine what and how assets will be displayed.
id: string
A unique identifier for the library entrysourceIds: string[]
An array of source ids that will be shown in this entry. You can use custom asset source ids or asset sources provided by default.ly.img.image
includes all registered imagesly.img.sticker
includes all registered stickersly.img.text
includes text configurationsly.img.vectorpath
includes shapes
canAdd: boolean | ((sourceId: string) => boolean)
If true (or returns true for a specific source id) an upload button will be shown that will add the uploaded file to the current asset source. In addition,onUpload
has to be configured and the asset source must support adding new assets.canRemove: boolean | ((sourceId: string) => boolean)
If true (or returns true for a specific source id) a remove button will be shown in the asset context menu that will remove the asset from the asset source. Please note, that the asset source must support removing assets.previewLength: number
determines how many asset results will be shown in an overview or section overview.previewBackgroundType: 'cover' | 'contain'
determines if the thumbUri is set as a background that will be contained or covered by the card in an overview or section overview.gridBackgroundType: 'cover' | 'contain'
determines if the thumbUri is set as a background that will be contained or covered by the card in the grid viewgridColumns: number
number of columns in the grid viewgridItemHeight: 'auto' | 'square'
determines the height of an item in the grid view.auto
automatically determines height yielding a masonry-like grid viewsquare
every card will have the same square size
cardLabel: (assetResult: AssetResult) => string | undefined
overwrite the label of a card for a specific asset resultcardStyle: (assetResult: AssetResult) => Record<string, string | undefined>
add custom styles to a card for a specific asset resultcardLabelStyle: ( assetResult: AssetResult) => Record<string, string | undefined>
add custom styles to a label for a specific asset resultcardLabelPosition: (assetResult: AssetResult) => 'inside' | 'below'
determines where the label shall be rendered in relation to the cardicon: string | (({ theme, iconSize }: { theme: string; iconSize: string }) => string)
uses a URL as string to set a custom icon for the library in the dock. If a function is passed, the current theme and the set icon size can be used within the function to return a corresponding icon URL. All image file types usable via a HTML<img />
are supported here.title: string | (({ group, sourceId }, TFunction) => string | undefined)
use a custom translation for this entry. Will be used in the dock as well as in the overviews for a group or a source. Ifundefined
is returned by the function it will be handled like there wasn't a title function set at all. The second argument is the translation function that can be used to lookup translations with i18n keys.
Adding, changing, or removing entries is done in ui.libraries.insert.entries
(for insertion) or ui.libraries.replace.entries
(for replacement). It can be either an array of entries as defined above in which case all default entries will be replaced with the given entries. Or, if a function is provided it will receive the default entries as an argument and expects an array of entries as a return value from this function. This allows adding, removing, and changing the default entries.
The basics of customizing the entries for replacement are the same as for insertion. The main difference is that these entries might vary depending on what block is currently selected and that the returned entries will determine if a replace action is shown on a selected block.
Most of the time it makes sense to provide a custom function to return different entries based on the type or fill of a block. If no replacement should be available for the current block, an empty array has to be returned. The UI will not show a replace button in that case.
As a second argument, you will get the current context in the editor, mainly what blocks are selected, their block type as well as fills. This makes it more convenient to quickly decide what to return, but of course, you can also use the API for further checks as well.
If you do not use a custom title
function for an entry, you need a translation provided with the following keys in the i18n
configuration:
libraries.<entry-id>.label
The label used in the dock panellibraries.<entry-id><group-id>.label
The label for groups for a given entry.libraries.<entry-id>.<source-id>.label
The label for a source in the source overview of a given entrylibraries.<entry-id>.<source-id>.<group-id>.label
The label for a given group in the group overview for a given entry.libraries.<source-id>.label
The label used for a source in all entrieslibraries.<source-id><group-id>.label
The label for groups for source in all entries.
import 'https://cdn.img.ly/packages/imgly/cesdk-js/1.16.1/cesdk.umd.js';let config = {baseURL: 'https://cdn.img.ly/packages/imgly/cesdk-js/1.16.1/assets',i18n: {en: {'libraries.empty-custom-asset-source.label': 'Empty'}},ui: {elements: {libraries: {replace: {entries: (defaultEntries, context) => {if (context.selectedBlocks.length !== 1) {return [];}const [selectedBlock] = context.selectedBlocks;if (selectedBlock.blockType === 'ly.img.image') {return [...defaultEntries,{id: 'empty-custom-asset-source-for-replace',sourceIds: ['emptySource'],previewLength: 3,gridColumns: 3,gridItemHeight: 'square'}];}return [];}},insert: {entries: (defaultEntries) => {const imageEntry = defaultEntries.find((entry) => {return entry.id === 'ly.img.image';});if (imageEntry) {imageEntry.gridColumns = 4;}return [...defaultEntries,{id: 'empty-custom-asset-source',sourceIds: ['emptySource'],previewLength: 3,gridColumns: 3,gridItemHeight: 'square',previewBackgroundType: 'contain',gridBackgroundType: 'contain',icon: ({ theme, iconSize }) => {if (theme === 'dark') {if (iconSize === 'normal') {return 'https://img.ly/static/cesdk/guides/icon-normal-dark.svg';} else {return 'https://img.ly/static/cesdk/guides/icon-large-dark.svg';}}if (iconSize === 'normal') {return 'https://img.ly/static/cesdk/guides/icon-normal-light.svg';} else {return 'https://img.ly/static/cesdk/guides/icon-large-light.svg';}}},{id: 'custom-images',sourceIds: ['ly.img.image'],previewLength: 5,gridColumns: 5,icon: 'https://img.ly/static/cesdk/guides/icon-normal-dark.svg'}];}}}}},callbacks: { onUpload: 'local' } // Enable local uploads in Asset Library.};CreativeEditorSDK.create('#cesdk_container', config).then(async (instance) => {// Do something with the instance of CreativeEditor SDK, for example:// Populate the asset library with default / demo asset sources.instance.addDefaultAssetSources();instance.addDemoAssetSources({ sceneMode: 'Design' });instance.engine.asset.addSource({id: 'emptySource',findAssets: () => {return Promise.resolve({assets: [],total: 0,currentPage: 1,nextPage: undefined});}});await instance.createDesignScene();});