@bsol-oss/react-datatable5 12.0.0-beta.81 → 12.0.0-beta.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +28 -1
- package/dist/index.js +277 -135
- package/dist/index.mjs +279 -138
- package/dist/types/components/Form/components/MediaLibraryBrowser.d.ts +22 -0
- package/dist/types/components/Form/components/fields/FilePicker.d.ts +16 -0
- package/dist/types/components/Form/components/fields/FormMediaLibraryBrowser.d.ts +2 -0
- package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +6 -0
- package/dist/types/components/Form/components/viewers/SchemaViewer.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -771,6 +771,10 @@ interface FilePickerLabels {
|
|
|
771
771
|
noFilesFound?: string;
|
|
772
772
|
cancel?: string;
|
|
773
773
|
select?: string;
|
|
774
|
+
uploadTab?: string;
|
|
775
|
+
browseTab?: string;
|
|
776
|
+
uploading?: string;
|
|
777
|
+
uploadFailed?: string;
|
|
774
778
|
}
|
|
775
779
|
interface CustomJSONSchema7 extends JSONSchema7 {
|
|
776
780
|
gridColumn?: string;
|
|
@@ -817,6 +821,8 @@ interface FilePickerProps {
|
|
|
817
821
|
onFetchFiles?: (search: string) => Promise<FilePickerMediaFile[]>;
|
|
818
822
|
enableMediaLibrary?: boolean;
|
|
819
823
|
filterImageOnly?: boolean;
|
|
824
|
+
enableUpload?: boolean;
|
|
825
|
+
onUploadFile?: (file: File) => Promise<string>;
|
|
820
826
|
}
|
|
821
827
|
|
|
822
828
|
interface FormRootProps<TData extends FieldValues> {
|
|
@@ -875,6 +881,27 @@ declare const FormTitle: () => react_jsx_runtime.JSX.Element;
|
|
|
875
881
|
|
|
876
882
|
declare const FormBody: <TData extends object>() => string | number | bigint | boolean | Iterable<react.ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<react.ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
|
|
877
883
|
|
|
884
|
+
type MediaLibraryBrowserPropsBase = {
|
|
885
|
+
onFetchFiles?: (search: string) => Promise<FilePickerMediaFile[]>;
|
|
886
|
+
filterImageOnly?: boolean;
|
|
887
|
+
labels?: FilePickerLabels;
|
|
888
|
+
enabled?: boolean;
|
|
889
|
+
};
|
|
890
|
+
type MediaLibraryBrowserPropsSingle = MediaLibraryBrowserPropsBase & {
|
|
891
|
+
multiple?: false;
|
|
892
|
+
onFileSelect?: (fileId: string) => void;
|
|
893
|
+
selectedFileId?: string;
|
|
894
|
+
onSelectedFileIdChange?: (fileId: string) => void;
|
|
895
|
+
};
|
|
896
|
+
type MediaLibraryBrowserPropsMultiple = MediaLibraryBrowserPropsBase & {
|
|
897
|
+
multiple: true;
|
|
898
|
+
onFileSelect?: (fileId: string[]) => void;
|
|
899
|
+
selectedFileId?: string[];
|
|
900
|
+
onSelectedFileIdChange?: (fileId: string[]) => void;
|
|
901
|
+
};
|
|
902
|
+
type MediaLibraryBrowserProps = MediaLibraryBrowserPropsSingle | MediaLibraryBrowserPropsMultiple;
|
|
903
|
+
declare const MediaLibraryBrowser: ({ onFetchFiles, filterImageOnly, labels, enabled, multiple, onFileSelect, selectedFileId: controlledSelectedFileId, onSelectedFileIdChange, }: MediaLibraryBrowserProps) => react_jsx_runtime.JSX.Element | null;
|
|
904
|
+
|
|
878
905
|
interface UseFormProps {
|
|
879
906
|
preLoadedValues?: FieldValues | undefined;
|
|
880
907
|
keyPrefix?: string;
|
|
@@ -1136,4 +1163,4 @@ declare module '@tanstack/react-table' {
|
|
|
1136
1163
|
}
|
|
1137
1164
|
}
|
|
1138
1165
|
|
|
1139
|
-
export { type CalendarProps, CardHeader, type CardHeaderProps, type CustomJSONSchema7, type CustomJSONSchema7Definition, DataDisplay, type DataDisplayProps, type DataResponse, DataTable, type DataTableDefaultState, type DataTableProps, DataTableServer, type DataTableServerProps, type DatePickerLabels, type DatePickerProps, type DateTimePickerLabels, DefaultCardTitle, DefaultForm, type DefaultFormProps, DefaultTable, type DefaultTableProps, DefaultTableServer, type DefaultTableServerProps, DensityToggleButton, type DensityToggleButtonProps, type EditFilterButtonProps, EditSortingButton, type EditSortingButtonProps, type EditViewButtonProps, EmptyState, type EmptyStateProps, type EnumPickerLabels, ErrorAlert, type ErrorAlertProps, type ErrorMessageConfig, type ErrorMessageResult, type FieldErrorConfig, type FilePickerLabels, type FilePickerMediaFile, type FilePickerProps, FilterDialog, FormBody, FormRoot, type FormRootProps, FormTitle, type GetColumnsConfigs, type GetDateColorProps, type GetMultiDatesProps, type GetRangeDatesProps, type GetStyleProps, type GetVariantProps, GlobalFilter, type IdPickerLabels, PageSizeControl, type PageSizeControlProps, Pagination, type QueryParams, type RangeCalendarProps, type RangeDatePickerProps, RecordDisplay, type RecordDisplayProps, ReloadButton, type ReloadButtonProps, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, type Result, RowCountText, Table, TableBody, type TableBodyProps, TableCardContainer, type TableCardContainerProps, TableCards, type TableCardsProps, TableComponent, TableControls, type TableControlsProps, TableDataDisplay, type TableDataDisplayProps, TableFilter, TableFilterTags, TableFooter, type TableFooterProps, TableHeader, type TableHeaderProps, type TableHeaderTexts, TableLoadingComponent, type TableLoadingComponentProps, type TableProps, type TableRendererProps, type TableRowSelectorProps, TableSelector, TableSorter, TableViewer, type TagPickerProps, TextCell, type TextCellProps, type UseDataTableProps, type UseDataTableReturn, type UseDataTableServerProps, type UseDataTableServerReturn, type UseFormProps, type ValidationErrorType, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, convertToAjvErrorsFormat, createErrorMessage, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
|
|
1166
|
+
export { type CalendarProps, CardHeader, type CardHeaderProps, type CustomJSONSchema7, type CustomJSONSchema7Definition, DataDisplay, type DataDisplayProps, type DataResponse, DataTable, type DataTableDefaultState, type DataTableProps, DataTableServer, type DataTableServerProps, type DatePickerLabels, type DatePickerProps, type DateTimePickerLabels, DefaultCardTitle, DefaultForm, type DefaultFormProps, DefaultTable, type DefaultTableProps, DefaultTableServer, type DefaultTableServerProps, DensityToggleButton, type DensityToggleButtonProps, type EditFilterButtonProps, EditSortingButton, type EditSortingButtonProps, type EditViewButtonProps, EmptyState, type EmptyStateProps, type EnumPickerLabels, ErrorAlert, type ErrorAlertProps, type ErrorMessageConfig, type ErrorMessageResult, type FieldErrorConfig, type FilePickerLabels, type FilePickerMediaFile, type FilePickerProps, FilterDialog, FormBody, FormRoot, type FormRootProps, FormTitle, type GetColumnsConfigs, type GetDateColorProps, type GetMultiDatesProps, type GetRangeDatesProps, type GetStyleProps, type GetVariantProps, GlobalFilter, type IdPickerLabels, MediaLibraryBrowser, type MediaLibraryBrowserProps, PageSizeControl, type PageSizeControlProps, Pagination, type QueryParams, type RangeCalendarProps, type RangeDatePickerProps, RecordDisplay, type RecordDisplayProps, ReloadButton, type ReloadButtonProps, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, type Result, RowCountText, Table, TableBody, type TableBodyProps, TableCardContainer, type TableCardContainerProps, TableCards, type TableCardsProps, TableComponent, TableControls, type TableControlsProps, TableDataDisplay, type TableDataDisplayProps, TableFilter, TableFilterTags, TableFooter, type TableFooterProps, TableHeader, type TableHeaderProps, type TableHeaderTexts, TableLoadingComponent, type TableLoadingComponentProps, type TableProps, type TableRendererProps, type TableRowSelectorProps, TableSelector, TableSorter, TableViewer, type TagPickerProps, TextCell, type TextCellProps, type UseDataTableProps, type UseDataTableReturn, type UseDataTableServerProps, type UseDataTableServerReturn, type UseFormProps, type ValidationErrorType, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, convertToAjvErrorsFormat, createErrorMessage, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
|
package/dist/index.js
CHANGED
|
@@ -4644,10 +4644,13 @@ function formatBytes(bytes) {
|
|
|
4644
4644
|
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
|
|
4645
4645
|
}
|
|
4646
4646
|
|
|
4647
|
-
|
|
4647
|
+
const MediaLibraryBrowser = ({ onFetchFiles, filterImageOnly = false, labels, enabled = true, multiple = false, onFileSelect, selectedFileId: controlledSelectedFileId, onSelectedFileIdChange, }) => {
|
|
4648
4648
|
const [searchTerm, setSearchTerm] = React.useState('');
|
|
4649
|
-
const [
|
|
4649
|
+
const [internalSelectedFileId, setInternalSelectedFileId] = React.useState(multiple ? [] : '');
|
|
4650
4650
|
const [failedImageIds, setFailedImageIds] = React.useState(new Set());
|
|
4651
|
+
// Use controlled or internal state for selectedFileId
|
|
4652
|
+
const selectedFileId = controlledSelectedFileId ?? internalSelectedFileId;
|
|
4653
|
+
const setSelectedFileId = onSelectedFileIdChange ?? setInternalSelectedFileId;
|
|
4651
4654
|
const { data: filesData, isLoading, isError, } = reactQuery.useQuery({
|
|
4652
4655
|
queryKey: ['file-picker-library', searchTerm],
|
|
4653
4656
|
queryFn: async () => {
|
|
@@ -4656,91 +4659,176 @@ function FilePickerDialog({ open, onClose, onSelect, title, filterImageOnly = fa
|
|
|
4656
4659
|
const files = await onFetchFiles(searchTerm.trim() || '');
|
|
4657
4660
|
return { data: files };
|
|
4658
4661
|
},
|
|
4659
|
-
enabled:
|
|
4662
|
+
enabled: enabled && !!onFetchFiles,
|
|
4660
4663
|
});
|
|
4661
4664
|
const files = (filesData?.data || []);
|
|
4662
4665
|
const filteredFiles = filterImageOnly
|
|
4663
4666
|
? files.filter((file) => /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name))
|
|
4664
4667
|
: files;
|
|
4668
|
+
const handleFileClick = (fileId) => {
|
|
4669
|
+
if (multiple) {
|
|
4670
|
+
const currentSelection = Array.isArray(selectedFileId)
|
|
4671
|
+
? selectedFileId
|
|
4672
|
+
: [];
|
|
4673
|
+
const newSelection = currentSelection.includes(fileId)
|
|
4674
|
+
? currentSelection.filter((id) => id !== fileId)
|
|
4675
|
+
: [...currentSelection, fileId];
|
|
4676
|
+
setSelectedFileId(newSelection);
|
|
4677
|
+
if (onFileSelect) {
|
|
4678
|
+
onFileSelect(newSelection);
|
|
4679
|
+
}
|
|
4680
|
+
}
|
|
4681
|
+
else {
|
|
4682
|
+
setSelectedFileId(fileId);
|
|
4683
|
+
if (onFileSelect) {
|
|
4684
|
+
onFileSelect(fileId);
|
|
4685
|
+
}
|
|
4686
|
+
}
|
|
4687
|
+
};
|
|
4688
|
+
const handleImageError = (fileId) => {
|
|
4689
|
+
setFailedImageIds((prev) => new Set(prev).add(fileId));
|
|
4690
|
+
};
|
|
4691
|
+
if (!onFetchFiles)
|
|
4692
|
+
return null;
|
|
4693
|
+
return (jsxRuntime.jsxs(react.VStack, { align: "stretch", gap: 4, children: [jsxRuntime.jsxs(react.Box, { position: "relative", children: [jsxRuntime.jsx(react.Input, { placeholder: labels?.searchPlaceholder ?? 'Search files...', value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), bg: "bg.panel", border: "1px solid", borderColor: "border.default", colorPalette: "blue", _focus: {
|
|
4694
|
+
borderColor: 'colorPalette.500',
|
|
4695
|
+
_dark: {
|
|
4696
|
+
borderColor: 'colorPalette.400',
|
|
4697
|
+
},
|
|
4698
|
+
boxShadow: {
|
|
4699
|
+
base: '0 0 0 1px var(--chakra-colors-blue-500)',
|
|
4700
|
+
_dark: '0 0 0 1px var(--chakra-colors-blue-400)',
|
|
4701
|
+
},
|
|
4702
|
+
}, pl: 10 }), jsxRuntime.jsx(react.Icon, { as: lu.LuSearch, position: "absolute", left: 3, top: "50%", transform: "translateY(-50%)", color: "fg.muted", boxSize: 4 })] }), isLoading && (jsxRuntime.jsxs(react.Box, { textAlign: "center", py: 8, children: [jsxRuntime.jsx(react.Spinner, { size: "lg", colorPalette: "blue" }), jsxRuntime.jsx(react.Text, { mt: 4, color: "fg.muted", children: labels?.loading ?? 'Loading files...' })] })), isError && (jsxRuntime.jsx(react.Box, { bg: { base: 'colorPalette.50', _dark: 'colorPalette.900/20' }, border: "1px solid", borderColor: {
|
|
4703
|
+
base: 'colorPalette.200',
|
|
4704
|
+
_dark: 'colorPalette.800',
|
|
4705
|
+
}, colorPalette: "red", borderRadius: "md", p: 4, children: jsxRuntime.jsx(react.Text, { color: {
|
|
4706
|
+
base: 'colorPalette.600',
|
|
4707
|
+
_dark: 'colorPalette.300',
|
|
4708
|
+
}, children: labels?.loadingFailed ?? 'Failed to load files' }) })), !isLoading && !isError && (jsxRuntime.jsx(react.Box, { maxHeight: "400px", overflowY: "auto", children: filteredFiles.length === 0 ? (jsxRuntime.jsx(react.Box, { textAlign: "center", py: 8, children: jsxRuntime.jsx(react.Text, { color: "fg.muted", children: labels?.noFilesFound ?? 'No files found' }) })) : (jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: filteredFiles.map((file) => {
|
|
4709
|
+
const isImage = /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name);
|
|
4710
|
+
const isSelected = multiple
|
|
4711
|
+
? Array.isArray(selectedFileId) &&
|
|
4712
|
+
selectedFileId.includes(file.id)
|
|
4713
|
+
: selectedFileId === file.id;
|
|
4714
|
+
const imageFailed = failedImageIds.has(file.id);
|
|
4715
|
+
return (jsxRuntime.jsx(react.Box, { p: 3, border: "2px solid", borderColor: isSelected
|
|
4716
|
+
? {
|
|
4717
|
+
base: 'colorPalette.500',
|
|
4718
|
+
_dark: 'colorPalette.400',
|
|
4719
|
+
}
|
|
4720
|
+
: 'border.default', borderRadius: "md", bg: isSelected
|
|
4721
|
+
? {
|
|
4722
|
+
base: 'colorPalette.50',
|
|
4723
|
+
_dark: 'colorPalette.900/20',
|
|
4724
|
+
}
|
|
4725
|
+
: 'bg.panel', colorPalette: "blue", cursor: "pointer", onClick: () => handleFileClick(file.id), _hover: {
|
|
4726
|
+
borderColor: isSelected
|
|
4727
|
+
? {
|
|
4728
|
+
base: 'colorPalette.600',
|
|
4729
|
+
_dark: 'colorPalette.400',
|
|
4730
|
+
}
|
|
4731
|
+
: {
|
|
4732
|
+
base: 'colorPalette.300',
|
|
4733
|
+
_dark: 'colorPalette.400',
|
|
4734
|
+
},
|
|
4735
|
+
bg: isSelected
|
|
4736
|
+
? {
|
|
4737
|
+
base: 'colorPalette.100',
|
|
4738
|
+
_dark: 'colorPalette.800/30',
|
|
4739
|
+
}
|
|
4740
|
+
: 'bg.muted',
|
|
4741
|
+
}, transition: "all 0.2s", children: jsxRuntime.jsxs(react.HStack, { gap: 3, children: [jsxRuntime.jsx(react.Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, children: isImage && file.url && !imageFailed ? (jsxRuntime.jsx(react.Image, { src: file.url, alt: file.name, boxSize: "60px", objectFit: "cover", borderRadius: "md", onError: () => handleImageError(file.id) })) : isImage && (imageFailed || !file.url) ? (jsxRuntime.jsx(react.Icon, { as: lu.LuImage, boxSize: 6, color: "fg.muted" })) : (jsxRuntime.jsx(react.Icon, { as: lu.LuFile, boxSize: 6, color: "fg.muted" })) }), jsxRuntime.jsxs(react.VStack, { align: "start", flex: 1, gap: 1, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.name }), jsxRuntime.jsxs(react.HStack, { gap: 2, children: [file.size && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: typeof file.size === 'number'
|
|
4742
|
+
? formatBytes(file.size)
|
|
4743
|
+
: file.size }) })), file.comment && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [file.size && (jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: "\u2022" })), jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.comment })] }))] })] }), isSelected && (jsxRuntime.jsx(react.Box, { width: "24px", height: "24px", borderRadius: "full", bg: {
|
|
4744
|
+
base: 'colorPalette.500',
|
|
4745
|
+
_dark: 'colorPalette.400',
|
|
4746
|
+
}, colorPalette: "blue", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, children: jsxRuntime.jsx(react.Text, { color: "white", fontSize: "xs", fontWeight: "bold", children: "\u2713" }) }))] }) }, file.id));
|
|
4747
|
+
}) })) }))] }));
|
|
4748
|
+
};
|
|
4749
|
+
|
|
4750
|
+
function FilePickerDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels, translate, colLabel, }) {
|
|
4751
|
+
const [selectedFileId, setSelectedFileId] = React.useState('');
|
|
4752
|
+
const [activeTab, setActiveTab] = React.useState('browse');
|
|
4753
|
+
const [uploadingFiles, setUploadingFiles] = React.useState(new Set());
|
|
4754
|
+
const [uploadErrors, setUploadErrors] = React.useState(new Map());
|
|
4665
4755
|
const handleSelect = () => {
|
|
4666
4756
|
if (selectedFileId) {
|
|
4667
4757
|
onSelect(selectedFileId);
|
|
4668
4758
|
onClose();
|
|
4669
4759
|
setSelectedFileId('');
|
|
4670
|
-
|
|
4760
|
+
setActiveTab('browse');
|
|
4671
4761
|
}
|
|
4672
4762
|
};
|
|
4673
4763
|
const handleClose = () => {
|
|
4674
4764
|
onClose();
|
|
4675
4765
|
setSelectedFileId('');
|
|
4676
|
-
|
|
4677
|
-
|
|
4766
|
+
setActiveTab('browse');
|
|
4767
|
+
setUploadingFiles(new Set());
|
|
4768
|
+
setUploadErrors(new Map());
|
|
4678
4769
|
};
|
|
4679
|
-
const
|
|
4680
|
-
|
|
4770
|
+
const handleFileUpload = async (files) => {
|
|
4771
|
+
if (!onUploadFile)
|
|
4772
|
+
return;
|
|
4773
|
+
for (const file of files) {
|
|
4774
|
+
const fileKey = `${file.name}-${file.size}`;
|
|
4775
|
+
setUploadingFiles((prev) => new Set(prev).add(fileKey));
|
|
4776
|
+
setUploadErrors((prev) => {
|
|
4777
|
+
const newMap = new Map(prev);
|
|
4778
|
+
newMap.delete(fileKey);
|
|
4779
|
+
return newMap;
|
|
4780
|
+
});
|
|
4781
|
+
try {
|
|
4782
|
+
const fileId = await onUploadFile(file);
|
|
4783
|
+
setSelectedFileId(fileId);
|
|
4784
|
+
setUploadingFiles((prev) => {
|
|
4785
|
+
const newSet = new Set(prev);
|
|
4786
|
+
newSet.delete(fileKey);
|
|
4787
|
+
return newSet;
|
|
4788
|
+
});
|
|
4789
|
+
// Auto-select and close in single-select mode
|
|
4790
|
+
onSelect(fileId);
|
|
4791
|
+
onClose();
|
|
4792
|
+
setSelectedFileId('');
|
|
4793
|
+
setActiveTab('browse');
|
|
4794
|
+
}
|
|
4795
|
+
catch (error) {
|
|
4796
|
+
setUploadingFiles((prev) => {
|
|
4797
|
+
const newSet = new Set(prev);
|
|
4798
|
+
newSet.delete(fileKey);
|
|
4799
|
+
return newSet;
|
|
4800
|
+
});
|
|
4801
|
+
setUploadErrors((prev) => {
|
|
4802
|
+
const newMap = new Map(prev);
|
|
4803
|
+
newMap.set(fileKey, error instanceof Error ? error.message : 'Upload failed');
|
|
4804
|
+
return newMap;
|
|
4805
|
+
});
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4681
4808
|
};
|
|
4682
|
-
|
|
4809
|
+
const showTabs = enableUpload && !!onUploadFile && !!onFetchFiles;
|
|
4810
|
+
if (!onFetchFiles && !onUploadFile)
|
|
4683
4811
|
return null;
|
|
4684
|
-
return (jsxRuntime.jsx(DialogRoot, { open: open, onOpenChange: (e) => !e.open && handleClose(), children: jsxRuntime.jsxs(DialogContent, { maxWidth: "800px", maxHeight: "90vh", children: [jsxRuntime.jsxs(DialogHeader, { children: [jsxRuntime.jsx(DialogTitle, { fontSize: "lg", fontWeight: "bold", children: title }), jsxRuntime.jsx(DialogCloseTrigger, {})] }), jsxRuntime.jsx(DialogBody, { children: jsxRuntime.jsxs(react.
|
|
4685
|
-
translate(removeIndex(`${colLabel}.
|
|
4686
|
-
'
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
_dark: '0 0 0 1px var(--chakra-colors-blue-400)',
|
|
4694
|
-
},
|
|
4695
|
-
}, pl: 10 }), jsxRuntime.jsx(react.Icon, { as: lu.LuSearch, position: "absolute", left: 3, top: "50%", transform: "translateY(-50%)", color: "fg.muted", boxSize: 4 })] }), isLoading && (jsxRuntime.jsxs(react.Box, { textAlign: "center", py: 8, children: [jsxRuntime.jsx(react.Spinner, { size: "lg", colorPalette: "blue" }), jsxRuntime.jsx(react.Text, { mt: 4, color: "fg.muted", children: labels?.loading ??
|
|
4696
|
-
translate(removeIndex(`${colLabel}.loading`)) ??
|
|
4697
|
-
'Loading files...' })] })), isError && (jsxRuntime.jsx(react.Box, { bg: { base: 'colorPalette.50', _dark: 'colorPalette.900/20' }, border: "1px solid", borderColor: {
|
|
4698
|
-
base: 'colorPalette.200',
|
|
4699
|
-
_dark: 'colorPalette.800',
|
|
4700
|
-
}, colorPalette: "red", borderRadius: "md", p: 4, children: jsxRuntime.jsx(react.Text, { color: {
|
|
4701
|
-
base: 'colorPalette.600',
|
|
4702
|
-
_dark: 'colorPalette.300',
|
|
4703
|
-
}, children: labels?.loadingFailed ??
|
|
4704
|
-
translate(removeIndex(`${colLabel}.error.loading_failed`)) ??
|
|
4705
|
-
'Failed to load files' }) })), !isLoading && !isError && (jsxRuntime.jsx(react.Box, { maxHeight: "400px", overflowY: "auto", children: filteredFiles.length === 0 ? (jsxRuntime.jsx(react.Box, { textAlign: "center", py: 8, children: jsxRuntime.jsx(react.Text, { color: "fg.muted", children: labels?.noFilesFound ??
|
|
4706
|
-
translate(removeIndex(`${colLabel}.no_files_found`)) ??
|
|
4707
|
-
'No files found' }) })) : (jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: filteredFiles.map((file) => {
|
|
4708
|
-
const isImage = /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name);
|
|
4709
|
-
const isSelected = selectedFileId === file.id;
|
|
4710
|
-
const imageFailed = failedImageIds.has(file.id);
|
|
4711
|
-
return (jsxRuntime.jsx(react.Box, { p: 3, border: "2px solid", borderColor: isSelected
|
|
4712
|
-
? {
|
|
4713
|
-
base: 'colorPalette.500',
|
|
4714
|
-
_dark: 'colorPalette.400',
|
|
4715
|
-
}
|
|
4716
|
-
: 'border.default', borderRadius: "md", bg: isSelected
|
|
4717
|
-
? {
|
|
4812
|
+
return (jsxRuntime.jsx(DialogRoot, { open: open, onOpenChange: (e) => !e.open && handleClose(), children: jsxRuntime.jsxs(DialogContent, { maxWidth: "800px", maxHeight: "90vh", children: [jsxRuntime.jsxs(DialogHeader, { children: [jsxRuntime.jsx(DialogTitle, { fontSize: "lg", fontWeight: "bold", children: title }), jsxRuntime.jsx(DialogCloseTrigger, {})] }), jsxRuntime.jsx(DialogBody, { children: showTabs ? (jsxRuntime.jsxs(react.Tabs.Root, { value: activeTab, onValueChange: (e) => setActiveTab(e.value ?? 'browse'), children: [jsxRuntime.jsxs(react.Tabs.List, { children: [jsxRuntime.jsx(react.Tabs.Trigger, { value: "browse", children: labels?.browseTab ??
|
|
4813
|
+
translate(removeIndex(`${colLabel}.browse_tab`)) ??
|
|
4814
|
+
'Browse Library' }), jsxRuntime.jsx(react.Tabs.Trigger, { value: "upload", children: labels?.uploadTab ??
|
|
4815
|
+
translate(removeIndex(`${colLabel}.upload_tab`)) ??
|
|
4816
|
+
'Upload Files' })] }), jsxRuntime.jsx(react.Tabs.Content, { value: "browse", children: onFetchFiles && (jsxRuntime.jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open && activeTab === 'browse', selectedFileId: selectedFileId, onSelectedFileIdChange: setSelectedFileId })) }), jsxRuntime.jsx(react.Tabs.Content, { value: "upload", children: jsxRuntime.jsxs(react.VStack, { align: "stretch", gap: 4, children: [jsxRuntime.jsx(FileDropzone, { onDrop: ({ files }) => handleFileUpload(files), placeholder: labels?.fileDropzone ??
|
|
4817
|
+
translate(removeIndex(`${colLabel}.fileDropzone`)) ??
|
|
4818
|
+
'Drop files here or click to upload' }), uploadingFiles.size > 0 && (jsxRuntime.jsx(react.Box, { children: Array.from(uploadingFiles).map((fileKey) => (jsxRuntime.jsx(react.Box, { py: 2, children: jsxRuntime.jsxs(react.HStack, { gap: 2, children: [jsxRuntime.jsx(react.Spinner, { size: "sm", colorPalette: "blue" }), jsxRuntime.jsxs(react.Text, { fontSize: "sm", color: "fg.muted", children: [labels?.uploading ??
|
|
4819
|
+
translate(removeIndex(`${colLabel}.uploading`)) ??
|
|
4820
|
+
'Uploading...', ' ', fileKey.split('-')[0]] })] }) }, fileKey))) })), uploadErrors.size > 0 && (jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: Array.from(uploadErrors.entries()).map(([fileKey, error]) => (jsxRuntime.jsx(react.Box, { bg: {
|
|
4718
4821
|
base: 'colorPalette.50',
|
|
4719
4822
|
_dark: 'colorPalette.900/20',
|
|
4720
|
-
}
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4823
|
+
}, border: "1px solid", borderColor: {
|
|
4824
|
+
base: 'colorPalette.200',
|
|
4825
|
+
_dark: 'colorPalette.800',
|
|
4826
|
+
}, colorPalette: "red", borderRadius: "md", p: 3, children: jsxRuntime.jsxs(react.Text, { fontSize: "sm", color: {
|
|
4724
4827
|
base: 'colorPalette.600',
|
|
4725
|
-
_dark: 'colorPalette.
|
|
4726
|
-
}
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
_dark: 'colorPalette.400',
|
|
4730
|
-
},
|
|
4731
|
-
bg: isSelected
|
|
4732
|
-
? {
|
|
4733
|
-
base: 'colorPalette.100',
|
|
4734
|
-
_dark: 'colorPalette.800/30',
|
|
4735
|
-
}
|
|
4736
|
-
: 'bg.muted',
|
|
4737
|
-
}, transition: "all 0.2s", children: jsxRuntime.jsxs(react.HStack, { gap: 3, children: [jsxRuntime.jsx(react.Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, children: isImage && file.url && !imageFailed ? (jsxRuntime.jsx(react.Image, { src: file.url, alt: file.name, boxSize: "60px", objectFit: "cover", borderRadius: "md", onError: () => handleImageError(file.id) })) : isImage && (imageFailed || !file.url) ? (jsxRuntime.jsx(react.Icon, { as: lu.LuImage, boxSize: 6, color: "fg.muted" })) : (jsxRuntime.jsx(react.Icon, { as: lu.LuFile, boxSize: 6, color: "fg.muted" })) }), jsxRuntime.jsxs(react.VStack, { align: "start", flex: 1, gap: 1, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.name }), jsxRuntime.jsxs(react.HStack, { gap: 2, children: [file.size && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: typeof file.size === 'number'
|
|
4738
|
-
? formatBytes(file.size)
|
|
4739
|
-
: file.size }) })), file.comment && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [file.size && (jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: "\u2022" })), jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.comment })] }))] })] }), isSelected && (jsxRuntime.jsx(react.Box, { width: "24px", height: "24px", borderRadius: "full", bg: {
|
|
4740
|
-
base: 'colorPalette.500',
|
|
4741
|
-
_dark: 'colorPalette.400',
|
|
4742
|
-
}, colorPalette: "blue", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, children: jsxRuntime.jsx(react.Text, { color: "white", fontSize: "xs", fontWeight: "bold", children: "\u2713" }) }))] }) }, file.id));
|
|
4743
|
-
}) })) }))] }) }), jsxRuntime.jsx(DialogFooter, { children: jsxRuntime.jsxs(react.HStack, { gap: 3, justify: "end", children: [jsxRuntime.jsx(react.Button, { variant: "outline", onClick: handleClose, borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: labels?.cancel ??
|
|
4828
|
+
_dark: 'colorPalette.300',
|
|
4829
|
+
}, children: [fileKey.split('-')[0], ":", ' ', labels?.uploadFailed ??
|
|
4830
|
+
translate(removeIndex(`${colLabel}.upload_failed`)) ??
|
|
4831
|
+
'Upload failed', error && ` - ${error}`] }) }, fileKey))) }))] }) })] })) : onFetchFiles ? (jsxRuntime.jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open, selectedFileId: selectedFileId, onSelectedFileIdChange: setSelectedFileId })) : null }), jsxRuntime.jsx(DialogFooter, { children: jsxRuntime.jsxs(react.HStack, { gap: 3, justify: "end", children: [jsxRuntime.jsx(react.Button, { variant: "outline", onClick: handleClose, borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: labels?.cancel ??
|
|
4744
4832
|
translate(removeIndex(`${colLabel}.cancel`)) ??
|
|
4745
4833
|
'Cancel' }), jsxRuntime.jsx(react.Button, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFileId, children: labels?.select ??
|
|
4746
4834
|
translate(removeIndex(`${colLabel}.select`)) ??
|
|
@@ -4750,84 +4838,71 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
4750
4838
|
const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
|
|
4751
4839
|
const { filePickerLabels } = useSchemaContext();
|
|
4752
4840
|
const formI18n = useFormI18n(column, prefix);
|
|
4753
|
-
const { required, gridColumn = 'span 12', gridRow = 'span 1',
|
|
4841
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', type, } = schema;
|
|
4754
4842
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4755
|
-
const
|
|
4756
|
-
const
|
|
4757
|
-
|
|
4758
|
-
|
|
4843
|
+
const isSingleSelect = type === 'string';
|
|
4844
|
+
const currentValue = watch(column) ?? (isSingleSelect ? '' : []);
|
|
4845
|
+
// Handle File objects only
|
|
4846
|
+
const currentFiles = isSingleSelect
|
|
4847
|
+
? currentValue && currentValue instanceof File
|
|
4848
|
+
? [currentValue]
|
|
4849
|
+
: []
|
|
4850
|
+
: Array.isArray(currentValue)
|
|
4851
|
+
? currentValue.filter((f) => f instanceof File)
|
|
4852
|
+
: [];
|
|
4759
4853
|
const colLabel = formI18n.colLabel;
|
|
4760
|
-
const [dialogOpen, setDialogOpen] = React.useState(false);
|
|
4761
4854
|
const [failedImageIds, setFailedImageIds] = React.useState(new Set());
|
|
4762
|
-
|
|
4763
|
-
const showMediaLibrary = enableMediaLibrary && !!onFetchFiles;
|
|
4855
|
+
// FilePicker variant: Only handle File objects, no media library browser
|
|
4764
4856
|
const handleImageError = (fileIdentifier) => {
|
|
4765
4857
|
setFailedImageIds((prev) => new Set(prev).add(fileIdentifier));
|
|
4766
4858
|
};
|
|
4767
|
-
const handleMediaLibrarySelect = (fileId) => {
|
|
4768
|
-
const newFiles = [...currentFiles, fileId];
|
|
4769
|
-
setValue(colLabel, newFiles);
|
|
4770
|
-
};
|
|
4771
4859
|
const handleRemove = (index) => {
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4860
|
+
if (isSingleSelect) {
|
|
4861
|
+
setValue(colLabel, '');
|
|
4862
|
+
}
|
|
4863
|
+
else {
|
|
4864
|
+
const newFiles = currentFiles.filter((_, i) => i !== index);
|
|
4865
|
+
setValue(colLabel, newFiles);
|
|
4866
|
+
}
|
|
4777
4867
|
};
|
|
4778
4868
|
const getFileIdentifier = (file, index) => {
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
}
|
|
4782
|
-
return file;
|
|
4869
|
+
// file-picker: file is a File object, create identifier from name and size
|
|
4870
|
+
return `${file.name}-${file.size}-${index}`;
|
|
4783
4871
|
};
|
|
4784
4872
|
const getFileName = (file) => {
|
|
4785
|
-
|
|
4786
|
-
return file.name;
|
|
4787
|
-
}
|
|
4788
|
-
return typeof file === 'string' ? file : 'Unknown file';
|
|
4873
|
+
return file.name;
|
|
4789
4874
|
};
|
|
4790
4875
|
const getFileSize = (file) => {
|
|
4791
|
-
|
|
4792
|
-
return file.size;
|
|
4793
|
-
}
|
|
4794
|
-
return undefined;
|
|
4876
|
+
return file.size;
|
|
4795
4877
|
};
|
|
4796
4878
|
const isImageFile = (file) => {
|
|
4797
|
-
|
|
4798
|
-
return file.type.startsWith('image/');
|
|
4799
|
-
}
|
|
4800
|
-
if (typeof file === 'string') {
|
|
4801
|
-
return /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file);
|
|
4802
|
-
}
|
|
4803
|
-
return false;
|
|
4879
|
+
return file.type.startsWith('image/');
|
|
4804
4880
|
};
|
|
4805
4881
|
const getImageUrl = (file) => {
|
|
4806
|
-
|
|
4807
|
-
return URL.createObjectURL(file);
|
|
4808
|
-
}
|
|
4809
|
-
return undefined;
|
|
4882
|
+
return URL.createObjectURL(file);
|
|
4810
4883
|
};
|
|
4811
4884
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4812
|
-
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsxRuntime.
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
}
|
|
4885
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: jsxRuntime.jsx(FileDropzone, { onDrop: ({ files }) => {
|
|
4886
|
+
// file-picker variant: Store File objects directly (no ID conversion)
|
|
4887
|
+
if (isSingleSelect) {
|
|
4888
|
+
// In single-select mode, use the first file and replace any existing file
|
|
4889
|
+
if (files.length > 0) {
|
|
4890
|
+
setValue(colLabel, files[0]);
|
|
4891
|
+
}
|
|
4892
|
+
}
|
|
4893
|
+
else {
|
|
4894
|
+
// In multi-select mode, filter duplicates and append
|
|
4895
|
+
const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
|
|
4819
4896
|
setValue(colLabel, [...currentFiles, ...newFiles]);
|
|
4820
|
-
}
|
|
4821
|
-
|
|
4822
|
-
'Browse from Library' }))] }), showMediaLibrary && (jsxRuntime.jsx(FilePickerDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
|
|
4823
|
-
formI18n.t('dialog_title') ??
|
|
4824
|
-
'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, labels: filePickerLabels, translate: formI18n.t, colLabel: colLabel })), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file, index) => {
|
|
4897
|
+
}
|
|
4898
|
+
}, placeholder: filePickerLabels?.fileDropzone ?? formI18n.t('fileDropzone') }) }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file, index) => {
|
|
4825
4899
|
const fileIdentifier = getFileIdentifier(file, index);
|
|
4826
4900
|
const fileName = getFileName(file);
|
|
4827
4901
|
const fileSize = getFileSize(file);
|
|
4828
4902
|
const isImage = isImageFile(file);
|
|
4829
4903
|
const imageUrl = getImageUrl(file);
|
|
4830
4904
|
const imageFailed = failedImageIds.has(fileIdentifier);
|
|
4905
|
+
// File Viewer
|
|
4831
4906
|
return (jsxRuntime.jsx(react.Card.Root, { variant: 'subtle', colorPalette: "blue", children: jsxRuntime.jsxs(react.Card.Body, { gap: "2", cursor: 'pointer', onClick: () => handleRemove(index), display: 'flex', flexFlow: 'row', alignItems: 'center', padding: '2', border: "2px solid", borderColor: "border.default", borderRadius: "md", _hover: {
|
|
4832
4907
|
borderColor: 'colorPalette.300',
|
|
4833
4908
|
bg: 'bg.muted',
|
|
@@ -4835,6 +4910,66 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
4835
4910
|
}) })] }));
|
|
4836
4911
|
};
|
|
4837
4912
|
|
|
4913
|
+
const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
4914
|
+
const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
|
|
4915
|
+
const { filePickerLabels } = useSchemaContext();
|
|
4916
|
+
const formI18n = useFormI18n(column, prefix);
|
|
4917
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, type, } = schema;
|
|
4918
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
4919
|
+
const isSingleSelect = type === 'string';
|
|
4920
|
+
const currentValue = watch(column) ?? (isSingleSelect ? '' : []);
|
|
4921
|
+
// Handle string IDs only
|
|
4922
|
+
const currentFileIds = isSingleSelect
|
|
4923
|
+
? currentValue
|
|
4924
|
+
? [currentValue]
|
|
4925
|
+
: []
|
|
4926
|
+
: Array.isArray(currentValue)
|
|
4927
|
+
? currentValue
|
|
4928
|
+
: [];
|
|
4929
|
+
const colLabel = formI18n.colLabel;
|
|
4930
|
+
const [dialogOpen, setDialogOpen] = React.useState(false);
|
|
4931
|
+
const [failedImageIds, setFailedImageIds] = React.useState(new Set());
|
|
4932
|
+
const { onFetchFiles, filterImageOnly = false, enableUpload = false, onUploadFile, } = filePicker || {};
|
|
4933
|
+
if (!onFetchFiles) {
|
|
4934
|
+
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4935
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsx(react.Text, { color: "fg.muted", children: "Media library browser requires onFetchFiles" }) }));
|
|
4936
|
+
}
|
|
4937
|
+
const handleMediaLibrarySelect = (fileId) => {
|
|
4938
|
+
if (isSingleSelect) {
|
|
4939
|
+
setValue(colLabel, fileId);
|
|
4940
|
+
}
|
|
4941
|
+
else {
|
|
4942
|
+
const newFileIds = [...currentFileIds, fileId];
|
|
4943
|
+
setValue(colLabel, newFileIds);
|
|
4944
|
+
}
|
|
4945
|
+
};
|
|
4946
|
+
const handleRemove = (index) => {
|
|
4947
|
+
if (isSingleSelect) {
|
|
4948
|
+
setValue(colLabel, '');
|
|
4949
|
+
}
|
|
4950
|
+
else {
|
|
4951
|
+
const newFileIds = currentFileIds.filter((_, i) => i !== index);
|
|
4952
|
+
setValue(colLabel, newFileIds);
|
|
4953
|
+
}
|
|
4954
|
+
};
|
|
4955
|
+
const isImageId = (fileId) => {
|
|
4956
|
+
return /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(fileId);
|
|
4957
|
+
};
|
|
4958
|
+
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4959
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: jsxRuntime.jsx(react.Button, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ??
|
|
4960
|
+
formI18n.t('browse_library') ??
|
|
4961
|
+
'Browse from Library' }) }), jsxRuntime.jsx(FilePickerDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
|
|
4962
|
+
formI18n.t('dialog_title') ??
|
|
4963
|
+
'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels, translate: formI18n.t, colLabel: colLabel }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
|
|
4964
|
+
const isImage = isImageId(fileId);
|
|
4965
|
+
const imageFailed = failedImageIds.has(fileId);
|
|
4966
|
+
return (jsxRuntime.jsx(react.Card.Root, { variant: 'subtle', colorPalette: "blue", children: jsxRuntime.jsxs(react.Card.Body, { gap: "2", cursor: 'pointer', onClick: () => handleRemove(index), display: 'flex', flexFlow: 'row', alignItems: 'center', padding: '2', border: "2px solid", borderColor: "border.default", borderRadius: "md", _hover: {
|
|
4967
|
+
borderColor: 'colorPalette.300',
|
|
4968
|
+
bg: 'bg.muted',
|
|
4969
|
+
}, transition: "all 0.2s", children: [jsxRuntime.jsx(react.Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, marginRight: "2", children: isImage && !imageFailed ? (jsxRuntime.jsx(react.Icon, { as: lu.LuImage, boxSize: 6, color: "fg.muted" })) : (jsxRuntime.jsx(react.Icon, { as: lu.LuFile, boxSize: 6, color: "fg.muted" })) }), jsxRuntime.jsx(react.VStack, { align: "start", flex: 1, gap: 1, children: jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileId }) }), jsxRuntime.jsx(react.Icon, { as: ti.TiDeleteOutline, boxSize: 5, color: "fg.muted" })] }) }, `${fileId}-${index}`));
|
|
4970
|
+
}) })] }));
|
|
4971
|
+
};
|
|
4972
|
+
|
|
4838
4973
|
const ToggleTip = React__namespace.forwardRef(function ToggleTip(props, ref) {
|
|
4839
4974
|
const { showArrow, children, portalled = true, content, portalRef, ...rest } = props;
|
|
4840
4975
|
return (jsxRuntime.jsxs(react.Popover.Root, { ...rest, positioning: { ...rest.positioning, gutter: 4 }, children: [jsxRuntime.jsx(react.Popover.Trigger, { asChild: true, children: children }), jsxRuntime.jsx(react.Portal, { disabled: !portalled, container: portalRef, children: jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsxs(react.Popover.Content, { width: "auto", px: "2", py: "1", textStyle: "xs", rounded: "sm", ref: ref, children: [showArrow && (jsxRuntime.jsx(react.Popover.Arrow, { children: jsxRuntime.jsx(react.Popover.ArrowTip, {}) })), content] }) }) })] }));
|
|
@@ -6025,6 +6160,9 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
6025
6160
|
if (variant === 'file-picker') {
|
|
6026
6161
|
return jsxRuntime.jsx(FilePicker, { schema: colSchema, prefix, column });
|
|
6027
6162
|
}
|
|
6163
|
+
if (variant === 'media-library-browser') {
|
|
6164
|
+
return (jsxRuntime.jsx(FormMediaLibraryBrowser, { schema: colSchema, prefix, column }));
|
|
6165
|
+
}
|
|
6028
6166
|
if (variant === 'date-range') {
|
|
6029
6167
|
return jsxRuntime.jsx(DateRangePicker, { schema: colSchema, prefix, column });
|
|
6030
6168
|
}
|
|
@@ -6416,59 +6554,62 @@ const DateTimeViewer = ({ column, schema, prefix }) => {
|
|
|
6416
6554
|
const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
6417
6555
|
const colSchema = schema;
|
|
6418
6556
|
const { type, variant, properties: innerProperties, foreign_key, items, format, } = schema;
|
|
6419
|
-
if (variant ===
|
|
6557
|
+
if (variant === 'custom-input') {
|
|
6420
6558
|
return jsxRuntime.jsx(CustomViewer, { schema: colSchema, prefix, column });
|
|
6421
6559
|
}
|
|
6422
|
-
if (type ===
|
|
6560
|
+
if (type === 'string') {
|
|
6423
6561
|
if ((schema.enum ?? []).length > 0) {
|
|
6424
6562
|
return jsxRuntime.jsx(EnumViewer, { schema: colSchema, prefix, column });
|
|
6425
6563
|
}
|
|
6426
|
-
if (variant ===
|
|
6564
|
+
if (variant === 'id-picker') {
|
|
6427
6565
|
idPickerSanityCheck(column, foreign_key);
|
|
6428
6566
|
return jsxRuntime.jsx(IdViewer, { schema: colSchema, prefix, column });
|
|
6429
6567
|
}
|
|
6430
|
-
if (format ===
|
|
6568
|
+
if (format === 'time') {
|
|
6431
6569
|
return jsxRuntime.jsx(TimeViewer, { schema: colSchema, prefix, column });
|
|
6432
6570
|
}
|
|
6433
|
-
if (format ===
|
|
6571
|
+
if (format === 'date') {
|
|
6434
6572
|
return jsxRuntime.jsx(DateViewer, { schema: colSchema, prefix, column });
|
|
6435
6573
|
}
|
|
6436
|
-
if (format ===
|
|
6574
|
+
if (format === 'date-time') {
|
|
6437
6575
|
return jsxRuntime.jsx(DateTimeViewer, { schema: colSchema, prefix, column });
|
|
6438
6576
|
}
|
|
6439
|
-
if (variant ===
|
|
6577
|
+
if (variant === 'text-area') {
|
|
6440
6578
|
return jsxRuntime.jsx(TextAreaViewer, { schema: colSchema, prefix, column });
|
|
6441
6579
|
}
|
|
6442
6580
|
return jsxRuntime.jsx(StringViewer, { schema: colSchema, prefix, column });
|
|
6443
6581
|
}
|
|
6444
|
-
if (type ===
|
|
6582
|
+
if (type === 'number' || type === 'integer') {
|
|
6445
6583
|
return jsxRuntime.jsx(NumberViewer, { schema: colSchema, prefix, column });
|
|
6446
6584
|
}
|
|
6447
|
-
if (type ===
|
|
6585
|
+
if (type === 'boolean') {
|
|
6448
6586
|
return jsxRuntime.jsx(BooleanViewer, { schema: colSchema, prefix, column });
|
|
6449
6587
|
}
|
|
6450
|
-
if (type ===
|
|
6588
|
+
if (type === 'object') {
|
|
6451
6589
|
if (innerProperties) {
|
|
6452
6590
|
return jsxRuntime.jsx(ObjectViewer, { schema: colSchema, prefix, column });
|
|
6453
6591
|
}
|
|
6454
6592
|
return jsxRuntime.jsx(RecordInput, { schema: colSchema, prefix, column });
|
|
6455
6593
|
}
|
|
6456
|
-
if (type ===
|
|
6457
|
-
if (variant ===
|
|
6594
|
+
if (type === 'array') {
|
|
6595
|
+
if (variant === 'id-picker') {
|
|
6458
6596
|
idPickerSanityCheck(column, foreign_key);
|
|
6459
6597
|
return (jsxRuntime.jsx(IdViewer, { schema: colSchema, prefix, column, isMultiple: true }));
|
|
6460
6598
|
}
|
|
6461
|
-
if (variant ===
|
|
6599
|
+
if (variant === 'tag-picker') {
|
|
6462
6600
|
return jsxRuntime.jsx(TagViewer, { schema: colSchema, prefix, column });
|
|
6463
6601
|
}
|
|
6464
|
-
if (variant ===
|
|
6602
|
+
if (variant === 'file-picker') {
|
|
6603
|
+
return jsxRuntime.jsx(FileViewer, { schema: colSchema, prefix, column });
|
|
6604
|
+
}
|
|
6605
|
+
if (variant === 'media-library-browser') {
|
|
6465
6606
|
return jsxRuntime.jsx(FileViewer, { schema: colSchema, prefix, column });
|
|
6466
6607
|
}
|
|
6467
|
-
if (variant ===
|
|
6608
|
+
if (variant === 'enum-picker') {
|
|
6468
6609
|
const { items } = schema;
|
|
6469
6610
|
const { enum: enumItems } = items;
|
|
6470
6611
|
const enumSchema = {
|
|
6471
|
-
type:
|
|
6612
|
+
type: 'string',
|
|
6472
6613
|
enum: enumItems,
|
|
6473
6614
|
};
|
|
6474
6615
|
return (jsxRuntime.jsx(EnumViewer, { isMultiple: true, schema: enumSchema, prefix, column }));
|
|
@@ -6478,7 +6619,7 @@ const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
|
6478
6619
|
}
|
|
6479
6620
|
return jsxRuntime.jsx(react.Text, { children: `array ${column}` });
|
|
6480
6621
|
}
|
|
6481
|
-
if (type ===
|
|
6622
|
+
if (type === 'null') {
|
|
6482
6623
|
return jsxRuntime.jsx(react.Text, { children: `null ${column}` });
|
|
6483
6624
|
}
|
|
6484
6625
|
return jsxRuntime.jsx(react.Text, { children: "missing type" });
|
|
@@ -7409,6 +7550,7 @@ exports.FormBody = FormBody;
|
|
|
7409
7550
|
exports.FormRoot = FormRoot;
|
|
7410
7551
|
exports.FormTitle = FormTitle;
|
|
7411
7552
|
exports.GlobalFilter = GlobalFilter;
|
|
7553
|
+
exports.MediaLibraryBrowser = MediaLibraryBrowser;
|
|
7412
7554
|
exports.PageSizeControl = PageSizeControl;
|
|
7413
7555
|
exports.Pagination = Pagination;
|
|
7414
7556
|
exports.RecordDisplay = RecordDisplay;
|