Skip to content

Commit

Permalink
fix(field): remove the need for wrapper:false in createField (#229)
Browse files Browse the repository at this point in the history
  • Loading branch information
EdieLemoine authored Jan 10, 2024
1 parent bf2d9c5 commit 86aa72c
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 24 deletions.
6 changes: 3 additions & 3 deletions apps/demo/src/views/NewFormView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
<div>
<h1>Form without fields array</h1>
<p>
These forms are defined entirely in the template. The components can be placed anywhere in the template. When
<code>wrapper: false</code> is passed when creating the component, you need to manually place the Label and Errors
component as well.
These forms are defined entirely in the template. The components can be placed anywhere in the template. You can
even choose to manually place the Label and Errors components as well.
</p>

<div class="gap-2 grid grid-cols-2 grid-flow-row mt-4">
Expand Down Expand Up @@ -184,6 +183,7 @@ const Email = createField({
name: 'email',
label: 'Email',
component: TTextInput,
// This is necessary because there's a global wrapper defined in the form options.
wrapper: false,
props: {
type: 'email',
Expand Down
21 changes: 6 additions & 15 deletions libs/core/src/utils/createField.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ describe('createField', () => {
const field = createField({name: 'test', ref: ref('value'), component: 'input'});

expect(field).toStrictEqual({
Component: expect.any(Object),
Component: expect.objectContaining({render: expect.any(Function)}),
Errors: expect.objectContaining({__asyncLoader: expect.any(Function)}),
Label: expect.objectContaining({__asyncLoader: expect.any(Function)}),
field: {name: 'test', ref: 'value', component: 'input'},
ref: 'value',
});
Expand All @@ -35,24 +37,14 @@ describe('createField', () => {
const field = createField({name: 'test', ref: ref('value2'), component: testComponent});

expect(field).toStrictEqual({
Component: expect.any(Object),
Component: expect.objectContaining({render: expect.any(Function)}),
Errors: expect.objectContaining({__asyncLoader: expect.any(Function)}),
Label: expect.objectContaining({__asyncLoader: expect.any(Function)}),
field: {name: 'test', ref: 'value2', component: testComponent},
ref: 'value2',
});
});

it('creates a modular field if wrapper is false', () => {
const field = createField({name: 'test', ref: ref('value'), component: 'input', wrapper: false});

expect(field).toStrictEqual({
Component: expect.any(Object),
Errors: expect.any(Object),
Label: expect.any(Object),
field: {name: 'test', ref: 'value', component: 'input', wrapper: false},
ref: 'value',
});
});

describe('rendering inside forms', () => {
afterEach(() => {
cleanup();
Expand Down Expand Up @@ -88,7 +80,6 @@ describe('createField', () => {
label: 'fieldLabel',
ref: ref('value2'),
component: testComponent,
wrapper: false,
});

const wrapper = render(form.Component, {
Expand Down
16 changes: 10 additions & 6 deletions libs/core/src/utils/createField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
reactive,
type ComputedRef,
type Component,
defineAsyncComponent,
} from 'vue';
import {isOfType} from '@myparcel/ts-utils';
import {
Expand Down Expand Up @@ -53,8 +54,8 @@ const createMainComponent = <Type = unknown, Props extends ComponentProps = Comp
});
};

const createLabelComponent = (field: AnyElementConfiguration): Component =>
defineComponent({
const createLabelComponent = (field: AnyElementConfiguration): Component => {
return defineComponent({
setup() {
const form = useForm();
const element = computed(() => field.name && form.getField(field.name));
Expand All @@ -70,6 +71,7 @@ const createLabelComponent = (field: AnyElementConfiguration): Component =>
return this.element && h('label', {for: this.element.attributes.id ?? this.element.name}, [this.element.label]);
},
});
};

const createErrorComponent = (field: AnyElementConfiguration): Component => {
return defineComponent({
Expand All @@ -92,6 +94,10 @@ const createErrorComponent = (field: AnyElementConfiguration): Component => {
});
};

const createAsyncComponent = <C extends Component>(cb: () => C) => {
return markRaw(defineAsyncComponent(() => Promise.resolve(cb())));
};

export const createField = <Type = unknown, Props extends ComponentProps = ComponentProps>(
field: AnyElementConfiguration<Type, Props>,
): ModularCreatedElement<Type, Props> => {
Expand All @@ -103,10 +109,8 @@ export const createField = <Type = unknown, Props extends ComponentProps = Compo
...(isOfType<InteractiveElementConfiguration>(field, 'ref') && {
ref: (field.ref ?? ref<Type>()) as Type extends undefined ? undefined : Ref<Type>,

...(field.wrapper === false && {
Label: markRaw(createLabelComponent(field)),
Errors: markRaw(createErrorComponent(field)),
}),
Label: createAsyncComponent(() => createLabelComponent(field)),
Errors: createAsyncComponent(() => createErrorComponent(field)),
}),
});
};

0 comments on commit 86aa72c

Please sign in to comment.