Skip to content

Commit 64dc32c

Browse files
fix: Fixed FileWidget to work across all themes
Fixes rjsf-team#2095 by making `FileWidget` use the `BaseInputTemplate` for rendering the file input - Updated `@rjsf/utils` to fix two small bugs found while fixing the issue: - `dataURItoBlob()` was updated to deal with parsing errors in `atob()` with malformed URL and to decode the name to a human-readable string - Added additional tests to verify the fixes - `replaceStringParameters()` was updated to split using a regex to deal with situations where the params themselves contain replaceable character identifiers - Added an additional test to verify the bug was fixed - Updated `@rjsf/core` to switch `FileWidget` so that it uses the `BaseInputTemplate` to render the input, passing a new `onChangeOverride` function to deal with file events - Updated `BaseInputTemplate` to favor `onChangeOverride` rather than the default `onChange` handler it builds - Updated the `BaseInputTemplate` in all of the themes to also favor `onChangeOverride` if specified over the default `onChange` handler - Updated the snapshots in all themes to reflect the improved `FileWidget` use of `BaseInputTemplate` in all themes - Updated `@rjsf/bootstrap-4` to delete the `FileWidget` in favor of the improved `core` one - Updated `@rjsf/material-ui` and `@rjsf/mui` to have the `BaseInputTemplate` support the automatic `shrink` of the label when the `type` of the input is `date`, `datetime-local` and `file` - Also removed the `DateWidget` and `DateTimeWidget` in both themes since they were only providing the `shrink` behavior which is now encapsulated in `BaseInputTemplate` - Updated the `CHANGELOG.md` file accordingly
1 parent 744e87c commit 64dc32c

File tree

34 files changed

+565
-389
lines changed

34 files changed

+565
-389
lines changed

