Reusable UI library for:
- media registries and curated assets
- React slash-menu icons
- slash-menu block catalogs
- color picker boards
- a unified tabbed asset picker for emojis, SVGs, icons, and future asset families
npm install @univers42/ui-collection reactMedia: images and videos
This package now exposes a focused, provider-driven media API under:
@univers42/ui-collection/library/media— exportsimagesandvideosnamespaces.
Images
Use the helpers and providers under images to normalize and consume remote images. The library provides:
images.normalizeUrlImage(source)— normalize a direct image URL to a pickableNormalizedImagemodel withthumbnailUrl,previewUrl, andfullUrl.images.UnsplashImageProvider— a minimal client that requires anaccessKeypassed by the consumer and returns normalized images from Unsplash.images.imageCollectionPresets— curated query presets for Japanese prints, NASA/space, art deco, nature, and animals.
Example — normalize a URL image:
import { images } from '@univers42/ui-collection/library/media';
const normalized = images.normalizeUrlImage({ kind: 'url', url: 'https://example.com/photo.jpg', alt: 'Example' });
console.log(normalized.thumbnailUrl, normalized.previewUrl, normalized.fullUrl);Example — search Unsplash (consumer must supply access key):
import { images } from '@univers42/ui-collection/library/media';
const provider = new images.UnsplashImageProvider({ accessKey: process.env.UNSPLASH_ACCESS_KEY });
const results = await provider.search('mountains', 1, 10);
console.log(results[0]?.thumbnailUrl, results[0]?.previewUrl, results[0]?.fullUrl);Videos
Videos are separate and support direct remote URLs plus future-ready external provider entries.
Example — normalize a URL video:
import { videos } from '@univers42/ui-collection/library/media';
const normalized = videos.normalizeUrlVideo({
kind: 'url',
src: 'https://cdn.example.com/video.mp4',
thumbnailUrl: 'https://cdn.example.com/video-thumb.jpg',
posterUrl: 'https://cdn.example.com/poster.jpg',
});
console.log(normalized.videoUrl, normalized.thumbnailUrl, normalized.posterUrl);Notes
- Unsplash is only used for images — there is no Unsplash video integration.
- The library does not bundle binary media files. Prefer remote URLs.
- The library does not apply styles or render UI; it only provides types, normalizers, and providers. Consumers decide rendering and styling.
import {
AssetPickerBoard,
AssetRenderer,
ColorPickerBoard,
IconPickerBoard,
EmojiPickerBoard,
assetValueToBoardValue,
createDefaultAssetPickerTabs,
createEmojiPickerTab,
createIconPickerTab,
parseAssetValue,
resolveAssetValue,
serializeAssetSelection,
SLASH_ITEMS,
SECTION_LABELS,
// media APIs changed: use images and videos providers
images,
videos,
DEFAULT_ASSET_PICKER_TABS,
DEFAULT_COLOR_PRESETS,
DEFAULT_ICON_PICKER_ITEMS,
EMOJI_PICKER_GROUPS,
DEFAULT_EMOJI_PICKER_ITEMS,
} from '@univers42/ui-collection';import * as media from '@univers42/ui-collection/library/media';
// Use `media.images` and `media.videos` providers and normalizers.
import { SLASH_ITEMS } from '@univers42/ui-collection/library/catalogs';
import { IconText, IconBoard } from '@univers42/ui-collection/library/icons/react/slash-menu';
import {
AssetPickerBoard,
AssetRenderer,
assetValueToBoardValue,
createMediaCollectionPickerTab,
parseAssetValue,
resolveAssetValue,
serializeAssetSelection,
} from '@univers42/ui-collection/library/components/react/asset-picker';
import { ColorPickerBoard } from '@univers42/ui-collection/library/components/react/color-picker';
import { IconPickerBoard } from '@univers42/ui-collection/library/components/react/icon-picker';
import { EmojiPickerBoard } from '@univers42/ui-collection/library/components/react/emoji-picker';
import { LineChart } from '@univers42/ui-collection/library/components/react/charts';
import { FormulaTypePie } from '@univers42/ui-collection/library/components/react/analytics/formula';
import { ThemeToggle } from '@univers42/ui-collection/library/components/react/theme';import { ColorPickerBoard } from '@univers42/ui-collection/components/blocks/ColorPickerBoard';
import { IconText } from '@univers42/ui-collection/components/blocks/SlashMenuIcons';
import { SLASH_ITEMS } from '@univers42/ui-collection/components/blocks/slashMenuCatalog';Available from:
@univers42/ui-collection: curated root surface@univers42/ui-collection/library/components/react: full React component catalog
The root API is intentionally small and stable. More specialized modules live under dedicated library/components/react/* entry points.
Root exports include:
AssetPickerBoardAssetRendererColorPickerBoardIconPickerBoardEmojiPickerBoardDEFAULT_ASSET_PICKER_TABScreateDefaultAssetPickerTabscreateEmojiPickerTabcreateIconPickerTabcreateMediaCollectionPickerTabparseAssetValueresolveAssetValueassetValueToBoardValueserializeAssetSelectionDEFAULT_COLOR_PRESETSDEFAULT_ICON_PICKER_ITEMSEMOJI_PICKER_GROUPSDEFAULT_EMOJI_PICKER_ITEMSAssetPickerBoardPropsAssetPickerBoardAppearanceAssetPickerBoardTabAssetPickerBoardItemAssetPickerBoardValueAssetPickerBoardSelectionColorPickerBoardPropsColorPickerPresetIconPickerBoardPropsIconPickerItemEmojiPickerGroupEmojiPickerBoardPropsEmojiPickerItem
Full React component exports include:
AssetPickerBoardColorPickerBoardIconPickerBoardEmojiPickerBoardVerticalBarChartHorizontalBarChartLineChartDonutPieChartMultiLineChartDonutChartAreaChartSVGProgressRingFormulaTypePieErrorBarChartComplexityChartTextDistributionCardKpiCardDisplayBadgeRollupCellValueRelationMapSectionFunctionDistSectionDisplayFormatSectionCompletionRingsSectionDataFlowSectionExampleBlockSettingsHeaderSettingsSectionLabelMenuDividerViewTypeCardPanelSectionLabelThemeToggle
Default datasets available from the root:
DEFAULT_ASSET_PICKER_TABS: default tabs for emojis, SVGs, and iconsDEFAULT_COLOR_PRESETS: 8 presetsDEFAULT_ICON_PICKER_ITEMS: 96 iconsEMOJI_PICKER_GROUPS: 9 standard-style emoji categoriesDEFAULT_EMOJI_PICKER_ITEMS: 1,981 emojis across smileys, people, animals, food, travel, activities, objects, symbols, and flags
AssetPickerBoard is the shared board used for asset selection. The default configuration groups emojis, SVGs, and icons into one tabbed picker, and the asset-picker subpath exposes factory helpers so new asset families can be added without duplicating UI.
import {
AssetPickerBoard,
assetValueToBoardValue,
createDefaultAssetPickerTabs,
serializeAssetSelection,
} from '@univers42/ui-collection';
export function Demo() {
const tabs = createDefaultAssetPickerTabs();
return (
<AssetPickerBoard
label="Block asset picker"
tabs={tabs}
value={assetValueToBoardValue('icon:text', tabs)}
onChange={(selection) => {
console.log(selection.tab.id);
console.log(selection.item.value);
console.log(serializeAssetSelection(selection));
}}
/>
);
}The package now emits stable values directly from the library so the consumer does not need local prefixes or wrappers:
- icons serialize as
icon:<id>, for exampleicon:text - emojis serialize as the raw glyph, for example
😀 - media values should be treated as opaque provider refs or direct
url:/absolute URLs. For direct images/videos use the newlibrary/mediahelpers (images/videos) to normalize remote assets; rendering and styling remain the consumer's responsibility.
import {
parseAssetValue,
resolveAssetValue,
} from '@univers42/ui-collection';
const parsed = parseAssetValue('icon:text');
const resolved = resolveAssetValue('icon:text');
console.log(parsed.kind); // icon
console.log(resolved?.label); // TextUse AssetPickerBoard when you want the general-purpose board with all default asset families in one place. You do not need to import IconPickerBoard or EmojiPickerBoard to use the unified board.
import { AssetPickerBoard } from '@univers42/ui-collection';
export function Demo() {
return (
<AssetPickerBoard
label="Block asset picker"
showSelectionPreview={false}
showStatusBar={false}
itemLabelVisibility="hidden"
appearance="unstyled"
onChange={({ tab, item }) => {
console.log(tab.id); // emojis | svg | icons
console.log(item.value); // selected value
}}
/>
);
}Use IconPickerBoard or EmojiPickerBoard only when you want a single-family picker with the legacy API shape.
Use the asset-picker subpath when you want to customize the tabs or add new asset families while keeping the same shared board UI.
import {
AssetPickerBoard,
createEmojiPickerTab,
createIconPickerTab,
createMediaCollectionPickerTab,
} from '@univers42/ui-collection/library/components/react/asset-picker';
const tabs = [
createEmojiPickerTab(),
createMediaCollectionPickerTab('svg'),
createIconPickerTab(),
];
export function Demo() {
return <AssetPickerBoard label="Custom asset picker" tabs={tabs} />;
}IconPickerBoard and EmojiPickerBoard are still available, but they now wrap the shared unified picker internally. This keeps compatibility while the implementation stays modular and scalable.
import {
ColorPickerBoard,
IconPickerBoard,
EmojiPickerBoard,
} from '@univers42/ui-collection';
export function Demo() {
return (
<>
<ColorPickerBoard label="Brand palette" onChange={(hex) => console.log(hex)} />
<IconPickerBoard label="Slash icons" onChange={(iconValue) => console.log(iconValue)} />
<EmojiPickerBoard label="Reaction picker" onChange={(emoji) => console.log(emoji)} />
</>
);
}ColorPickerBoard now defaults to a visually agnostic circular chromatic wheel built from octagonal swatches. Use variant="classic" if you want the legacy square HSV board. If you want the packaged dark skin from this library, opt in with appearance="default". Otherwise, leave the default behavior and provide classNames or styles from the consumer.
<ColorPickerBoard
label="Brand palette"
styles={{
root: { width: 320 },
input: { border: '1px solid var(--border)' },
inputButton: { padding: '0.5rem 0.75rem' },
}}
/>If the host application does not want any board chrome from this package, import ChromaticWheel directly. It only ships the wheel geometry and color swatches, so the surrounding layout and active-state styling can come entirely from the consumer theme.
import { ChromaticWheel } from '@univers42/ui-collection';
export function Demo() {
return (
<ChromaticWheel
value="#2563EB"
onChange={(hex) => console.log(hex)}
className="brand-wheel"
/>
);
}IconPickerBoard emits canonical icon values by default, for example icon:text. EmojiPickerBoard emits the raw emoji glyph, and supports grouped sections plus persistent recents through recentStorageKey.
This is the recommended integration when the host application owns the visual theme and wants emoji, icon and cover-heavy tabs without visible labels.
import {
AssetPickerBoard,
AssetRenderer,
createDefaultAssetPickerTabs,
} from '@univers42/ui-collection';
const tabs = createDefaultAssetPickerTabs({
emojiTabOptions: {
itemLabelVisibility: 'hidden',
layout: 'emoji',
},
iconTabOptions: {
itemLabelVisibility: 'hidden',
layout: 'icon',
},
svgTabOptions: {
itemLabelVisibility: 'hidden',
layout: 'cover',
},
});
export function Demo() {
return (
<AssetPickerBoard
tabs={tabs}
appearance="unstyled"
showSelectionPreview={false}
showStatusBar={false}
classNames={{
root: 'asset-picker-root',
tabButton: 'asset-picker-tab',
itemButton: 'asset-picker-cell',
}}
/>
);
}
export function StoredAssetPreview({ value }: { value: string }) {
return <AssetRenderer value={value} size={28} />;
}Available from:
@univers42/ui-collection@univers42/ui-collection/library/icons/react@univers42/ui-collection/library/icons/react/slash-menu@univers42/ui-collection/components/blocks/SlashMenuIcons
Exported icons:
IconTextIconH1IconH2IconH3IconH4IconH5IconH6IconBulletIconNumberedIconTodoIconToggleIconPageIconCalloutIconQuoteIconTableIconDividerIconLinkToPageIconImageIconVideoIconAudioIconCodeIconFileIconBookmarkIconBoardIconGalleryIconListIconColumnsIconTOCIconEquationIconSpacerIconEmbedIconBreadcrumb
import { IconText, IconBoard, IconImage } from '@univers42/ui-collection';
export function Toolbar() {
return (
<div>
<IconText />
<IconBoard />
<IconImage />
</div>
);
}Available from:
@univers42/ui-collection@univers42/ui-collection/library/catalogs@univers42/ui-collection/components/blocks/slashMenuCatalog
Exports:
SLASH_ITEMSSECTION_LABELSSlashMenuItemSlashMenuBlockTypeSlashMenuSection
SLASH_ITEMS currently contains 35 entries.
Section labels:
basic->Basic blocksmedia->Medialayout->Layoutadvanced->Advanceddatabase->Database
import { SECTION_LABELS, SLASH_ITEMS } from '@univers42/ui-collection/library/catalogs';
const mediaItems = SLASH_ITEMS.filter((item) => item.section === 'media');
const label = SECTION_LABELS.media;Available from:
@univers42/ui-collection@univers42/ui-collection/library/media
Built-in providers:
localpackageurlapiunsplashpicker
Built-in collections:
svgemojisphotosvideosother-media
Built-in kinds:
svgemojiphotovideoaudiodocumentlottiemodel-3d
The media registry previously exposed collection and resolver utilities. That implementation was removed
and replaced by a focused images/videos API. See the "Media: images and videos" section above for
examples showing how to normalize URL images, use the UnsplashImageProvider, and normalize URL videos.
Current curated asset inventory:
svg: 154 itemsemojis: 4 itemsphotos: 0 packaged binaries, remote-only presets/providersvideos: 59 itemsother-media: 69 items
Remote image collections are now provider-driven only: Unsplash API queries and direct remote URLs.
No photo binaries are shipped in npm package, and media/photos/optimized is no longer part of public image surface.
Curated external asset sources are documented in library/media/SOURCES.md.
Current sources:
- Heroicons
- Unsplash
- Wikimedia Commons
- NASA Science
- NASA
- Google Sample Videos
- Samplelib
- SoundHelix
- MDN Shared Assets
- Twemoji
- W3C
- GitHub Raw Content
- Khronos glTF Sample Assets
Importing from @univers42/ui-collection gives you:
- the unified
AssetPickerBoard - the official
AssetRenderer - the color, icon, and emoji picker wrappers
- the React slash-menu icons
SLASH_ITEMSandSECTION_LABELS- the media registry and helpers
- the default color, icon, emoji, and asset-picker datasets
- the canonical asset value helpers for parse, resolve and serialize
import {
AssetPickerBoard,
AssetRenderer,
ColorPickerBoard,
DEFAULT_ICON_PICKER_ITEMS,
EmojiPickerBoard,
IconPickerBoard,
SLASH_ITEMS,
createDefaultAssetPickerTabs,
parseAssetValue,
} from '@univers42/ui-collection';
// The legacy media registry was removed. Use `library/media` (`images` / `videos`) helpers
// to normalize and consume remote image and video URLs as shown in the "Media: images and videos" section.
const tabs = createDefaultAssetPickerTabs();
const parsed = parseAssetValue('icon:text');
console.log(DEFAULT_ICON_PICKER_ITEMS.length);
console.log(SLASH_ITEMS.length);
console.log(emojiAssets.length);
console.log(src);
console.log(parsed.kind);
export function Demo() {
return (
<>
<AssetPickerBoard
label="Unified asset picker"
tabs={tabs}
showSelectionPreview={false}
/>
<ColorPickerBoard label="Brand palette" />
<IconPickerBoard label="Slash icon picker" />
<EmojiPickerBoard label="Emoji picker" recentStorageKey="demo:emoji-recents" />
<AssetRenderer value="icon:text" size={24} />
</>
);
}