Skip to content

Commit

Permalink
fix: Fixed FileWidget to work across all themes
Browse files Browse the repository at this point in the history
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
  • Loading branch information
heath-freenome committed Mar 5, 2023
1 parent bf9424d commit bdb7b08
Show file tree
Hide file tree
Showing 34 changed files with 565 additions and 389 deletions.
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,38 @@ it according to semantic versioning. For example, if your PR adds a breaking cha
should change the heading of the (upcoming) version to include a major version bump.
-->
# 5.2.1

## @rjsf/antd
- Updated `BaseInputTemplate` to favor the special `onChangeOverride` provided by the `core` `FileWidget`

## @rjsf/bootstrap-4
- 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)

## @rjsf/chakra-ui
- Updated `BaseInputTemplate` to favor the special `onChangeOverride` provided by the `core` `FileWidget`

## @rjsf/core
- 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)

## @rjsf/fluent-ui
- Updated `BaseInputTemplate` to favor the special `onChangeOverride` provided by the `core` `FileWidget`

## @rjsf/material-ui
- 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
- Removed the `DateWidget` and `DateTimeWidget` since they were only created to provide the label shrinking property

## @rjsf/mui
- 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
- Removed the `DateWidget` and `DateTimeWidget` since they were only created to provide the label shrinking property

## @rjsf/semantic-ui
- Updated `BaseInputTemplate` to favor the special `onChangeOverride` provided by the `core` `FileWidget`

## @rjsf/utils
- 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
- Fixed `replaceStringParameters()` to improve the replaceable parameters logic so that it works properly when a parameter also contains a replaceable parameter identifier

# 5.2.0

## @rjsf/antd
Expand Down
7 changes: 5 additions & 2 deletions packages/antd/src/templates/BaseInputTemplate/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export default function BaseInputTemplate<
id,
onBlur,
onChange,
onChangeOverride,
onFocus,
options,
placeholder,
Expand All @@ -46,8 +47,10 @@ export default function BaseInputTemplate<

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

const handleTextChange = ({ target }: React.ChangeEvent<HTMLInputElement>) =>
onChange(target.value === "" ? options.emptyValue : target.value);
const handleTextChange = onChangeOverride
? onChangeOverride
: ({ target }: React.ChangeEvent<HTMLInputElement>) =>
onChange(target.value === "" ? options.emptyValue : target.value);

