Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: support custom attributes as functions (do not execute them) #86

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@remoteoss/json-schema-form",
"version": "0.11.1-beta.0",
"version": "0.11.2-dev.20240729104214",
"description": "Headless UI form powered by JSON Schemas",
"author": "Remote.com <engineering@remote.com> (https://remote.com/)",
"license": "MIT",
Expand Down
12 changes: 10 additions & 2 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,18 @@ function updateField(field, requiredFields, node, formValues, logic, config) {

const updateAttributes = (fieldAttrs) => {
Object.entries(fieldAttrs).forEach(([key, value]) => {
sandrina-p marked this conversation as resolved.
Show resolved Hide resolved
// some attributes' value (eg "schema") are a function, so we need to call it here
field[key] = typeof value === 'function' ? value() : value;
field[key] = value;

if (key === 'schema' && typeof value === 'function') {
// key "schema" refers to YupSchema that needs to be processed for validations.
field[key] = value();
}

if (key === 'value') {
/* NOTE/TODO: This section does not have any unit test. Be careful when changing this.
You'll need to check the internal MRs !9266 and !6572 (or other through git blame)
to better understand the reason. Then try to remove this workaround and/or write comprehensive unit tests. */

// The value of the field should not be driven by the json-schema,
// unless it's a read-only field
// If the readOnly property has changed, use that updated value,
Expand Down
69 changes: 69 additions & 0 deletions src/tests/createHeadlessForm.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2177,6 +2177,75 @@ describe('createHeadlessForm', () => {
});
});

it('pass custom attributes as function', () => {
function FakeComponent(props) {
const { label, description } = props;
return `A React component with ${label} and ${description}`;
}
// Any custom attributes must be inside "x-jsf-presentation"
const { fields, handleValidation } = createHeadlessForm({
properties: {
field_a: {
title: 'Field A',
'x-jsf-presentation': {
inputType: 'text',
MyComponent: FakeComponent,
},
},
field_b: {
title: 'Field B',
'x-jsf-presentation': {
inputType: 'text',
MyComponent: FakeComponent,
},
},
},
allOf: [
{
if: {
properties: {
field_a: { const: 'yes' },
},
required: ['field_a'],
},
then: {
required: ['field_b'],
},
},
],
});

const fieldA = getField(fields, 'field_a');
expect(fieldA).toMatchObject({
label: 'Field A',
MyComponent: expect.any(Function),
});

const fieldB = getField(fields, 'field_b');
expect(fieldB).toMatchObject({
label: 'Field B',
required: false,
MyComponent: expect.any(Function),
});

const fakeProps = { label: 'Field B', description: 'fake description' };
expect(fieldB.MyComponent(fakeProps)).toBe(
'A React component with Field B and fake description'
);

// Ensure "MyComponent" attribute still exsits after a validation cycle.
// This covers the updateField(). Check PR for more context.
handleValidation({ field_a: 'yes' });

expect(getField(fields, 'field_a')).toMatchObject({
MyComponent: expect.any(Function),
});
expect(getField(fields, 'field_b')).toMatchObject({
required: true,
MyComponent: expect.any(Function),
});
});

it('passes scopedJsonSchema to each field', () => {
const { fields } = createHeadlessForm(schemaWithoutInputTypes, {
strictInputType: false,
Expand Down
Loading