CHANGELOG.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,38 @@ it according to semantic versioning. For example, if your PR adds a breaking cha
1515
should change the heading of the (upcoming) version to include a major version bump.
1616
1717
-->
18+
# 5.2.1
19+
20+
## @rjsf/antd
21+
- Updated `BaseInputTemplate` to favor the special `onChangeOverride` provided by the `core` `FileWidget`
22+
23+
## @rjsf/bootstrap-4
24+
- Updated `BaseInputTemplate` to favor the special `onChangeOverride` provided by the `core` `FileWidget`, deleting the theme's `FileWidget`, fixing [#2095](https://github.com/rjsf-team/react-jsonschema-form/issues/2095)
25+
26+
## @rjsf/chakra-ui
27+
- Updated `BaseInputTemplate` to favor the special `onChangeOverride` provided by the `core` `FileWidget`
28+
29+
## @rjsf/core
30+
- Updated the `FileWidget` to render the input using the `BaseInputTemplate` passing a special `onChangeOverride` function to deal with the file events, fixing [#2095](https://github.com/rjsf-team/react-jsonschema-form/issues/2095)
31+
32+
## @rjsf/fluent-ui
33+
- Updated `BaseInputTemplate` to favor the special `onChangeOverride` provided by the `core` `FileWidget`
34+
35+
## @rjsf/material-ui
36+
- Updated `BaseInputTemplate` to favor the special `onChangeOverride` provided by the `core` `FileWidget` and to support automatically shrinking the label for the `date`, `datetime-local` and `file` types
37+
- Removed the `DateWidget` and `DateTimeWidget` since they were only created to provide the label shrinking property
38+
39+
## @rjsf/mui
40+
- Updated `BaseInputTemplate` to favor the special `onChangeOverride` provided by the `core` `FileWidget` and to support automatically shrinking the label for the `date`, `datetime-local` and `file` types
41+
- Removed the `DateWidget` and `DateTimeWidget` since they were only created to provide the label shrinking property
42+
43+
## @rjsf/semantic-ui
44+
- Updated `BaseInputTemplate` to favor the special `onChangeOverride` provided by the `core` `FileWidget`
45+
46+
## @rjsf/utils
47+
- Fixed `dataURItoBlob()` to handle the exception thrown by `atob()` when it is passed a malformed URL, returning an `blob` that indicates the error in the `type` prop
48+
- Fixed `replaceStringParameters()` to improve the replaceable parameters logic so that it works properly when a parameter also contains a replaceable parameter identifier
49+
1850
# 5.2.0
1951

2052
## @rjsf/antd

packages/antd/src/templates/BaseInputTemplate/index.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export default function BaseInputTemplate<
3333
id,
3434
onBlur,
3535
onChange,
36+
onChangeOverride,
3637
onFocus,
3738
options,
3839
placeholder,
@@ -46,8 +47,10 @@ export default function BaseInputTemplate<
4647

4748
const handleNumberChange = (nextValue: number | null) => onChange(nextValue);
4849

49-
const handleTextChange = ({ target }: React.ChangeEvent<HTMLInputElement>) =>
50-
onChange(target.value === "" ? options.emptyValue : target.value);
50+
const handleTextChange = onChangeOverride
51+
? onChangeOverride
52+
: ({ target }: React.ChangeEvent<HTMLInputElement>) =>
53+
onChange(target.value === "" ? options.emptyValue : target.value);
5154

5255
const handleBlur = ({ target }: React.FocusEvent<HTMLInputElement>) =>
5356
onBlur(id, target.value);

packages/antd/test/__snapshots__/Form.test.tsx.snap

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,18 +1602,24 @@ exports[`single fields string field format data-url 1`] = `
16021602
className="form-group field field-string"
16031603
>
16041604
<div>
1605-
<p>
1606-
<input
1607-
aria-describedby="root__error root__description root__help"
1608-
autoFocus={false}
1609-
defaultValue=""
1610-
disabled={false}
1611-
id="root"
1612-
name="root"
1613-
onChange={[Function]}
1614-
type="file"
1615-
/>
1616-
</p>
1605+
<input
1606+
aria-describedby="root__error root__description root__help"
1607+
className="ant-input"
1608+
id="root"
1609+
name="root"
1610+
onBlur={[Function]}
1611+
onChange={[Function]}
1612+
onFocus={[Function]}
1613+
onKeyDown={[Function]}
1614+
placeholder=""
1615+
style={
1616+
Object {
1617+
"width": "100%",
1618+
}
1619+
}
1620+
type="file"
1621+
value=""
1622+
/>
16171623
</div>
16181624
</div>
16191625
<button

packages/bootstrap-4/src/BaseInputTemplate/BaseInputTemplate.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export default function BaseInputTemplate<
2323
type,
2424
value,
2525
onChange,
26+
onChangeOverride,
2627
onBlur,
2728
onFocus,
2829
autofocus,
@@ -61,7 +62,7 @@ export default function BaseInputTemplate<
6162
list={schema.examples ? examplesId<T>(id) : undefined}
6263
{...inputProps}
6364
value={value || value === 0 ? value : ""}
64-
onChange={_onChange}
65+
onChange={onChangeOverride || _onChange}
6566
onBlur={_onBlur}
6667
onFocus={_onFocus}
6768
aria-describedby={ariaDescribedByIds<T>(id, !!schema.examples)}

packages/bootstrap-4/src/FileWidget/FileWidget.tsx

Lines changed: 0 additions & 22 deletions
This file was deleted.

packages/bootstrap-4/src/FileWidget/index.ts

Lines changed: 0 additions & 2 deletions
This file was deleted.

packages/bootstrap-4/src/Widgets/Widgets.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import RadioWidget from "../RadioWidget/RadioWidget";
44
import RangeWidget from "../RangeWidget/RangeWidget";
55
import SelectWidget from "../SelectWidget/SelectWidget";
66
import TextareaWidget from "../TextareaWidget/TextareaWidget";
7-
import FileWidget from "../FileWidget/FileWidget";
87
import {
98
FormContextType,
109
RegistryWidgetsType,
@@ -24,7 +23,6 @@ export function generateWidgets<
2423
RangeWidget,
2524
SelectWidget,
2625
TextareaWidget,
27-
FileWidget,
2826
};
2927
}
3028

packages/bootstrap-4/test/__snapshots__/Form.test.tsx.snap

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,21 +1211,23 @@ exports[`single fields string field format data-url 1`] = `
12111211
>
12121212
12131213
</label>
1214-
<input
1215-
aria-describedby="root__error root__description root__help"
1216-
autoFocus={false}
1217-
className="form-control-file"
1218-
disabled={false}
1219-
id="root"
1220-
name="root"
1221-
onBlur={[Function]}
1222-
onChange={[Function]}
1223-
onFocus={[Function]}
1224-
placeholder=""
1225-
readOnly={false}
1226-
type="file"
1227-
value=""
1228-
/>
1214+
<div>
1215+
<input
1216+
aria-describedby="root__error root__description root__help"
1217+
autoFocus={false}
1218+
className="form-control-file"
1219+
disabled={false}
1220+
id="root"
1221+
name="root"
1222+
onBlur={[Function]}
1223+
onChange={[Function]}
1224+
onFocus={[Function]}
1225+
placeholder=""
1226+
readOnly={false}
1227+
type="file"
1228+
value=""
1229+
/>
1230+
</div>
12291231
12301232
</div>
12311233
</div>

packages/chakra-ui/src/BaseInputTemplate/BaseInputTemplate.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export default function BaseInputTemplate<
2424
schema,
2525
uiSchema,
2626
onChange,
27+
onChangeOverride,
2728
onBlur,
2829
onFocus,
2930
options,
@@ -71,7 +72,7 @@ export default function BaseInputTemplate<
7172
id={id}
7273
name={id}
7374
value={value || value === 0 ? value : ""}
74-
onChange={_onChange}
75+
onChange={onChangeOverride || _onChange}
7576
onBlur={_onBlur}
7677
onFocus={_onFocus}
7778
autoFocus={autofocus}

packages/chakra-ui/test/__snapshots__/Form.test.tsx.snap

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4778,10 +4778,14 @@ exports[`single fields slider field 1`] = `
47784778

47794779
exports[`single fields string field format data-url 1`] = `
47804780
.emotion-1 {
4781+
margin-bottom: 1px;
4782+
}
4783+
4784+
.emotion-3 {
47814785
margin-top: 3px;
47824786
}
47834787
4784-
.emotion-2 {
4788+
.emotion-4 {
47854789
display: -webkit-inline-box;
47864790
display: -webkit-inline-flex;
47874791
display: -ms-inline-flexbox;
@@ -4823,26 +4827,35 @@ exports[`single fields string field format data-url 1`] = `
48234827
role="group"
48244828
>
48254829
<div>
4826-
<p>
4830+
<div
4831+
className="chakra-form-control emotion-1"
4832+
role="group"
4833+
>
48274834
<input
48284835
aria-describedby="root__error root__description root__help"
48294836
autoFocus={false}
4830-
defaultValue=""
4837+
className="chakra-input emotion-0"
48314838
disabled={false}
48324839
id="root"
48334840
name="root"
4841+
onBlur={[Function]}
48344842
onChange={[Function]}
4843+
onFocus={[Function]}
4844+
placeholder=""
4845+
readOnly={false}
4846+
required={false}
48354847
type="file"
4848+
value=""
48364849
/>
4837-
</p>
4850+
</div>
48384851
</div>
48394852
</div>
48404853
</div>
48414854
<div
4842-
className="emotion-1"
4855+
className="emotion-3"
48434856
>
48444857
<button
4845-
className="chakra-button emotion-2"
4858+
className="chakra-button emotion-4"
48464859
disabled={false}
48474860
type="submit"
48484861
>

packages/core/src/components/templates/BaseInputTemplate.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export default function BaseInputTemplate<
2929
onBlur,
3030
onFocus,
3131
onChange,
32+
onChangeOverride,
3233
options,
3334
schema,
3435
uiSchema,
@@ -85,7 +86,7 @@ export default function BaseInputTemplate<
8586
value={inputValue}
8687
{...inputProps}
8788
list={schema.examples ? examplesId<T>(id) : undefined}
88-
onChange={_onChange}
89+
onChange={onChangeOverride || _onChange}
8990
onBlur={_onBlur}
9091
onFocus={_onFocus}
9192
aria-describedby={ariaDescribedByIds<T>(id, !!schema.examples)}

packages/core/src/components/widgets/FileWidget.tsx

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { ChangeEvent, useCallback, useMemo, useState } from "react";
22
import {
3-
ariaDescribedByIds,
43
dataURItoBlob,
4+
getTemplate,
55
FormContextType,
66
Registry,
77
RJSFSchema,
@@ -92,7 +92,7 @@ function FilesInfo<
9292

9393
function extractFileInfo(dataURLs: string[]) {
9494
return dataURLs
95-
.filter((dataURL) => typeof dataURL !== "undefined")
95+
.filter((dataURL) => dataURL)
9696
.map((dataURL) => {
9797
const { blob, name } = dataURItoBlob(dataURL);
9898
return {
@@ -111,17 +111,14 @@ function FileWidget<
111111
T = any,
112112
S extends StrictRJSFSchema = RJSFSchema,
113113
F extends FormContextType = any
114-
>({
115-
multiple,
116-
id,
117-
readonly,
118-
disabled,
119-
onChange,
120-
value,
121-
autofocus = false,
122-
options,
123-
registry,
124-
}: WidgetProps<T, S, F>) {
114+
>(props: WidgetProps<T, S, F>) {
115+
const { disabled, readonly, multiple, onChange, value, options, registry } =
116+
props;
117+
const BaseInputTemplate = getTemplate<"BaseInputTemplate", T, S, F>(
118+
"BaseInputTemplate",
119+
registry,
120+
options
121+
);
125122
const extractedFilesInfo = useMemo(
126123
() =>
127124
Array.isArray(value) ? extractFileInfo(value) : extractFileInfo([value]),
@@ -150,20 +147,14 @@ function FileWidget<
150147

151148
return (
152149
<div>
153-
<p>
154-
<input
155-
id={id}
156-
name={id}
157-
type="file"
158-
disabled={readonly || disabled}
159-
onChange={handleChange}
160-
defaultValue=""
161-
autoFocus={autofocus}
162-
multiple={multiple}
163-
accept={options.accept ? String(options.accept) : undefined}
164-
aria-describedby={ariaDescribedByIds<T>(id)}
165-
/>
166-
</p>
150+
<BaseInputTemplate
151+
{...props}
152+
disabled={disabled || readonly}
153+
type="file"
154+
onChangeOverride={handleChange}
155+
value=""
156+
accept={options.accept ? String(options.accept) : undefined}
157+
/>
167158
<FilesInfo<T, S, F> filesInfo={filesInfo} registry={registry} />
168159
</div>
169160
);

packages/fluent-ui/src/BaseInputTemplate/BaseInputTemplate.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export default function BaseInputTemplate<
6565
label,
6666
value,
6767
onChange,
68+
onChangeOverride,
6869
onBlur,
6970
onFocus,
7071
autofocus,
@@ -103,7 +104,7 @@ export default function BaseInputTemplate<
103104
// name={name}
104105
{...inputProps}
105106
value={value || value === 0 ? value : ""}
106-
onChange={_onChange as any}
107+
onChange={onChangeOverride || _onChange}
107108
onBlur={_onBlur}
108109
onFocus={_onFocus}
109110
errorMessage={(rawErrors || []).join("\n")}

0 commit comments

Comments
 (0)