Skip to content

feat(Form): allow custom components as children #4777

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

Merged
merged 39 commits into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
4211b33
wip
Lukas742 May 17, 2023
32b2f62
Merge branch 'main' into local/feat/new-form
Lukas742 May 24, 2023
90f4b0e
wip
Lukas742 May 24, 2023
72e9732
wip
Lukas742 May 24, 2023
2f33419
wip
Lukas742 May 25, 2023
6d8d302
Merge branch 'main' into local/feat/new-form
Lukas742 May 26, 2023
88ac97b
wip
Lukas742 May 30, 2023
c675c36
wip
Lukas742 May 30, 2023
d87d0f6
wip
Lukas742 May 30, 2023
3ed2f46
Merge branch 'main' into local/feat/new-form
Lukas742 May 30, 2023
8010e83
wip
Lukas742 May 31, 2023
9d71e80
wip
Lukas742 May 31, 2023
60d36e6
Merge branch 'main' into local/feat/new-form
Lukas742 Jun 7, 2023
a1fd36f
Merge branch 'main' into local/feat/new-form
Lukas742 Jun 12, 2023
a7b2ead
Merge branch 'main' into local/feat/new-form
Lukas742 Jun 15, 2023
f1cf54f
wip
Lukas742 Jun 16, 2023
254a0d6
Merge branch 'main' into local/feat/new-form
Lukas742 Jun 20, 2023
7b56ad2
wip
Lukas742 Jun 21, 2023
7e8f56e
Merge branch 'main' into local/feat/new-form
Lukas742 Jun 22, 2023
3f03e0d
wip: finalize
Lukas742 Jun 22, 2023
6344956
comment
Lukas742 Jun 22, 2023
8f41c82
imports
Lukas742 Jun 22, 2023
8346860
wip: fix layouting, replace old form with new one
Lukas742 Jun 22, 2023
528357f
item margins, fix column span
Lukas742 Jun 22, 2023
72f991a
item layouting & cleanup & types
Lukas742 Jun 22, 2023
f27a219
more cleanup & types
Lukas742 Jun 22, 2023
53fdc7b
comment & spread inputs to available space
Lukas742 Jun 23, 2023
63af685
remove comments
Lukas742 Jun 23, 2023
48e5490
last group item margin
Lukas742 Jun 23, 2023
5dff1d2
fix tests
Lukas742 Jun 26, 2023
ddafcdc
Merge branch 'main' into local/feat/new-form
Lukas742 Jun 26, 2023
0ad7444
cleanup
Lukas742 Jun 26, 2023
1201fa1
docs
Lukas742 Jun 26, 2023
64cedae
docs
Lukas742 Jun 26, 2023
e13721d
docs
Lukas742 Jun 26, 2023
8081af8
remove custom width on `FormItem` children
Lukas742 Jun 26, 2023
c54109a
types
Lukas742 Jun 26, 2023
cb47a2f
Merge branch 'main' into local/feat/new-form
Lukas742 Jul 3, 2023
0164863
Merge branch 'main' into local/feat/new-form
Lukas742 Jul 3, 2023
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
6 changes: 3 additions & 3 deletions packages/main/src/components/Form/Form.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,21 @@ describe('Form', () => {
cy.viewport(393, 852); // iPhone 14 Pro
cy.mount(component);
cy.findByText('item 1:').should('have.css', 'grid-column', '1 / span 12');
cy.findByTestId('formInput').parent().should('have.css', 'grid-column', 'auto / span 12');
cy.findByTestId('formInput').parent().should('have.css', 'grid-column', '1 / span 12');
});

it('size M - label should cover 2/12, field 10/12', () => {
cy.viewport(834, 1194); // iPad Pro
cy.mount(component);
cy.findByText('item 1:').should('have.css', 'grid-column', '1 / span 2');
cy.findByTestId('formInput').parent().should('have.css', 'grid-column', 'auto / span 10');
cy.findByTestId('formInput').parent().should('have.css', 'grid-column', '3 / span 10');
});

it('size L - label should cover 1/3, field 2/3', () => {
cy.viewport(1280, 1024);
cy.mount(component);
cy.findByText('item 1:').should('have.css', 'grid-column', '1 / span 4');
cy.findByTestId('formInput').parent().should('have.css', 'grid-column', 'auto / span 8');
cy.findByTestId('formInput').parent().should('have.css', 'grid-column', '5 / span 8');
});