const handleBlur = ({ target }: React.FocusEvent<HTMLInputElement>) =>
onBlur(id, target.value);
Expand Down
30 changes: 18 additions & 12 deletions packages/antd/test/__snapshots__/Form.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1602,18 +1602,24 @@ exports[`single fields string field format data-url 1`] = `
className="form-group field field-string"
>
<div>
<p>
<input
aria-describedby="root__error root__description root__help"
autoFocus={false}
defaultValue=""
disabled={false}
id="root"
name="root"
onChange={[Function]}
type="file"
/>
</p>
<input
aria-describedby="root__error root__description root__help"
className="ant-input"
id="root"
name="root"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
placeholder=""
style={
Object {
"width": "100%",
}
}
type="file"
value=""
/>
</div>
</div>
<button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default function BaseInputTemplate<
type,
value,
onChange,
onChangeOverride,
onBlur,
onFocus,
autofocus,
Expand Down Expand Up @@ -61,7 +62,7 @@ export default function BaseInputTemplate<
list={schema.examples ? examplesId<T>(id) : undefined}
{...inputProps}
value={value || value === 0 ? value : ""}
onChange={_onChange}
onChange={onChangeOverride || _onChange}
onBlur={_onBlur}
onFocus={_onFocus}
aria-describedby={ariaDescribedByIds<T>(id, !!schema.examples)}
Expand Down
22 changes: 0 additions & 22 deletions packages/bootstrap-4/src/FileWidget/FileWidget.tsx

This file was deleted.

2 changes: 0 additions & 2 deletions packages/bootstrap-4/src/FileWidget/index.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/bootstrap-4/src/Widgets/Widgets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import RadioWidget from "../RadioWidget/RadioWidget";
import RangeWidget from "../RangeWidget/RangeWidget";
import SelectWidget from "../SelectWidget/SelectWidget";
import TextareaWidget from "../TextareaWidget/TextareaWidget";
import FileWidget from "../FileWidget/FileWidget";
import {
FormContextType,
RegistryWidgetsType,
Expand All @@ -24,7 +23,6 @@ export function generateWidgets<
RangeWidget,
SelectWidget,
TextareaWidget,
FileWidget,
};
}

Expand Down
32 changes: 17 additions & 15 deletions packages/bootstrap-4/test/__snapshots__/Form.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1211,21 +1211,23 @@ exports[`single fields string field format data-url 1`] = `
>
</label>
<input
aria-describedby="root__error root__description root__help"
autoFocus={false}
className="form-control-file"
disabled={false}
id="root"
name="root"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
placeholder=""
readOnly={false}
type="file"
value=""
/>
<div>
<input
aria-describedby="root__error root__description root__help"
autoFocus={false}
className="form-control-file"
disabled={false}
id="root"
name="root"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
placeholder=""
readOnly={false}
type="file"
value=""
/>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default function BaseInputTemplate<
schema,
uiSchema,
onChange,
onChangeOverride,
onBlur,
onFocus,
options,
Expand Down Expand Up @@ -71,7 +72,7 @@ export default function BaseInputTemplate<
id={id}
name={id}
value={value || value === 0 ? value : ""}
onChange={_onChange}
onChange={onChangeOverride || _onChange}
onBlur={_onBlur}
onFocus={_onFocus}
autoFocus={autofocus}
Expand Down
25 changes: 19 additions & 6 deletions packages/chakra-ui/test/__snapshots__/Form.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4778,10 +4778,14 @@ exports[`single fields slider field 1`] = `

exports[`single fields string field format data-url 1`] = `
.emotion-1 {
margin-bottom: 1px;
}
.emotion-3 {
margin-top: 3px;
}
.emotion-2 {
.emotion-4 {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
Expand Down Expand Up @@ -4823,26 +4827,35 @@ exports[`single fields string field format data-url 1`] = `
role="group"
>
<div>
<p>
<div
className="chakra-form-control emotion-1"
role="group"
>
<input
aria-describedby="root__error root__description root__help"
autoFocus={false}
defaultValue=""
className="chakra-input emotion-0"
disabled={false}
id="root"
name="root"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
placeholder=""
readOnly={false}
required={false}
type="file"
value=""
/>
</p>
</div>
</div>
</div>
</div>
<div
className="emotion-1"
className="emotion-3"
>
<button
className="chakra-button emotion-2"
className="chakra-button emotion-4"
disabled={false}
type="submit"
>
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/components/templates/BaseInputTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default function BaseInputTemplate<
onBlur,
onFocus,
onChange,
onChangeOverride,
options,
schema,
uiSchema,
Expand Down Expand Up @@ -85,7 +86,7 @@ export default function BaseInputTemplate<
value={inputValue}
{...inputProps}
list={schema.examples ? examplesId<T>(id) : undefined}
onChange={_onChange}
onChange={onChangeOverride || _onChange}
onBlur={_onBlur}
onFocus={_onFocus}
aria-describedby={ariaDescribedByIds<T>(id, !!schema.examples)}
Expand Down
45 changes: 18 additions & 27 deletions packages/core/src/components/widgets/FileWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { ChangeEvent, useCallback, useMemo, useState } from "react";
import {
ariaDescribedByIds,
dataURItoBlob,
getTemplate,
FormContextType,
Registry,
RJSFSchema,
Expand Down Expand Up @@ -92,7 +92,7 @@ function FilesInfo<

function extractFileInfo(dataURLs: string[]) {
return dataURLs
.filter((dataURL) => typeof dataURL !== "undefined")
.filter((dataURL) => dataURL)
.map((dataURL) => {
const { blob, name } = dataURItoBlob(dataURL);
return {
Expand All @@ -111,17 +111,14 @@ function FileWidget<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>({
multiple,
id,
readonly,
disabled,
onChange,
value,
autofocus = false,
options,
registry,
}: WidgetProps<T, S, F>) {
>(props: WidgetProps<T, S, F>) {
const { disabled, readonly, multiple, onChange, value, options, registry } =
props;
const BaseInputTemplate = getTemplate<"BaseInputTemplate", T, S, F>(
"BaseInputTemplate",
registry,
options
);
const extractedFilesInfo = useMemo(
() =>
Array.isArray(value) ? extractFileInfo(value) : extractFileInfo([value]),
Expand Down Expand Up @@ -150,20 +147,14 @@ function FileWidget<

return (
<div>
<p>
<input
id={id}
name={id}
type="file"
disabled={readonly || disabled}
onChange={handleChange}
defaultValue=""
autoFocus={autofocus}
multiple={multiple}
accept={options.accept ? String(options.accept) : undefined}
aria-describedby={ariaDescribedByIds<T>(id)}
/>
</p>
<BaseInputTemplate
{...props}
disabled={disabled || readonly}
type="file"
onChangeOverride={handleChange}
value=""
accept={options.accept ? String(options.accept) : undefined}
/>
<FilesInfo<T, S, F> filesInfo={filesInfo} registry={registry} />
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export default function BaseInputTemplate<
label,
value,
onChange,
onChangeOverride,
onBlur,
onFocus,
autofocus,
Expand Down Expand Up @@ -103,7 +104,7 @@ export default function BaseInputTemplate<
// name={name}
{...inputProps}
value={value || value === 0 ? value : ""}
onChange={_onChange as any}
onChange={onChangeOverride || _onChange}
onBlur={_onBlur}
onFocus={_onFocus}
errorMessage={(rawErrors || []).join("\n")}
Expand Down
Loading

0 comments on commit bdb7b08

Please sign in to comment.