// // Copyright 2026 DXOS.org // import React, { InputHTMLAttributes, forwardRef, useCallback, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { translationKey } from '#translations'; import { IconButton, type IconButtonProps } from './IconButton'; import { ToggleIconButton, type ToggleIconButtonProps } from './ToggleIconButton'; // Static presets fix the icon and default the label; callers can still override `label`. type StaticPresetProps = Omit & { label?: string }; // Stateful presets fix both icons so a call site cannot supply a conflicting glyph. type TogglePresetProps = Omit & { label?: string }; // // Star // const StarIconButton = forwardRef(({ label, active, ...props }, forwardedRef) => { const { t } = useTranslation(translationKey); return ( ); }); StarIconButton.displayName = 'SystemIconButton.Star'; // // Bookmark // const BookmarkIconButton = forwardRef( ({ label, active, ...props }, forwardedRef) => { const { t } = useTranslation(translationKey); return ( ); }, ); BookmarkIconButton.displayName = 'SystemIconButton.Bookmark'; // // Expander // const ExpanderIconButton = forwardRef( ({ label, active, ...props }, forwardedRef) => { const { t } = useTranslation(translationKey); return ( ); }, ); ExpanderIconButton.displayName = 'SystemIconButton.Expander'; // // Add // const AddIconButton = forwardRef(({ label, ...props }, forwardedRef) => { const { t } = useTranslation(translationKey); return ( ); }); AddIconButton.displayName = 'SystemIconButton.Add'; // // Delete // const DeleteIconButton = forwardRef(({ label, ...props }, forwardedRef) => { const { t } = useTranslation(translationKey); return ( ); }); DeleteIconButton.displayName = 'SystemIconButton.Delete'; // // Edit // const EditIconButton = forwardRef(({ label, ...props }, forwardedRef) => { const { t } = useTranslation(translationKey); return ( ); }); EditIconButton.displayName = 'SystemIconButton.Edit'; // // Close // const CloseIconButton = forwardRef(({ label, ...props }, forwardedRef) => { const { t } = useTranslation(translationKey); return ( ); }); CloseIconButton.displayName = 'SystemIconButton.Close'; // // Clipboard // type ClipboardIconButtonProps = StaticPresetProps & { onCopy: () => string; }; const ClipboardIconButton = forwardRef( ({ label, onCopy, ...props }, forwardedRef) => { const { t } = useTranslation(translationKey); const handleCopy = useCallback(() => { const text = onCopy(); if (text) { void navigator.clipboard.writeText(text); } }, [onCopy]); return ( ); }, ); ClipboardIconButton.displayName = 'SystemIconButton.Clipboard'; // // Upload // type UploadIconButtonProps = StaticPresetProps & Pick, 'accept'> & { onFileChange?: InputHTMLAttributes['onChange']; }; const UploadIconButton = forwardRef( ({ accept, onFileChange, label, ...props }, forwardedRef) => { const { t } = useTranslation(translationKey); const fileInputRef = useRef(null); return ( <> fileInputRef.current?.click()} ref={forwardedRef} /> ); }, ); UploadIconButton.displayName = 'SystemIconButton.Upload'; // // Download // type DownloadIconButtonProps = StaticPresetProps & { filename: string; onDownload: () => Blob | null; }; const DownloadIconButton = forwardRef( ({ filename, onDownload, label, ...props }, forwardedRef) => { const { t } = useTranslation(translationKey); const handleDownload = useCallback(() => { const blob = onDownload(); if (!blob) { return; } const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); }, [onDownload]); return ( ); }, ); DownloadIconButton.displayName = 'SystemIconButton.Download'; // // Namespace // export const SystemIconButton = { Star: StarIconButton, Bookmark: BookmarkIconButton, Expander: ExpanderIconButton, Add: AddIconButton, Delete: DeleteIconButton, Edit: EditIconButton, Close: CloseIconButton, Clipboard: ClipboardIconButton, Upload: UploadIconButton, Download: DownloadIconButton, }; export type { ClipboardIconButtonProps, DownloadIconButtonProps, StaticPresetProps, TogglePresetProps, UploadIconButtonProps, };