Skip to content

Commit 80609ab

Browse files
committed
[fields] Replace asyncProxy with createAction for file handling
1 parent b349ed9 commit 80609ab

File tree

2 files changed

+102
-46
lines changed

2 files changed

+102
-46
lines changed

packages/form/src/fields/extra-fields/file.svelte

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
<script lang="ts">
1010
import { fileToDataURL } from "@/lib/file.js";
11-
import { asyncProxy } from "@/lib/svelte.svelte";
11+
import { abortPrevious, createAction } from "@/lib/action.svelte.js";
1212
import {
1313
makeEventHandlers,
1414
getErrors,
@@ -22,7 +22,11 @@
2222
2323
import "../extra-widgets/file.js";
2424
25-
let { config, value = $bindable(), uiOption }: ComponentProps["fileField"] = $props();
25+
let {
26+
config,
27+
value = $bindable(),
28+
uiOption,
29+
}: ComponentProps["fileField"] = $props();
2630
2731
const ctx = getFormContext();
2832
@@ -34,28 +38,45 @@
3438
validateField(ctx, config, value)
3539
);
3640
37-
const files = asyncProxy(
38-
async (isRegOnly, signal) => {
39-
if (!value || isRegOnly) {
40-
return;
41-
}
41+
let lastValueUpdate: string | undefined;
42+
const toValue = createAction({
43+
combinator: abortPrevious,
44+
async execute(
45+
signal,
46+
files: FileList | undefined
47+
): Promise<string | undefined> {
48+
return files === undefined || files.length === 0
49+
? undefined
50+
: fileToDataURL(signal, files[0]!);
51+
},
52+
onSuccess(result: string | undefined) {
53+
lastValueUpdate = result;
54+
value = result;
55+
},
56+
});
57+
58+
let files = $state.raw<FileList>();
59+
const toFiles = createAction({
60+
combinator: abortPrevious,
61+
async execute(signal, value: string | undefined) {
4262
const data = new DataTransfer();
43-
await addFile(ctx, signal, data, value);
63+
if (value !== undefined) {
64+
await addFile(ctx, signal, data, value);
65+
}
4466
return data.files;
4567
},
46-
async (v, signal) => {
47-
if (v === undefined || v.length === 0) {
48-
value = undefined;
49-
return;
50-
}
51-
try {
52-
value = await fileToDataURL(signal, v[0]!);
53-
} catch (e) {
54-
console.error("Failed to read file", e);
55-
}
68+
onSuccess(list: FileList) {
69+
files = list;
5670
},
57-
(v) => v
58-
);
71+
});
72+
73+
$effect(() => {
74+
if (value === lastValueUpdate) {
75+
return;
76+
}
77+
toValue.abort();
78+
toFiles.run(value);
79+
});
5980
6081
const errors = $derived(getErrors(ctx, config.id));
6182
</script>
@@ -72,9 +93,15 @@
7293
>
7394
<Widget
7495
type="widget"
75-
bind:value={files.value}
76-
processing={files.inputProcessing}
77-
loading={files.outputProcessing}
96+
bind:value={
97+
() => files,
98+
(files) => {
99+
toFiles.abort();
100+
toValue.run(files);
101+
}
102+
}
103+
processing={toValue.isProcessed}
104+
loading={toFiles.isProcessed}
78105
{uiOption}
79106
{handlers}
80107
{errors}

packages/form/src/fields/extra-fields/files.svelte

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
<script lang="ts">
1010
import { fileToDataURL } from "@/lib/file.js";
11-
import { asyncProxy } from "@/lib/svelte.svelte";
11+
import { abortPrevious, createAction } from "@/lib/action.svelte.js";
1212
import {
1313
makeEventHandlers,
1414
getErrors,
@@ -38,30 +38,53 @@
3838
validateField(ctx, config, value)
3939
);
4040
41-
const files = asyncProxy(
42-
async (isRegOnly, signal) => {
43-
if (!value || isRegOnly) {
44-
return;
41+
let lastValueUpdate: string[] | undefined;
42+
const toValue = createAction({
43+
combinator: abortPrevious,
44+
async execute(
45+
signal,
46+
files: FileList | undefined
47+
): Promise<string[] | undefined> {
48+
if (files === undefined) {
49+
return undefined;
4550
}
51+
return Promise.all(
52+
Array.from(files).map((f) => fileToDataURL(signal, f))
53+
);
54+
},
55+
onSuccess(result: string[] | undefined) {
56+
lastValueUpdate = result;
57+
value = result;
58+
},
59+
});
60+
61+
let files = $state.raw<FileList>();
62+
const toFiles = createAction({
63+
combinator: abortPrevious,
64+
async execute(signal, value: string[] | undefined) {
4665
const data = new DataTransfer();
47-
await addFiles(ctx, signal, data, value);
66+
if (value !== undefined) {
67+
await addFiles(ctx, signal, data, value);
68+
}
4869
return data.files;
4970
},
50-
async (v, signal) => {
51-
if (v === undefined || v.length === 0) {
52-
value = [];
53-
return;
54-
}
55-
try {
56-
value = await Promise.all(
57-
Array.from(v).map((f) => fileToDataURL(signal, f))
58-
);
59-
} catch (e) {
60-
console.error("Failed to read file", e);
61-
}
71+
onSuccess(list: FileList) {
72+
files = list;
6273
},
63-
(v) => v
64-
);
74+
});
75+
76+
$effect(() => {
77+
if (
78+
Array.isArray(value) &&
79+
Array.isArray(lastValueUpdate) &&
80+
value.length === lastValueUpdate.length &&
81+
value.every((v, i) => v === lastValueUpdate![i])
82+
) {
83+
return;
84+
}
85+
toValue.abort();
86+
toFiles.run(value);
87+
});
6588
6689
const errors = $derived(getErrors(ctx, config.id));
6790
</script>
@@ -78,9 +101,15 @@
78101
>
79102
<Widget
80103
type="widget"
81-
bind:value={files.value}
82-
processing={files.inputProcessing}
83-
loading={files.outputProcessing}
104+
bind:value={
105+
() => files,
106+
(files) => {
107+
toFiles.abort();
108+
toValue.run(files);
109+
}
110+
}
111+
processing={toValue.isProcessed}
112+
loading={toFiles.isProcessed}
84113
{uiOption}
85114
{handlers}
86115
{errors}

0 commit comments

Comments
 (0)