it('size XL - render two columns with 1/3 and 2/3 each', () => {
Expand Down
116 changes: 116 additions & 0 deletions packages/main/src/components/Form/Form.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,122 @@ import * as ComponentStories from './Form.stories';

<ControlsWithNote of={ComponentStories.Default} />

# More Examples

## Form with wrapped FormItems and FormGroups

This feature is supported **since v1.17.0**.

It is possible to nest `FormItem`s and `FormGroup`s in custom components, the only thing you have to take care of is that no other elements (e.g. `div` or `span`) are mounted outside of FilterItems, as this will most likely result in breaking the layout of the `Form`.

<Canvas of={ComponentStories.FormWithCustomComponents} sourceState="none" />

### Code

<details>

<summary>Show Code</summary>

```jsx
const CustomComponent = ({ children }) => {
return <>{children}</>;
};

const CustomComponent2 = () => {
return (
<CustomComponent>
<FormGroup titleText="Group 1 inside custom component2">
<CustomComponent>
<FormItem label="FormItem 1 within group">
<Input />
</FormItem>
<FormItem label="FormItem 2 within group">
<Input />
</FormItem>
</CustomComponent>
</FormGroup>
<FormGroup titleText="Group 2 inside custom component2">
<FormItem label="FormItem 1 within group">
<Input />
</FormItem>
<FormItem label="FormItem 2 within group">
<Input />
</FormItem>
</FormGroup>
</CustomComponent>
);
};

const FormComponent = (props) => {
return (
<Form {...props}>
<FormItem label="Standalone FormItem">
<Input />
</FormItem>
<FormGroup titleText="Standalone FormGroup">
<FormItem label="Standalone FormItem within group">
<Input />
</FormItem>
<FormItem label="Standalone FormItem within group">
<Input />
</FormItem>
</FormGroup>
<FormItem label="Standalone FormItem">
<Input />
</FormItem>
<CustomComponent>
<FormItem label="FormItem within custom component">
<Input />
</FormItem>
</CustomComponent>
<FormGroup titleText="Standalone FormGroup with custom component">
<CustomComponent>
<FormItem label="FormItem 1 within custom component">
<Input />
</FormItem>
<FormItem label="FormItem 2 within custom component">
<Input />
</FormItem>
</CustomComponent>
</FormGroup>
<CustomComponent>
<FormGroup titleText="FormGroup within custom component">
<FormItem label="FormItem 1 within group">
<Input />
</FormItem>
<FormItem label="FormItem 2 within group">
<Input />
</FormItem>
</FormGroup>
</CustomComponent>
<CustomComponent>
<FormGroup titleText="Group 1 inside custom component">
<CustomComponent>
<FormItem label="FormItem 1 within group">
<Input />
</FormItem>
<FormItem label="FormItem 2 within group">
<Input />
</FormItem>
</CustomComponent>
</FormGroup>
<FormGroup titleText="Group 2 inside custom component">
<FormItem label="FormItem 1 within group">
<Input />
</FormItem>
<FormItem label="FormItem 2 within group">
<Input />
</FormItem>
</FormGroup>
</CustomComponent>
<CustomComponent2 />
</Form>
);
};
```

</details>

<Markdown>{SubcomponentsSection}</Markdown>

## Form Group
Expand Down
104 changes: 99 additions & 5 deletions packages/main/src/components/Form/Form.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,9 @@ export const Default: Story = {
<Option>Italy</Option>
</Select>
</FormItem>
<FormItem
style={{ alignSelf: 'start' }}
label={<Label style={{ alignSelf: 'start', paddingTop: '0.25rem' }}>Additional Comment</Label>}
>
<FormItem label={<Label style={{ alignSelf: 'start', paddingTop: '0.25rem' }}>Additional Comment</Label>}>
<TextArea
rows={5}
style={{ width: '210px', '--_ui5_textarea_margin': 0 }}
placeholder="The styles of the Label of the TextArea FormItem is set to: alignSelf: 'start', paddingTop: '0.25rem'"
/>
</FormItem>
Expand Down Expand Up @@ -128,3 +124,101 @@ export const Default: Story = {
);
}
};

const CustomComponent = ({ children }) => {
return <>{children}</>;
};

const CustomComponent2 = () => {
return (
<CustomComponent>
<FormGroup titleText="Group 1 inside custom component2">
<CustomComponent>
<FormItem label="FormItem 1 within group">
<Input />
</FormItem>
<FormItem label="FormItem 2 within group">
<Input />
</FormItem>
</CustomComponent>
</FormGroup>
<FormGroup titleText="Group 2 inside custom component2">
<FormItem label="FormItem 1 within group">
<Input />
</FormItem>
<FormItem label="FormItem 2 within group">
<Input />
</FormItem>
</FormGroup>
</CustomComponent>
);
};

export const FormWithCustomComponents: Story = {
render: (args) => {
return (
<Form {...args}>
<FormItem label="Standalone FormItem">
<Input />
</FormItem>
<FormGroup titleText="Standalone FormGroup">
<FormItem label="Standalone FormItem within group">
<Input />
</FormItem>
<FormItem label="Standalone FormItem within group">
<Input />
</FormItem>
</FormGroup>
<FormItem label="Standalone FormItem">
<Input />
</FormItem>
<CustomComponent>
<FormItem label="FormItem within custom component">
<Input />
</FormItem>
</CustomComponent>
<FormGroup titleText="Standalone FormGroup with custom component">
<CustomComponent>
<FormItem label="FormItem 1 within custom component">
<Input />
</FormItem>
<FormItem label="FormItem 2 within custom component">
<Input />
</FormItem>
</CustomComponent>
</FormGroup>
<CustomComponent>
<FormGroup titleText="FormGroup within custom component">
<FormItem label="FormItem 1 within group">
<Input />
</FormItem>
<FormItem label="FormItem 2 within group">
<Input />
</FormItem>
</FormGroup>
</CustomComponent>
<CustomComponent>
<FormGroup titleText="Group 1 inside custom component">
<CustomComponent>
<FormItem label="FormItem 1 within group">
<Input />
</FormItem>
<FormItem label="FormItem 2 within group">
<Input />
</FormItem>
</CustomComponent>
</FormGroup>
<FormGroup titleText="Group 2 inside custom component">
<FormItem label="FormItem 1 within group">
<Input />
</FormItem>
<FormItem label="FormItem 2 within group">
<Input />
</FormItem>
</FormGroup>
</CustomComponent>
<CustomComponent2 />
</Form>
);
}
};
9 changes: 8 additions & 1 deletion packages/main/src/components/Form/FormContext.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { createContext, useContext } from 'react';
import type { FormContextType, GroupContextType } from './types.js';

export const FormContext = createContext({ labelSpan: null });
export const FormContext = createContext<FormContextType>({ labelSpan: null });

export function useFormContext() {
return useContext(FormContext);
}

export const GroupContext = createContext<GroupContextType>({});

export function useFormGroupContext() {
return useContext(GroupContext);
}
Loading