react-ui-suite 1.1.3 → 1.1.4

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 CHANGED
@@ -197,13 +197,22 @@ type DropdownProps = {
197
197
  declare const Dropdown: React.ForwardRefExoticComponent<DropdownProps & React.RefAttributes<HTMLDivElement>>;
198
198
 
199
199
  type NativeInputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "type">;
200
+ type FilePickerMode = "path" | "content" | "both";
201
+ type FileSelection = {
202
+ file: File;
203
+ path?: string;
204
+ text?: string;
205
+ bytes?: Uint8Array;
206
+ };
200
207
  type FilePickerProps = NativeInputProps & {
201
208
  label?: string;
202
209
  description?: string;
203
210
  error?: string;
204
211
  dropzoneLabel?: string;
205
212
  maxFiles?: number;
206
- onFilesChange?: (files: File[]) => void;
213
+ mode?: FilePickerMode;
214
+ resolvePath?: (file: File) => string | undefined | Promise<string | undefined>;
215
+ onFilesChange?: (files: FileSelection[]) => void;
207
216
  };
208
217
  declare const FilePicker: React.ForwardRefExoticComponent<NativeInputProps & {
209
218
  label?: string;
@@ -211,7 +220,9 @@ declare const FilePicker: React.ForwardRefExoticComponent<NativeInputProps & {
211
220
  error?: string;
212
221
  dropzoneLabel?: string;
213
222
  maxFiles?: number;
214
- onFilesChange?: (files: File[]) => void;
223
+ mode?: FilePickerMode;
224
+ resolvePath?: (file: File) => string | undefined | Promise<string | undefined>;
225
+ onFilesChange?: (files: FileSelection[]) => void;
215
226
  } & React.RefAttributes<HTMLInputElement>>;
216
227
 
217
228
  type InputFieldProps = React.InputHTMLAttributes<HTMLInputElement> & {
@@ -530,4 +541,4 @@ declare const Toggle: React.ForwardRefExoticComponent<Omit<React.ButtonHTMLAttri
530
541
  onChange?: (checked: boolean) => void;
531
542
  } & React.RefAttributes<HTMLButtonElement>>;
532
543
 
533
- export { Alert, type AlertProps, type AlertVariant, Badge, type BadgeProps, type BadgeVariant, Button, type ButtonProps, Card, type CardProps, Checkbox, type CheckboxProps, ColorPicker, type ColorPickerProps, Combobox, type ComboboxOption, type ComboboxProps, type ComboboxRenderState, DatalistInput, type DatalistInputProps, DatePicker, type DatePickerProps, Dialog, type DialogProps, Disclosure, type DisclosureProps, Dropdown, type DropdownProps, FilePicker, type FilePickerProps, InputField, type InputFieldProps, Meter, type MeterProps, NumberInput, type NumberInputProps, OutputChip, type OutputChipProps, Popover, type PopoverProps, Progress, type ProgressProps, Radio, type RadioColor, type RadioProps, ResizableContainer, type ResizableContainerProps, Select, type SelectOption, type SelectProps, Slider, type SliderProps, StackedList, type StackedListItem, type StackedListProps, TabGroup, TabGroupAlign, TabGroupFill, TabGroupPosition, type TabGroupProps, TabGroupRotation, type TabGroupTab, Table, type TableColumn, type TableProps, Textarea, type TextareaProps, Toggle, type ToggleProps };
544
+ export { Alert, type AlertProps, type AlertVariant, Badge, type BadgeProps, type BadgeVariant, Button, type ButtonProps, Card, type CardProps, Checkbox, type CheckboxProps, ColorPicker, type ColorPickerProps, Combobox, type ComboboxOption, type ComboboxProps, type ComboboxRenderState, DatalistInput, type DatalistInputProps, DatePicker, type DatePickerProps, Dialog, type DialogProps, Disclosure, type DisclosureProps, Dropdown, type DropdownProps, FilePicker, type FilePickerMode, type FilePickerProps, type FileSelection, InputField, type InputFieldProps, Meter, type MeterProps, NumberInput, type NumberInputProps, OutputChip, type OutputChipProps, Popover, type PopoverProps, Progress, type ProgressProps, Radio, type RadioColor, type RadioProps, ResizableContainer, type ResizableContainerProps, Select, type SelectOption, type SelectProps, Slider, type SliderProps, StackedList, type StackedListItem, type StackedListProps, TabGroup, TabGroupAlign, TabGroupFill, TabGroupPosition, type TabGroupProps, TabGroupRotation, type TabGroupTab, Table, type TableColumn, type TableProps, Textarea, type TextareaProps, Toggle, type ToggleProps };
package/dist/index.js CHANGED
@@ -2820,12 +2820,55 @@ function formatBytes(bytes) {
2820
2820
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
2821
2821
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
2822
2822
  }
2823
+ function decodeUtf8IfPossible(bytes) {
2824
+ try {
2825
+ const decoder = new TextDecoder("utf-8", { fatal: true });
2826
+ return decoder.decode(bytes);
2827
+ } catch {
2828
+ return void 0;
2829
+ }
2830
+ }
2831
+ async function derivePath(file, resolvePath) {
2832
+ const resolved = await (resolvePath == null ? void 0 : resolvePath(file));
2833
+ if (resolved) return resolved;
2834
+ const fileWithPath = file;
2835
+ if (typeof fileWithPath.path === "string" && fileWithPath.path.length > 0) {
2836
+ return fileWithPath.path;
2837
+ }
2838
+ if (typeof fileWithPath.webkitRelativePath === "string" && fileWithPath.webkitRelativePath.length > 0) {
2839
+ return fileWithPath.webkitRelativePath;
2840
+ }
2841
+ return void 0;
2842
+ }
2843
+ async function readFileBytes(file) {
2844
+ const fileWithArrayBuffer = file;
2845
+ if (typeof fileWithArrayBuffer.arrayBuffer === "function") {
2846
+ return new Uint8Array(await fileWithArrayBuffer.arrayBuffer());
2847
+ }
2848
+ if (typeof Blob !== "undefined" && typeof Blob.prototype.arrayBuffer === "function") {
2849
+ return new Uint8Array(await Blob.prototype.arrayBuffer.call(file));
2850
+ }
2851
+ if (typeof FileReader !== "undefined") {
2852
+ return await new Promise((resolve) => {
2853
+ const reader = new FileReader();
2854
+ reader.onload = () => {
2855
+ const result = reader.result;
2856
+ resolve(result instanceof ArrayBuffer ? new Uint8Array(result) : void 0);
2857
+ };
2858
+ reader.onerror = () => resolve(void 0);
2859
+ reader.readAsArrayBuffer(file);
2860
+ });
2861
+ }
2862
+ return void 0;
2863
+ }
2823
2864
  var FilePicker = React15.forwardRef(function FilePicker2({
2824
2865
  label,
2825
2866
  description,
2826
2867
  error,
2827
2868
  dropzoneLabel = "Drop files here or click to browse",
2828
2869
  maxFiles,
2870
+ mode = "path",
2871
+ resolvePath,
2829
2872
  id,
2830
2873
  className,
2831
2874
  accept,
@@ -2843,6 +2886,7 @@ var FilePicker = React15.forwardRef(function FilePicker2({
2843
2886
  const [selectedFiles, setSelectedFiles] = React15.useState([]);
2844
2887
  const [restrictedCount, setRestrictedCount] = React15.useState(0);
2845
2888
  const inputRef = React15.useRef(null);
2889
+ const selectionRequestIdRef = React15.useRef(0);
2846
2890
  const setRefs = React15.useCallback(
2847
2891
  (node) => {
2848
2892
  inputRef.current = node;
@@ -2861,22 +2905,43 @@ var FilePicker = React15.forwardRef(function FilePicker2({
2861
2905
  return Math.max(1, Math.floor(maxFiles));
2862
2906
  }, [maxFiles]);
2863
2907
  const applySelectedFiles = React15.useCallback(
2864
- (files) => {
2908
+ async (files) => {
2865
2909
  const acceptedFiles = filterFilesByAccept(files, accept);
2866
2910
  const selectionLimit = multiple ? resolvedMaxFiles != null ? resolvedMaxFiles : Infinity : 1;
2867
2911
  const nextFiles = acceptedFiles.slice(0, selectionLimit);
2868
2912
  const nextRestrictedCount = files.length - nextFiles.length;
2869
- setSelectedFiles(nextFiles);
2913
+ const requestId = selectionRequestIdRef.current + 1;
2914
+ selectionRequestIdRef.current = requestId;
2915
+ const nextSelections = await Promise.all(
2916
+ nextFiles.map(async (file) => {
2917
+ const selection = { file };
2918
+ if (mode === "path" || mode === "both") {
2919
+ selection.path = await derivePath(file, resolvePath);
2920
+ }
2921
+ if (mode === "content" || mode === "both") {
2922
+ const bytes = await readFileBytes(file);
2923
+ if (bytes) {
2924
+ selection.bytes = bytes;
2925
+ selection.text = decodeUtf8IfPossible(bytes);
2926
+ }
2927
+ }
2928
+ return selection;
2929
+ })
2930
+ );
2931
+ if (selectionRequestIdRef.current !== requestId) {
2932
+ return [];
2933
+ }
2934
+ setSelectedFiles(nextSelections);
2870
2935
  setRestrictedCount(nextRestrictedCount);
2871
- onFilesChange == null ? void 0 : onFilesChange(nextFiles);
2872
- return nextFiles;
2936
+ onFilesChange == null ? void 0 : onFilesChange(nextSelections);
2937
+ return nextSelections;
2873
2938
  },
2874
- [accept, multiple, onFilesChange, resolvedMaxFiles]
2939
+ [accept, mode, multiple, onFilesChange, resolvePath, resolvedMaxFiles]
2875
2940
  );
2876
2941
  const handleInputChange = (event) => {
2877
2942
  var _a;
2878
2943
  const incomingFiles = Array.from((_a = event.target.files) != null ? _a : []);
2879
- applySelectedFiles(incomingFiles);
2944
+ void applySelectedFiles(incomingFiles);
2880
2945
  onChange == null ? void 0 : onChange(event);
2881
2946
  };
2882
2947
  const openFileDialog = () => {
@@ -2892,7 +2957,7 @@ var FilePicker = React15.forwardRef(function FilePicker2({
2892
2957
  if (disabled) return;
2893
2958
  setIsDragActive(false);
2894
2959
  const files = Array.from((_a = event.dataTransfer.files) != null ? _a : []);
2895
- applySelectedFiles(files);
2960
+ void applySelectedFiles(files);
2896
2961
  };
2897
2962
  const hasSelection = selectedFiles.length > 0;
2898
2963
  return /* @__PURE__ */ jsxs15("div", { className: "rui-file-picker rui-root", children: [
@@ -2954,10 +3019,17 @@ var FilePicker = React15.forwardRef(function FilePicker2({
2954
3019
  "Maximum files: ",
2955
3020
  resolvedMaxFiles
2956
3021
  ] }) : null,
2957
- hasSelection ? /* @__PURE__ */ jsx17("ul", { className: "rui-file-picker__list", "aria-label": "Selected files", children: selectedFiles.map((file) => /* @__PURE__ */ jsxs15("li", { className: "rui-file-picker__item", children: [
2958
- /* @__PURE__ */ jsx17("span", { className: "rui-file-picker__file-name rui-text-wrap", children: file.name }),
2959
- /* @__PURE__ */ jsx17("span", { className: "rui-file-picker__file-meta", children: formatBytes(file.size) })
2960
- ] }, `${file.name}-${file.size}-${file.lastModified}`)) }) : null
3022
+ hasSelection ? /* @__PURE__ */ jsx17("ul", { className: "rui-file-picker__list", "aria-label": "Selected files", children: selectedFiles.map((selection) => /* @__PURE__ */ jsxs15(
3023
+ "li",
3024
+ {
3025
+ className: "rui-file-picker__item",
3026
+ children: [
3027
+ /* @__PURE__ */ jsx17("span", { className: "rui-file-picker__file-name rui-text-wrap", children: selection.file.name }),
3028
+ /* @__PURE__ */ jsx17("span", { className: "rui-file-picker__file-meta", children: formatBytes(selection.file.size) })
3029
+ ]
3030
+ },
3031
+ `${selection.file.name}-${selection.file.size}-${selection.file.lastModified}`
3032
+ )) }) : null
2961
3033
  ]
2962
3034
  }
2963
3035
  ),