@aws-amplify/ui-react-core 3.0.29 → 3.1.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.
- package/dist/elements.js +116 -3
- package/dist/esm/elements/ControlsContext.mjs +71 -0
- package/dist/esm/elements/ElementsContext.mjs +3 -2
- package/dist/esm/elements/defineBaseElement.mjs +30 -1
- package/dist/esm/elements/utils.mjs +11 -0
- package/dist/esm/elements/withBaseElementProps.mjs +1 -1
- package/dist/esm/elements.mjs +3 -1
- package/dist/esm/hooks/useDataState.mjs +10 -4
- package/dist/esm/hooks/useDropZone.mjs +13 -4
- package/dist/esm/utils/createContextUtilities.mjs +6 -3
- package/dist/esm/utils/processDroppedItems.mjs +66 -0
- package/dist/index.js +92 -11
- package/dist/types/elements/ControlsContext.d.ts +63 -0
- package/dist/types/elements/ElementsContext.d.ts +3 -2
- package/dist/types/elements/defineBaseElement.d.ts +19 -2
- package/dist/types/elements/index.d.ts +4 -1
- package/dist/types/elements/types.d.ts +88 -6
- package/dist/types/elements/utils.d.ts +3 -0
- package/dist/types/elements/withBaseElementProps.d.ts +3 -3
- package/dist/types/hooks/index.d.ts +1 -1
- package/dist/types/hooks/useDataState.d.ts +6 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/utils/createContextUtilities.d.ts +1 -1
- package/dist/types/utils/processDroppedItems.d.ts +1 -0
- package/package.json +3 -3
- package/src/elements/ControlsContext.tsx +89 -0
- package/src/elements/ElementsContext.tsx +3 -2
- package/src/elements/defineBaseElement.tsx +50 -2
- package/src/elements/index.ts +7 -1
- package/src/elements/types.ts +114 -6
- package/src/elements/utils.ts +20 -0
- package/src/elements/withBaseElementProps.tsx +3 -3
- package/src/hooks/index.ts +6 -1
- package/src/hooks/useDataState.ts +25 -7
- package/src/hooks/useDropZone.ts +18 -7
- package/src/index.ts +2 -0
- package/src/utils/createContextUtilities.tsx +9 -6
- package/src/utils/processDroppedItems.ts +79 -0
package/src/elements/types.ts
CHANGED
|
@@ -13,16 +13,31 @@ import React from 'react';
|
|
|
13
13
|
* are always optional at the interface level, allowing for additional `props`
|
|
14
14
|
* to be added to existing `BaseElement` interfaces as needed.
|
|
15
15
|
*/
|
|
16
|
-
export type BaseElement<T = {}
|
|
16
|
+
export type BaseElement<T = {}> = (props: T) => React.JSX.Element;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @internal @unstable
|
|
20
|
+
*
|
|
21
|
+
* see @type {BaseElement}
|
|
22
|
+
*
|
|
23
|
+
* `BaseElement` with a `ref` corresponding to the `element` type
|
|
24
|
+
*/
|
|
25
|
+
export type BaseElementWithRef<
|
|
26
|
+
T = {},
|
|
27
|
+
K = {},
|
|
28
|
+
> = React.ForwardRefExoticComponent<
|
|
17
29
|
React.PropsWithoutRef<T> & React.RefAttributes<K>
|
|
18
30
|
>;
|
|
19
31
|
|
|
20
32
|
type ListElementSubType = 'Ordered' | 'Unordered';
|
|
21
|
-
type ListElementDisplayName =
|
|
33
|
+
type ListElementDisplayName = `${ListElementSubType}List`;
|
|
22
34
|
|
|
23
|
-
type TableElementSubType = 'Body' | '
|
|
35
|
+
type TableElementSubType = 'Body' | 'DataCell' | 'Row' | 'Head' | 'Header';
|
|
24
36
|
type TableElementDisplayName = 'Table' | `Table${TableElementSubType}`;
|
|
25
37
|
|
|
38
|
+
type DescriptionElementSubType = 'Details' | 'List' | 'Term';
|
|
39
|
+
type DescriptionElementDisplayName = `Description${DescriptionElementSubType}`;
|
|
40
|
+
|
|
26
41
|
/**
|
|
27
42
|
* @internal @unstable
|
|
28
43
|
*
|
|
@@ -30,7 +45,6 @@ type TableElementDisplayName = 'Table' | `Table${TableElementSubType}`;
|
|
|
30
45
|
*/
|
|
31
46
|
export type ElementDisplayName =
|
|
32
47
|
| 'Button'
|
|
33
|
-
| 'Divider'
|
|
34
48
|
| 'Heading' // h1, h2, etc
|
|
35
49
|
| 'Icon'
|
|
36
50
|
| 'Image'
|
|
@@ -44,6 +58,7 @@ export type ElementDisplayName =
|
|
|
44
58
|
| 'TextArea'
|
|
45
59
|
| 'Title'
|
|
46
60
|
| 'View'
|
|
61
|
+
| DescriptionElementDisplayName
|
|
47
62
|
| ListElementDisplayName
|
|
48
63
|
| TableElementDisplayName;
|
|
49
64
|
|
|
@@ -68,7 +83,7 @@ export type ReactElementType = keyof React.JSX.IntrinsicElements;
|
|
|
68
83
|
* @internal @unstable
|
|
69
84
|
*/
|
|
70
85
|
export type ReactElementProps<T extends ReactElementType> =
|
|
71
|
-
React.
|
|
86
|
+
React.ComponentProps<T>;
|
|
72
87
|
|
|
73
88
|
/**
|
|
74
89
|
* @internal @unstable
|
|
@@ -85,5 +100,98 @@ export type BaseElementProps<
|
|
|
85
100
|
V = string,
|
|
86
101
|
K extends Record<ElementPropKey<keyof K>, any> = Record<string, any>,
|
|
87
102
|
> = React.AriaAttributes &
|
|
88
|
-
React.
|
|
103
|
+
React.Attributes &
|
|
89
104
|
Pick<K, ElementPropKey<T>> & { testId?: string; variant?: V };
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @internal @unstable
|
|
108
|
+
*/
|
|
109
|
+
export type BaseElementWithRefProps<
|
|
110
|
+
T extends keyof K,
|
|
111
|
+
V = string,
|
|
112
|
+
K extends Record<ElementPropKey<keyof K>, any> = Record<string, any>,
|
|
113
|
+
> = BaseElementProps<T, V, K> & React.RefAttributes<ElementRefType<K>>;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @internal @unstable
|
|
117
|
+
*/
|
|
118
|
+
export type ElementWithAndWithoutRef<
|
|
119
|
+
T extends ReactElementType,
|
|
120
|
+
K extends React.ComponentType<React.ComponentProps<T>> = React.ComponentType<
|
|
121
|
+
React.ComponentProps<T>
|
|
122
|
+
>,
|
|
123
|
+
> = K extends React.ComponentType<infer U>
|
|
124
|
+
? React.ForwardRefExoticComponent<U>
|
|
125
|
+
: never;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @internal @unstable
|
|
129
|
+
*
|
|
130
|
+
* Merge `BaseElement` defintions with `elements` types provided by
|
|
131
|
+
* consumers, for use with top level connected component function
|
|
132
|
+
* signatures.
|
|
133
|
+
*
|
|
134
|
+
* Example:
|
|
135
|
+
*
|
|
136
|
+
* ```tsx
|
|
137
|
+
* export function createStorageBrowser<
|
|
138
|
+
* T extends Partial<StorageBrowserElements>,
|
|
139
|
+
* >({ elements }: CreateStorageBrowserInput<T> = {}): {
|
|
140
|
+
* StorageBrowser: StorageBrowser<MergeElements<StorageBrowserElements, T>>
|
|
141
|
+
* } {
|
|
142
|
+
* // ...do create stuff
|
|
143
|
+
* };
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export type MergeBaseElements<T, K extends Partial<T>> = {
|
|
147
|
+
[U in keyof T]: K[U] extends T[U] ? K[U] : T[U];
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @internal @unstable
|
|
152
|
+
*
|
|
153
|
+
* Extend the defintion of a `BaseElement` with additional `props`.
|
|
154
|
+
*
|
|
155
|
+
* Use cases are restricted to scenarios where additional `props`
|
|
156
|
+
* are required for a `ControlElement` interface, for example:
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```tsx
|
|
160
|
+
* const FieldInput = defineBaseElementWithRef({
|
|
161
|
+
* type: 'input',
|
|
162
|
+
* displayName: 'Input'
|
|
163
|
+
* });
|
|
164
|
+
*
|
|
165
|
+
* type InputWithSearchCallback =
|
|
166
|
+
* ExtendBaseElement<
|
|
167
|
+
* typeof FieldInput,
|
|
168
|
+
* { onSearch?: (event: { value: string }) => void }
|
|
169
|
+
* >
|
|
170
|
+
*
|
|
171
|
+
* const SearchInput = React.forwardRef((
|
|
172
|
+
* { onSearch, ...props }
|
|
173
|
+
* ref
|
|
174
|
+
* ) => {
|
|
175
|
+
* // ...do something with onSearch
|
|
176
|
+
*
|
|
177
|
+
* return <FieldInput {...props} ref={ref} />;
|
|
178
|
+
* });
|
|
179
|
+
* ```
|
|
180
|
+
*
|
|
181
|
+
* Caveats:
|
|
182
|
+
* - additional `props` should not be passed directly to
|
|
183
|
+
* `BaseElement` components, the outputted interface should be
|
|
184
|
+
* applied to a wrapping element that handles the additional `props`
|
|
185
|
+
*
|
|
186
|
+
* - additional `props` that share a key with existing `props`
|
|
187
|
+
* are omitted from the outputted interface to adhere to `BaseElement`
|
|
188
|
+
* type contracts
|
|
189
|
+
*
|
|
190
|
+
*/
|
|
191
|
+
export type ExtendBaseElement<
|
|
192
|
+
// `BaseElement` to extend
|
|
193
|
+
T extends React.ComponentType,
|
|
194
|
+
// additional `props`
|
|
195
|
+
K = {},
|
|
196
|
+
U extends React.ComponentPropsWithRef<T> = React.ComponentPropsWithRef<T>,
|
|
197
|
+
> = BaseElementWithRef<U & Omit<K, keyof U>, U>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export function isComponent<T>(
|
|
4
|
+
component?: React.ComponentType<T> | React.ForwardRefExoticComponent<T>
|
|
5
|
+
): component is React.ComponentType<T> {
|
|
6
|
+
return typeof component === 'function';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function isForwardRefExoticComponent<T>(
|
|
10
|
+
component: React.ComponentType<T> | React.ForwardRefExoticComponent<T>
|
|
11
|
+
): component is React.ForwardRefExoticComponent<T> {
|
|
12
|
+
return (
|
|
13
|
+
typeof component === 'object' &&
|
|
14
|
+
typeof (component as React.ForwardRefExoticComponent<T>).$$typeof ===
|
|
15
|
+
'symbol' &&
|
|
16
|
+
['react.memo', 'react.forward_ref'].includes(
|
|
17
|
+
(component as React.ForwardRefExoticComponent<T>).$$typeof.description!
|
|
18
|
+
)
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { BaseElementWithRef, ElementRefType } from './types';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @internal @unstable
|
|
@@ -16,7 +16,7 @@ import { BaseElement, ElementRefType } from './types';
|
|
|
16
16
|
* type InputElementPropKey = 'onChange' | 'type';
|
|
17
17
|
*
|
|
18
18
|
* // create `InputElement` base with `type` generic and extended `props` key
|
|
19
|
-
* export const InputElement =
|
|
19
|
+
* export const InputElement = defineBaseElementWithRef<"input", InputElementPropKey>({
|
|
20
20
|
* type: "input",
|
|
21
21
|
* displayName: "Input",
|
|
22
22
|
* });
|
|
@@ -38,7 +38,7 @@ export default function withBaseElementProps<
|
|
|
38
38
|
>(
|
|
39
39
|
Target: React.ForwardRefExoticComponent<T>,
|
|
40
40
|
defaultProps: K
|
|
41
|
-
):
|
|
41
|
+
): BaseElementWithRef<T, ElementRefType<T>> {
|
|
42
42
|
const Component = React.forwardRef<ElementRefType<T>, T>((props, ref) => (
|
|
43
43
|
<Target
|
|
44
44
|
{...{
|
package/src/hooks/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isFunction } from '@aws-amplify/ui';
|
|
1
2
|
import React from 'react';
|
|
2
3
|
|
|
3
4
|
export interface DataState<T> {
|
|
@@ -7,6 +8,13 @@ export interface DataState<T> {
|
|
|
7
8
|
message: string | undefined;
|
|
8
9
|
}
|
|
9
10
|
|
|
11
|
+
export type DataAction<T = any, K = any> = (prevData: T, input: K) => T;
|
|
12
|
+
|
|
13
|
+
export type AsyncDataAction<T = any, K = any> = (
|
|
14
|
+
prevData: T,
|
|
15
|
+
input: K
|
|
16
|
+
) => Promise<T>;
|
|
17
|
+
|
|
10
18
|
// default state
|
|
11
19
|
const INITIAL_STATE = { hasError: false, isLoading: false, message: undefined };
|
|
12
20
|
const LOADING_STATE = { hasError: false, isLoading: true, message: undefined };
|
|
@@ -20,9 +28,13 @@ const resolveMaybeAsync = async <T>(
|
|
|
20
28
|
};
|
|
21
29
|
|
|
22
30
|
export default function useDataState<T, K>(
|
|
23
|
-
action:
|
|
24
|
-
initialData: T
|
|
25
|
-
|
|
31
|
+
action: DataAction<T, K> | AsyncDataAction<T, K>,
|
|
32
|
+
initialData: T,
|
|
33
|
+
options?: {
|
|
34
|
+
onSuccess?: (data: T) => void;
|
|
35
|
+
onError?: (message: string) => void;
|
|
36
|
+
}
|
|
37
|
+
): [state: DataState<T>, handleAction: (input: K) => void] {
|
|
26
38
|
const [dataState, setDataState] = React.useState<DataState<T>>(() => ({
|
|
27
39
|
...INITIAL_STATE,
|
|
28
40
|
data: initialData,
|
|
@@ -30,20 +42,26 @@ export default function useDataState<T, K>(
|
|
|
30
42
|
|
|
31
43
|
const prevData = React.useRef(initialData);
|
|
32
44
|
|
|
33
|
-
const
|
|
34
|
-
|
|
45
|
+
const { onSuccess, onError } = options ?? {};
|
|
46
|
+
|
|
47
|
+
const handleAction: (input: K) => void = React.useCallback(
|
|
48
|
+
(input) => {
|
|
35
49
|
setDataState(({ data }) => ({ ...LOADING_STATE, data }));
|
|
36
50
|
|
|
37
|
-
resolveMaybeAsync(action(prevData.current,
|
|
51
|
+
resolveMaybeAsync(action(prevData.current, input))
|
|
38
52
|
.then((data: T) => {
|
|
53
|
+
if (isFunction(onSuccess)) onSuccess(data);
|
|
54
|
+
|
|
39
55
|
prevData.current = data;
|
|
40
56
|
setDataState({ ...INITIAL_STATE, data });
|
|
41
57
|
})
|
|
42
58
|
.catch(({ message }: Error) => {
|
|
59
|
+
if (isFunction(onError)) onError(message);
|
|
60
|
+
|
|
43
61
|
setDataState(({ data }) => ({ ...ERROR_STATE, data, message }));
|
|
44
62
|
});
|
|
45
63
|
},
|
|
46
|
-
[action]
|
|
64
|
+
[action, onError, onSuccess]
|
|
47
65
|
);
|
|
48
66
|
|
|
49
67
|
return [dataState, handleAction];
|
package/src/hooks/useDropZone.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
2
|
import { isFunction } from '@aws-amplify/ui';
|
|
3
3
|
import { filterAllowedFiles } from '../utils/filterAllowedFiles';
|
|
4
|
+
import { processDroppedItems } from '../utils/processDroppedItems';
|
|
4
5
|
|
|
5
6
|
interface DragEvents {
|
|
6
7
|
onDragStart: (event: React.DragEvent<HTMLDivElement>) => void;
|
|
@@ -85,17 +86,27 @@ export default function useDropZone({
|
|
|
85
86
|
event.preventDefault();
|
|
86
87
|
event.stopPropagation();
|
|
87
88
|
setDragState('inactive');
|
|
88
|
-
|
|
89
|
-
const {
|
|
90
|
-
files,
|
|
91
|
-
acceptedFileTypes
|
|
92
|
-
);
|
|
89
|
+
|
|
90
|
+
const { files, items } = event.dataTransfer;
|
|
93
91
|
|
|
94
92
|
if (isFunction(_onDrop)) {
|
|
95
93
|
_onDrop(event);
|
|
96
94
|
}
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
|
|
96
|
+
const completeDrop = (files: File[]) => {
|
|
97
|
+
const { acceptedFiles, rejectedFiles } = filterAllowedFiles<File>(
|
|
98
|
+
files,
|
|
99
|
+
acceptedFileTypes
|
|
100
|
+
);
|
|
101
|
+
if (isFunction(onDropComplete)) {
|
|
102
|
+
onDropComplete({ acceptedFiles, rejectedFiles });
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
if (!items) {
|
|
107
|
+
completeDrop(Array.from(files));
|
|
108
|
+
} else {
|
|
109
|
+
processDroppedItems(Array.from(items)).then(completeDrop);
|
|
99
110
|
}
|
|
100
111
|
};
|
|
101
112
|
|
package/src/index.ts
CHANGED
|
@@ -36,7 +36,7 @@ type CreateContextUtilitiesReturn<ContextType, ContextName extends string> = {
|
|
|
36
36
|
: Key extends `use${string}`
|
|
37
37
|
? (params?: HookParams) => ContextType
|
|
38
38
|
: Key extends `${string}Context`
|
|
39
|
-
? React.Context<ContextType
|
|
39
|
+
? React.Context<ContextType>
|
|
40
40
|
: never;
|
|
41
41
|
};
|
|
42
42
|
|
|
@@ -89,7 +89,7 @@ type CreateContextUtilitiesReturn<ContextType, ContextName extends string> = {
|
|
|
89
89
|
export default function createContextUtilities<
|
|
90
90
|
ContextType,
|
|
91
91
|
ContextName extends string = string,
|
|
92
|
-
Message extends string | undefined = string | undefined
|
|
92
|
+
Message extends string | undefined = string | undefined,
|
|
93
93
|
>(
|
|
94
94
|
options: ContextOptions<ContextType, ContextName, Message>
|
|
95
95
|
): CreateContextUtilitiesReturn<ContextType, ContextName> {
|
|
@@ -99,7 +99,11 @@ export default function createContextUtilities<
|
|
|
99
99
|
throw new Error(INVALID_OPTIONS_MESSAGE);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
const contextDisplayName = `${contextName}Context`;
|
|
103
|
+
const providerDisplayName = `${contextName}Provider`;
|
|
104
|
+
|
|
102
105
|
const Context = React.createContext<ContextType | undefined>(defaultValue);
|
|
106
|
+
Context.displayName = contextDisplayName;
|
|
103
107
|
|
|
104
108
|
function Provider(props: React.PropsWithChildren<ContextType>) {
|
|
105
109
|
const { children, ...context } = props;
|
|
@@ -113,8 +117,7 @@ export default function createContextUtilities<
|
|
|
113
117
|
return <Context.Provider value={value}>{children}</Context.Provider>;
|
|
114
118
|
}
|
|
115
119
|
|
|
116
|
-
Provider.displayName =
|
|
117
|
-
|
|
120
|
+
Provider.displayName = providerDisplayName;
|
|
118
121
|
return {
|
|
119
122
|
[`use${contextName}`]: function (params?: HookParams) {
|
|
120
123
|
const context = React.useContext(Context);
|
|
@@ -125,7 +128,7 @@ export default function createContextUtilities<
|
|
|
125
128
|
|
|
126
129
|
return context;
|
|
127
130
|
},
|
|
128
|
-
[
|
|
129
|
-
[
|
|
131
|
+
[providerDisplayName]: Provider,
|
|
132
|
+
[contextDisplayName]: Context,
|
|
130
133
|
} as CreateContextUtilitiesReturn<ContextType, ContextName>;
|
|
131
134
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Helper function to convert FileSystemFileEntry to File
|
|
2
|
+
const getFileFromEntry = (fileEntry: FileSystemFileEntry): Promise<File> => {
|
|
3
|
+
return new Promise((resolve) => {
|
|
4
|
+
fileEntry.file(resolve);
|
|
5
|
+
});
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// Helper function to read all entries in a directory
|
|
9
|
+
const readAllDirectoryEntries = async (
|
|
10
|
+
dirReader: FileSystemDirectoryReader
|
|
11
|
+
): Promise<FileSystemEntry[]> => {
|
|
12
|
+
const entries: FileSystemEntry[] = [];
|
|
13
|
+
|
|
14
|
+
let readBatch: FileSystemEntry[] = [];
|
|
15
|
+
do {
|
|
16
|
+
readBatch = await new Promise<FileSystemEntry[]>((resolve, reject) => {
|
|
17
|
+
try {
|
|
18
|
+
dirReader.readEntries(resolve, reject);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
reject(error);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
entries.push(...readBatch);
|
|
24
|
+
} while (readBatch.length > 0);
|
|
25
|
+
|
|
26
|
+
return entries;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Helper function to process files and folder contents
|
|
30
|
+
export async function processDroppedItems(
|
|
31
|
+
dataTransferItems: DataTransferItem[]
|
|
32
|
+
): Promise<File[]> {
|
|
33
|
+
const files: File[] = [];
|
|
34
|
+
|
|
35
|
+
const processFileSystemEntry = async (
|
|
36
|
+
entry: FileSystemEntry
|
|
37
|
+
): Promise<void> => {
|
|
38
|
+
if (entry.isFile) {
|
|
39
|
+
const file = await getFileFromEntry(entry as FileSystemFileEntry);
|
|
40
|
+
// drag and dropped files do not have a webkitRelativePath property,
|
|
41
|
+
// but they do have a fullPath property which has the same information
|
|
42
|
+
// https://github.com/ant-design/ant-design/issues/16426
|
|
43
|
+
if (entry.fullPath && !file.webkitRelativePath) {
|
|
44
|
+
Object.defineProperties(file, {
|
|
45
|
+
webkitRelativePath: {
|
|
46
|
+
writable: true,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// intentionally overwriting webkitRelativePath
|
|
51
|
+
// @ts-expect-error
|
|
52
|
+
file.webkitRelativePath = entry.fullPath.replace(/^\//, '');
|
|
53
|
+
|
|
54
|
+
Object.defineProperties(file, {
|
|
55
|
+
webkitRelativePath: {
|
|
56
|
+
writable: false,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
files.push(file);
|
|
61
|
+
} else if (entry.isDirectory) {
|
|
62
|
+
const dirReader = (entry as FileSystemDirectoryEntry).createReader();
|
|
63
|
+
const dirEntries = await readAllDirectoryEntries(dirReader);
|
|
64
|
+
await Promise.all(dirEntries.map(processFileSystemEntry));
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Filter out and process files from the data transfer items
|
|
69
|
+
await Promise.all(
|
|
70
|
+
dataTransferItems
|
|
71
|
+
.reduce<FileSystemEntry[]>((acc, item) => {
|
|
72
|
+
const entry = item.webkitGetAsEntry();
|
|
73
|
+
return item.kind === 'file' && entry ? [...acc, entry] : acc;
|
|
74
|
+
}, [])
|
|
75
|
+
.map(processFileSystemEntry)
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
return files;
|
|
79
|
+
}
|