@alextheman/components 6.26.0 → 7.0.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/Tab/TabItem.tsx","../../src/Tab/TabProvider.tsx","../../src/Tab/TabList.tsx","../../src/Tab/TabPanel.tsx","../../src/Tab/createTabGroup.tsx"],"sourcesContent":["import type { TabProps } from \"@mui/material/Tab\";\n\nimport Tab from \"@mui/material/Tab\";\n\nexport interface TabItemProps<TabState extends string = string> extends Omit<TabProps, \"value\"> {\n value: TabState;\n}\n\n/**\n * Renders a tab to be used within a `TabProvider`\n *\n * @template TabState The possible values for the tab.\n */\nfunction TabItem<TabState extends string = string>({\n label,\n value,\n ...tabProps\n}: TabItemProps<TabState>) {\n return <Tab label={label ?? value} value={value} {...tabProps} />;\n}\n\nexport default TabItem;\n","import type { OptionalOnCondition } from \"@alextheman/utility\";\nimport type { Dispatch, ReactNode, SetStateAction } from \"react\";\n\nimport type { ContextHookOptions } from \"src/root\";\n\nimport { DataError } from \"@alextheman/utility/v6\";\nimport { createContext, use } from \"react\";\n\nexport interface TabContextValue<TabState extends string = string> {\n tab: TabState;\n setTab: Dispatch<SetStateAction<TabState>>;\n}\n\nexport interface TabProviderProps<\n TabState extends string = string,\n> extends TabContextValue<TabState> {\n children: ReactNode;\n}\n\nexport const TabContext = createContext<TabContextValue<any> | undefined>(undefined);\n/** Access the TabContext directly. */\nexport function useTabContext<TabState extends string = string, Strict extends boolean = true>({\n strict = true as Strict,\n}: ContextHookOptions<Strict> = {}): OptionalOnCondition<Strict, TabContextValue<TabState>> {\n const context = use(TabContext);\n if (strict && !context) {\n throw new DataError(\n { strict, context },\n \"TAB_PROVIDER_NOT_FOUND\",\n \"Could not find the TabProvider. Please double-check that it is present.\",\n );\n }\n return context as OptionalOnCondition<Strict, TabContextValue<TabState>>;\n}\n\n/**\n * A provider for a context that manages tab grouping.\n *\n * @template TabState The possible values for the tab.\n */\nfunction TabProvider<TabState extends string = string>({\n children,\n tab,\n setTab,\n}: TabProviderProps<TabState>) {\n return <TabContext value={{ tab, setTab }}>{children}</TabContext>;\n}\n\nexport default TabProvider;\n","import type { TabsProps } from \"@mui/material/Tabs\";\nimport type { ReactNode } from \"react\";\n\nimport Tabs from \"@mui/material/Tabs\";\n\nimport { useTabContext } from \"src/Tab/TabProvider\";\n\nexport interface TabListProps extends Omit<TabsProps, \"value\"> {\n children: ReactNode;\n}\n\n/** Takes the tabs provided as the children and renders them in a list. Should be used with `TabProvider`. */\nfunction TabList({ children, onChange, ...tabListProps }: TabListProps) {\n const { tab, setTab } = useTabContext();\n\n return (\n <Tabs\n value={tab}\n onChange={(event, value) => {\n if (onChange) {\n onChange(event, value);\n }\n if (event.defaultPrevented) {\n return;\n }\n setTab(value);\n }}\n {...tabListProps}\n >\n {children}\n </Tabs>\n );\n}\n\nexport default TabList;\n","import type { ReactNode } from \"react\";\n\nimport { useTabContext } from \"src/Tab/TabProvider\";\n\nexport interface TabPanelProps<TabState extends string = string> {\n value: TabState;\n children: ReactNode;\n}\n\n/**\n * Displays the children if the current tab matches the value prop.\n *\n * @template TabState The possible values for the tab.\n */\nfunction TabPanel<TabState extends string = string>({ value, children }: TabPanelProps<TabState>) {\n const { tab } = useTabContext();\n\n if (value === tab) {\n return children;\n }\n\n return null;\n}\n\nexport default TabPanel;\n","import type { JSX, ReactNode } from \"react\";\n\nimport type { TabContextValue } from \"src/Tab/TabProvider\";\n\nimport TabItem from \"src/Tab/TabItem\";\nimport TabList from \"src/Tab/TabList\";\nimport TabPanel from \"src/Tab/TabPanel\";\nimport TabProvider from \"src/Tab/TabProvider\";\n\nexport interface TabComponents<TabState extends string = string> {\n /** Provides the context for the tab grouping. */\n Context: (props: { children: ReactNode }) => JSX.Element;\n /** Takes the tabs provided as the children and renders them in a list. Should be used with the tab context. */\n List: typeof TabList;\n /**\n * Renders a tab to be used within the context.\n *\n * @template TabState The possible values for the tab.\n */\n Item: typeof TabItem<TabState>;\n /**\n * Displays the children if the current tab in the `Tab.Context` matches the value prop.\n *\n * @template TabState The possible values for the tab.\n */\n Panel: typeof TabPanel<TabState>;\n}\n\n/** A creator function to create the tab group with the tab state fully typed throughout. */\nfunction createTabGroup<TabState extends string = string>({\n tab,\n setTab,\n}: TabContextValue<TabState>): TabComponents<TabState> {\n return {\n Context: ({ children }) => {\n return (\n <TabProvider tab={tab} setTab={setTab}>\n {children}\n </TabProvider>\n );\n },\n List: TabList,\n Item: TabItem,\n Panel: TabPanel,\n };\n}\n\nexport default createTabGroup;\n"],"mappings":"6MAaA,SAAS,EAA0C,CACjD,QACA,QACA,GAAG,GACsB,CACzB,OAAO,EAAC,EAAD,CAAK,MAAO,GAAS,EAAc,QAAO,GAAI,CAAW,CAAA,CAClE,CCAA,MAAa,EAAa,EAAgD,IAAA,EAAS,EAEnF,SAAgB,EAA+E,CAC7F,SAAS,IACqB,CAAC,EAA2D,CAC1F,IAAM,EAAU,EAAI,CAAU,EAC9B,GAAI,GAAU,CAAC,EACb,MAAM,IAAI,EACR,CAAE,SAAQ,SAAQ,EAClB,yBACA,yEACF,EAEF,OAAO,CACT,CAOA,SAAS,EAA8C,CACrD,WACA,MACA,UAC6B,CAC7B,OAAO,EAAC,EAAD,CAAY,MAAO,CAAE,MAAK,QAAO,EAAI,UAAqB,CAAA,CACnE,CClCA,SAAS,EAAQ,CAAE,WAAU,WAAU,GAAG,GAA8B,CACtE,GAAM,CAAE,MAAK,UAAW,EAAc,EAEtC,OACE,EAAC,EAAD,CACE,MAAO,EACP,UAAW,EAAO,IAAU,CACtB,GACF,EAAS,EAAO,CAAK,EAEnB,GAAM,kBAGV,EAAO,CAAK,CACd,EACA,GAAI,EAEH,UACG,CAAA,CAEV,CClBA,SAAS,EAA2C,CAAE,QAAO,YAAqC,CAChG,GAAM,CAAE,OAAQ,EAAc,EAM9B,OAJI,IAAU,EACL,EAGF,IACT,CCOA,SAAS,EAAiD,CACxD,MACA,UACqD,CACrD,MAAO,CACL,SAAU,CAAE,cAER,EAAC,EAAD,CAAkB,MAAa,SAC5B,UACU,CAAA,EAGjB,KAAM,EACN,KAAM,EACN,MAAO,CACT,CACF"}
@@ -0,0 +1,40 @@
1
+ import { Dispatch, ReactNode, SetStateAction } from "react";
2
+ import { OptionalOnCondition } from "@alextheman/utility";
3
+
4
+ //#region src/audio/AudioControls.d.ts
5
+ /** Controls the tracks provided by the AudioProvider. */
6
+ declare function AudioControls(): import("react/jsx-runtime").JSX.Element;
7
+ //#endregion
8
+ //#region src/root/types/ContextHookOptions.d.ts
9
+ interface ContextHookOptions<Strict extends boolean = true> {
10
+ /** Error if the context is missing if this is set to true. */
11
+ strict?: Strict;
12
+ }
13
+ //#endregion
14
+ //#region src/audio/AudioProvider.d.ts
15
+ interface TrackData {
16
+ title: string;
17
+ src: string;
18
+ artist: string;
19
+ }
20
+ interface AudioContextValue {
21
+ tracks: Array<TrackData>;
22
+ currentTrack: TrackData | null;
23
+ setCurrentTrack: Dispatch<SetStateAction<TrackData | null>>;
24
+ }
25
+ interface AudioProviderProps {
26
+ tracks: Array<TrackData>;
27
+ children: ReactNode;
28
+ }
29
+ /** Allows access to the audio information provided by AudioProvider. Will fail if AudioProvider could not be accessed and strict mode is true. */
30
+ declare function useAudioContext<Strict extends boolean = true>({
31
+ strict
32
+ }?: ContextHookOptions<Strict>): OptionalOnCondition<Strict, AudioContextValue>;
33
+ /** Provides audio information to the children components. */
34
+ declare function AudioProvider({
35
+ tracks,
36
+ children
37
+ }: AudioProviderProps): import("react/jsx-runtime").JSX.Element;
38
+ //#endregion
39
+ export { type AudioContextValue, AudioControls, AudioProvider, type AudioProviderProps, type TrackData, useAudioContext };
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ import e from"@mui/material/Typography";import{DataError as t}from"@alextheman/utility/v6";import{createContext as n,use as r,useState as i}from"react";import{jsx as a}from"react/jsx-runtime";const o=n(void 0);function s({strict:e=!0}={}){let n=r(o);if(e&&!n)throw new t({strict:e,context:n},`AUDIO_PROVIDER_NOT_FOUND`,`Could not find the AudioProvider context. Please double-check that it is present.`);return n}function c({tracks:e,children:t}){let[n,r]=i(e.length===0?null:e[0]);return a(o,{value:{tracks:e,currentTrack:n,setCurrentTrack:r},children:t})}function l(){let{currentTrack:t}=s();return t===null?a(e,{children:`No track selected`}):a(`audio`,{src:t.src,controls:!0,children:a(`track`,{kind:`captions`})})}export{l as AudioControls,c as AudioProvider,s as useAudioContext};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/audio/AudioProvider.tsx","../../src/audio/AudioControls.tsx"],"sourcesContent":["import type { OptionalOnCondition } from \"@alextheman/utility\";\nimport type { Dispatch, ReactNode, SetStateAction } from \"react\";\n\nimport type { ContextHookOptions } from \"src/root/types\";\n\nimport { DataError } from \"@alextheman/utility/v6\";\nimport { createContext, use, useState } from \"react\";\n\nexport interface TrackData {\n title: string;\n src: string;\n artist: string;\n}\n\nexport interface AudioContextValue {\n tracks: Array<TrackData>;\n currentTrack: TrackData | null;\n setCurrentTrack: Dispatch<SetStateAction<TrackData | null>>;\n}\nexport interface AudioProviderProps {\n tracks: Array<TrackData>;\n children: ReactNode;\n}\n\nconst AudioContext = createContext<AudioContextValue | undefined>(undefined);\n\n/** Allows access to the audio information provided by AudioProvider. Will fail if AudioProvider could not be accessed and strict mode is true. */\nexport function useAudioContext<Strict extends boolean = true>({\n strict = true as Strict,\n}: ContextHookOptions<Strict> = {}): OptionalOnCondition<Strict, AudioContextValue> {\n const context = use(AudioContext);\n if (strict && !context) {\n throw new DataError(\n { strict, context },\n \"AUDIO_PROVIDER_NOT_FOUND\",\n \"Could not find the AudioProvider context. Please double-check that it is present.\",\n );\n }\n return context as OptionalOnCondition<Strict, AudioContextValue>;\n}\n\n/** Provides audio information to the children components. */\nfunction AudioProvider({ tracks, children }: AudioProviderProps) {\n const [currentTrack, setCurrentTrack] = useState<TrackData | null>(\n tracks.length === 0 ? null : tracks[0],\n );\n\n return <AudioContext value={{ tracks, currentTrack, setCurrentTrack }}>{children}</AudioContext>;\n}\n\nexport default AudioProvider;\n","import Typography from \"@mui/material/Typography\";\n\nimport { useAudioContext } from \"src/audio/AudioProvider\";\n\n/** Controls the tracks provided by the AudioProvider. */\nfunction AudioControls() {\n const { currentTrack } = useAudioContext();\n\n if (currentTrack === null) {\n return <Typography>No track selected</Typography>;\n }\n\n return (\n <audio src={currentTrack.src} controls>\n <track kind=\"captions\" />\n </audio>\n );\n}\n\nexport default AudioControls;\n"],"mappings":"gMAwBA,MAAM,EAAe,EAA6C,IAAA,EAAS,EAG3E,SAAgB,EAA+C,CAC7D,SAAS,IACqB,CAAC,EAAmD,CAClF,IAAM,EAAU,EAAI,CAAY,EAChC,GAAI,GAAU,CAAC,EACb,MAAM,IAAI,EACR,CAAE,SAAQ,SAAQ,EAClB,2BACA,mFACF,EAEF,OAAO,CACT,CAGA,SAAS,EAAc,CAAE,SAAQ,YAAgC,CAC/D,GAAM,CAAC,EAAc,GAAmB,EACtC,EAAO,SAAW,EAAI,KAAO,EAAO,EACtC,EAEA,OAAO,EAAC,EAAD,CAAc,MAAO,CAAE,SAAQ,eAAc,iBAAgB,EAAI,UAAuB,CAAA,CACjG,CC3CA,SAAS,GAAgB,CACvB,GAAM,CAAE,gBAAiB,EAAgB,EAMzC,OAJI,IAAiB,KACZ,EAAC,EAAD,CAAA,SAAY,mBAA6B,CAAA,EAIhD,EAAC,QAAD,CAAO,IAAK,EAAa,IAAK,SAAA,YAC5B,EAAC,QAAD,CAAO,KAAK,UAAY,CAAA,CACnB,CAAA,CAEX"}
@@ -0,0 +1,56 @@
1
+ import { ButtonOwnProps } from "@mui/material/Button";
2
+ import { Dispatch, SetStateAction } from "react";
3
+ import { CreateEnumType } from "@alextheman/utility";
4
+
5
+ //#region src/file/FileInput.d.ts
6
+ declare const FileType: {
7
+ readonly PDF: "application/pdf";
8
+ readonly PNG: "image/png";
9
+ readonly JPEG: "image/jpeg";
10
+ readonly JPG: "image/jpg";
11
+ readonly XLSX: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
12
+ readonly DOCX: "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
13
+ readonly MP3: "audio/mp3";
14
+ readonly MP4: "video/mp4";
15
+ readonly WAV: "audio/wav";
16
+ };
17
+ type FileType = CreateEnumType<typeof FileType>;
18
+ interface FileInputProps extends ButtonOwnProps {
19
+ /** A function to run when a file has been uploaded. */
20
+ onFileInput: (allowedFiles: Array<File>) => void;
21
+ /** The label to display on the input button (defaults to "Upload files") */
22
+ label?: string;
23
+ /** Whether to accept multiple files or not. */
24
+ multiple?: boolean;
25
+ /** An array of file types to accept. */
26
+ accept?: Array<string>;
27
+ /** Enable the dropzone, allowing users to drag and drop files. */
28
+ useDropzone?: boolean;
29
+ }
30
+ /** Handles file inputs. */
31
+ declare function FileInput({
32
+ onFileInput,
33
+ label,
34
+ multiple,
35
+ accept,
36
+ useDropzone,
37
+ ...buttonProps
38
+ }: FileInputProps): import("react/jsx-runtime").JSX.Element;
39
+ //#endregion
40
+ //#region src/file/FileInputList.d.ts
41
+ interface FileInputListProps extends Omit<FileInputProps, "onFileInput"> {
42
+ /** The array of files (must be a React state). */
43
+ files: Array<File>;
44
+ /** The state setter for the array of files. */
45
+ setFiles: Dispatch<SetStateAction<Array<File>>>;
46
+ }
47
+ /** Renders the `FileInput` component with a list of uploaded files underneath it. */
48
+ declare function FileInputList({
49
+ files,
50
+ setFiles,
51
+ multiple,
52
+ ...fileInputProps
53
+ }: FileInputListProps): import("react/jsx-runtime").JSX.Element;
54
+ //#endregion
55
+ export { FileInput, FileInputList, type FileInputListProps, type FileInputProps, FileType };
56
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ import e from"@mui/material/Button";import{styled as t}from"@mui/material/styles";import{useId as n,useState as r}from"react";import{MdCloudUpload as i,MdDelete as a}from"react-icons/md";import{jsx as o,jsxs as s}from"react/jsx-runtime";import c from"@mui/material/Box";import l from"@mui/material/IconButton";import u from"@mui/material/List";import d from"@mui/material/ListItem";import f from"@mui/material/ListItemText";const p={PDF:`application/pdf`,PNG:`image/png`,JPEG:`image/jpeg`,JPG:`image/jpg`,XLSX:`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`,DOCX:`application/vnd.openxmlformats-officedocument.wordprocessingml.document`,MP3:`audio/mp3`,MP4:`video/mp4`,WAV:`audio/wav`},m=t(`input`)({clip:`rect(0 0 0 0)`,clipPath:`inset(50%)`,height:1,overflow:`hidden`,position:`absolute`,bottom:0,left:0,whiteSpace:`nowrap`,width:1}),h=t(`div`)(({theme:e,$dragging:t})=>({border:`2px dashed`,borderColor:t?e.palette.primary.main:`#ccc`,backgroundColor:t?e.palette.action.hover:`transparent`,borderRadius:8,padding:`1.5rem`,textAlign:`center`,transition:`border-color 0.2s`,cursor:`pointer`}));function g({onFileInput:t,label:a=`Upload files`,multiple:c,accept:l,useDropzone:u,...d}){let[f,p]=r(!1),g=n(),_=s(e,{variant:`contained`,component:`label`,"aria-label":`File input button`,onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),document.getElementById(g)?.click())},...d,startIcon:d.startIcon??o(i,{}),children:[a,o(m,{id:g,type:`file`,onChange:e=>{let n=e.target;t(Array.from(n.files??[])),n.value=``},multiple:c,accept:l?.join(`,`),disabled:d.disabled})]});return u?o(h,{$dragging:f,onDragOver:e=>{e.preventDefault(),!d.disabled&&p(!0)},onDragLeave:e=>{e.preventDefault(),p(!1)},onDrop:e=>{e.preventDefault(),p(!1),!d.disabled&&t(Array.from(e.dataTransfer.files??[]))},children:_}):_}function _({files:e,setFiles:t,multiple:n=!0,...r}){function i(e){t(t=>[...t,...e])}return s(c,{children:[o(g,{...r,multiple:n,onFileInput:i}),o(u,{children:e.map(e=>o(d,{secondaryAction:o(l,{"aria-label":`Delete`,edge:`end`,onClick:()=>{t(t=>t.filter(t=>t!==e))},children:o(a,{})}),children:o(f,{primary:e.name})},`${e.name}-${e.lastModified}`))})]})}export{g as FileInput,_ as FileInputList,p as FileType};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/file/FileInput.tsx","../../src/file/FileInputList.tsx"],"sourcesContent":["import type { CreateEnumType } from \"@alextheman/utility\";\nimport type { ButtonOwnProps } from \"@mui/material/Button\";\n\nimport Button from \"@mui/material/Button\";\nimport { styled } from \"@mui/material/styles\";\nimport { useId, useState } from \"react\";\nimport { MdCloudUpload } from \"react-icons/md\";\n\nexport const FileType = {\n PDF: \"application/pdf\",\n PNG: \"image/png\",\n JPEG: \"image/jpeg\",\n JPG: \"image/jpg\",\n XLSX: \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n DOCX: \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n MP3: \"audio/mp3\",\n MP4: \"video/mp4\",\n WAV: \"audio/wav\",\n} as const;\nexport type FileType = CreateEnumType<typeof FileType>;\n\nconst VisuallyHiddenInput = styled(\"input\")({\n clip: \"rect(0 0 0 0)\",\n clipPath: \"inset(50%)\",\n height: 1,\n overflow: \"hidden\",\n position: \"absolute\",\n bottom: 0,\n left: 0,\n whiteSpace: \"nowrap\",\n width: 1,\n});\n\nconst Dropzone = styled(\"div\")<{ $dragging: boolean }>(({ theme, $dragging }) => {\n return {\n border: \"2px dashed\",\n borderColor: $dragging ? theme.palette.primary.main : \"#ccc\",\n backgroundColor: $dragging ? theme.palette.action.hover : \"transparent\",\n borderRadius: 8,\n padding: \"1.5rem\",\n textAlign: \"center\",\n transition: \"border-color 0.2s\",\n cursor: \"pointer\",\n };\n});\n\nexport interface FileInputProps extends ButtonOwnProps {\n /** A function to run when a file has been uploaded. */\n onFileInput: (allowedFiles: Array<File>) => void;\n /** The label to display on the input button (defaults to \"Upload files\") */\n label?: string;\n /** Whether to accept multiple files or not. */\n multiple?: boolean;\n /** An array of file types to accept. */\n accept?: Array<string>;\n /** Enable the dropzone, allowing users to drag and drop files. */\n useDropzone?: boolean;\n}\n\n/** Handles file inputs. */\nfunction FileInput({\n onFileInput,\n label = \"Upload files\",\n multiple,\n accept,\n useDropzone,\n ...buttonProps\n}: FileInputProps) {\n const [isDragging, setIsDragging] = useState<boolean>(false);\n const id = useId();\n\n const fileInputButton = (\n <Button\n variant=\"contained\"\n component=\"label\"\n aria-label=\"File input button\"\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n document.getElementById(id)?.click();\n }\n }}\n {...buttonProps}\n startIcon={buttonProps.startIcon ?? <MdCloudUpload />}\n >\n {label}\n <VisuallyHiddenInput\n id={id}\n type=\"file\"\n onChange={(event) => {\n const input = event.target;\n onFileInput(Array.from(input.files ?? []));\n input.value = \"\";\n }}\n multiple={multiple}\n accept={accept?.join(\",\")}\n disabled={buttonProps.disabled}\n />\n </Button>\n );\n\n return useDropzone ? (\n <Dropzone\n $dragging={isDragging}\n onDragOver={(event) => {\n event.preventDefault();\n if (buttonProps.disabled) {\n return;\n }\n setIsDragging(true);\n }}\n onDragLeave={(event) => {\n event.preventDefault();\n setIsDragging(false);\n }}\n onDrop={(event) => {\n event.preventDefault();\n setIsDragging(false);\n if (buttonProps.disabled) {\n return;\n }\n const filesArray = Array.from(event.dataTransfer.files ?? []);\n onFileInput(filesArray);\n }}\n >\n {fileInputButton}\n </Dropzone>\n ) : (\n fileInputButton\n );\n}\n\nexport default FileInput;\n","import type { Dispatch, SetStateAction } from \"react\";\n\nimport type { FileInputProps } from \"src/file/FileInput\";\n\nimport Box from \"@mui/material/Box\";\nimport IconButton from \"@mui/material/IconButton\";\nimport List from \"@mui/material/List\";\nimport ListItem from \"@mui/material/ListItem\";\nimport ListItemText from \"@mui/material/ListItemText\";\nimport { MdDelete } from \"react-icons/md\";\n\nimport FileInput from \"src/file/FileInput\";\n\nexport interface FileInputListProps extends Omit<FileInputProps, \"onFileInput\"> {\n /** The array of files (must be a React state). */\n files: Array<File>;\n /** The state setter for the array of files. */\n setFiles: Dispatch<SetStateAction<Array<File>>>;\n}\n\n/** Renders the `FileInput` component with a list of uploaded files underneath it. */\nfunction FileInputList({\n files,\n setFiles,\n multiple = true,\n ...fileInputProps\n}: FileInputListProps) {\n function onFileInput(newFiles: Array<File>) {\n setFiles((oldFiles) => {\n return [...oldFiles, ...newFiles];\n });\n }\n\n return (\n <Box>\n <FileInput {...fileInputProps} multiple={multiple} onFileInput={onFileInput} />\n <List>\n {files.map((file) => {\n return (\n <ListItem\n key={`${file.name}-${file.lastModified}`}\n secondaryAction={\n <IconButton\n aria-label=\"Delete\"\n edge=\"end\"\n onClick={() => {\n setFiles((oldFiles) => {\n return oldFiles.filter((fileToDelete) => {\n return fileToDelete !== file;\n });\n });\n }}\n >\n <MdDelete />\n </IconButton>\n }\n >\n <ListItemText primary={file.name} />\n </ListItem>\n );\n })}\n </List>\n </Box>\n );\n}\n\nexport default FileInputList;\n"],"mappings":"waAQA,MAAa,EAAW,CACtB,IAAK,kBACL,IAAK,YACL,KAAM,aACN,IAAK,YACL,KAAM,oEACN,KAAM,0EACN,IAAK,YACL,IAAK,YACL,IAAK,WACP,EAGM,EAAsB,EAAO,OAAO,EAAE,CAC1C,KAAM,gBACN,SAAU,aACV,OAAQ,EACR,SAAU,SACV,SAAU,WACV,OAAQ,EACR,KAAM,EACN,WAAY,SACZ,MAAO,CACT,CAAC,EAEK,EAAW,EAAO,KAAK,GAA2B,CAAE,QAAO,gBACxD,CACL,OAAQ,aACR,YAAa,EAAY,EAAM,QAAQ,QAAQ,KAAO,OACtD,gBAAiB,EAAY,EAAM,QAAQ,OAAO,MAAQ,cAC1D,aAAc,EACd,QAAS,SACT,UAAW,SACX,WAAY,oBACZ,OAAQ,SACV,EACD,EAgBD,SAAS,EAAU,CACjB,cACA,QAAQ,eACR,WACA,SACA,cACA,GAAG,GACc,CACjB,GAAM,CAAC,EAAY,GAAiB,EAAkB,EAAK,EACrD,EAAK,EAAM,EAEX,EACJ,EAAC,EAAD,CACE,QAAQ,YACR,UAAU,QACV,aAAW,oBACX,UAAY,GAAU,EAChB,EAAM,MAAQ,SAAW,EAAM,MAAQ,OACzC,EAAM,eAAe,EACrB,SAAS,eAAe,CAAE,GAAG,MAAM,EAEvC,EACA,GAAI,EACJ,UAAW,EAAY,WAAa,EAAC,EAAD,CAAgB,CAAA,WAXtD,CAaG,EACD,EAAC,EAAD,CACM,KACJ,KAAK,OACL,SAAW,GAAU,CACnB,IAAM,EAAQ,EAAM,OACpB,EAAY,MAAM,KAAK,EAAM,OAAS,CAAC,CAAC,CAAC,EACzC,EAAM,MAAQ,EAChB,EACU,WACV,OAAQ,GAAQ,KAAK,GAAG,EACxB,SAAU,EAAY,QACvB,CAAA,CACK,IAGV,OAAO,EACL,EAAC,EAAD,CACE,UAAW,EACX,WAAa,GAAU,CACrB,EAAM,eAAe,EACjB,GAAY,UAGhB,EAAc,EAAI,CACpB,EACA,YAAc,GAAU,CACtB,EAAM,eAAe,EACrB,EAAc,EAAK,CACrB,EACA,OAAS,GAAU,CACjB,EAAM,eAAe,EACrB,EAAc,EAAK,EACf,GAAY,UAIhB,EADmB,MAAM,KAAK,EAAM,aAAa,OAAS,CAAC,CACtC,CAAC,CACxB,WAEC,CACO,CAAA,EAEV,CAEJ,CC7GA,SAAS,EAAc,CACrB,QACA,WACA,WAAW,GACX,GAAG,GACkB,CACrB,SAAS,EAAY,EAAuB,CAC1C,EAAU,GACD,CAAC,GAAG,EAAU,GAAG,CAAQ,CACjC,CACH,CAEA,OACE,EAAC,EAAD,CAAA,SAAA,CACE,EAAC,EAAD,CAAW,GAAI,EAA0B,WAAuB,aAAc,CAAA,EAC9E,EAAC,EAAD,CAAA,SACG,EAAM,IAAK,GAER,EAAC,EAAD,CAEE,gBACE,EAAC,EAAD,CACE,aAAW,SACX,KAAK,MACL,YAAe,CACb,EAAU,GACD,EAAS,OAAQ,GACf,IAAiB,CACzB,CACF,CACH,WAEA,EAAC,EAAD,CAAW,CAAA,CACD,CAAA,WAGd,EAAC,EAAD,CAAc,QAAS,EAAK,IAAO,CAAA,CAC3B,EAlBH,GAAG,EAAK,KAAK,GAAG,EAAK,cAkBlB,CAEb,CACG,CAAA,CACH,CAAA,CAAA,CAET"}