fix(ux): input error messages no longer overlap adjacent fields in forms (#21886)
## Context `InputErrorHelper` used `position: absolute` which took the error message out of normal document flow. In multi-field grid layouts (e.g. the HTTP Request workflow node editor), this caused the error text to render on top of the input below it instead of pushing it down. ## Solution Removed `position: absolute` from `InputErrorHelper`. The error message now participates in normal document flow and pushes subsequent content downward, as expected in modern forms. ## Test plan - [x] Open the HTTP Request node editor, fill in a field incorrectly — error message appears below the field without overlapping the next input - [x] Verify single-field forms still display error messages correctly 🤖 Generated with [Claude Code](https://claude.ai/claude-code) <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21886?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: Emmanuel Hernandez <emmanuel.hernandez@clickbalance.com> Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
committed by
GitHub
parent
6ee5413951
commit
33d2441a93
+1
-2
@@ -5,7 +5,6 @@ import {
|
||||
} from '@/advanced-text-editor/hooks/useAdvancedTextEditor';
|
||||
import { FormFieldInputContainer } from '@/object-record/record-field/ui/form-types/components/FormFieldInputContainer';
|
||||
import { type VariablePickerComponent } from '@/object-record/record-field/ui/form-types/types/VariablePickerComponent';
|
||||
import { InputErrorHelper } from '@/ui/input/components/InputErrorHelper';
|
||||
import { InputHint } from '@/ui/input/components/InputHint';
|
||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
import { useFullScreenModal } from '@/ui/layout/fullscreen/hooks/useFullScreenModal';
|
||||
@@ -243,7 +242,7 @@ export const FormAdvancedTextFieldInput = ({
|
||||
</StyledAdvancedTextFieldInnerContainer>
|
||||
</StyledAdvancedTextFieldFieldContainer>
|
||||
{hint && <InputHint>{hint}</InputHint>}
|
||||
{error && <InputErrorHelper>{error}</InputErrorHelper>}
|
||||
{error && <InputHint danger>{error}</InputHint>}
|
||||
</FormFieldInputContainer>
|
||||
</StyledAdvancedTextFieldContainerWrapper>
|
||||
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ import { FormFieldInputRowContainer } from '@/object-record/record-field/ui/form
|
||||
import { TextVariableEditor } from '@/object-record/record-field/ui/form-types/components/TextVariableEditor';
|
||||
import { useTextVariableEditor } from '@/object-record/record-field/ui/form-types/hooks/useTextVariableEditor';
|
||||
import { type VariablePickerComponent } from '@/object-record/record-field/ui/form-types/types/VariablePickerComponent';
|
||||
import { InputErrorHelper } from '@/ui/input/components/InputErrorHelper';
|
||||
import { InputHint } from '@/ui/input/components/InputHint';
|
||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useId } from 'react';
|
||||
@@ -95,7 +95,7 @@ export const FormFilesFieldInput = ({
|
||||
/>
|
||||
)}
|
||||
</FormFieldInputRowContainer>
|
||||
<InputErrorHelper>{error}</InputErrorHelper>
|
||||
{error && <InputHint danger>{error}</InputHint>}
|
||||
</FormFieldInputContainer>
|
||||
);
|
||||
};
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@ import { FormFieldInputRowContainer } from '@/object-record/record-field/ui/form
|
||||
import { TextVariableEditor } from '@/object-record/record-field/ui/form-types/components/TextVariableEditor';
|
||||
import { useTextVariableEditor } from '@/object-record/record-field/ui/form-types/hooks/useTextVariableEditor';
|
||||
import { type VariablePickerComponent } from '@/object-record/record-field/ui/form-types/types/VariablePickerComponent';
|
||||
import { InputErrorHelper } from '@/ui/input/components/InputErrorHelper';
|
||||
import { InputHint } from '@/ui/input/components/InputHint';
|
||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
import { useId } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -90,7 +90,7 @@ export const FormRawJsonFieldInput = ({
|
||||
/>
|
||||
)}
|
||||
</FormFieldInputRowContainer>
|
||||
<InputErrorHelper>{error}</InputErrorHelper>
|
||||
{error && <InputHint danger>{error}</InputHint>}
|
||||
</FormFieldInputContainer>
|
||||
);
|
||||
};
|
||||
|
||||
+30
@@ -17,6 +17,36 @@ export default meta;
|
||||
|
||||
type Story = StoryObj<typeof FormRawJsonFieldInput>;
|
||||
|
||||
export const WithError: Story = {
|
||||
args: {
|
||||
label: 'Body',
|
||||
placeholder: 'Enter valid json',
|
||||
error:
|
||||
'Use only letters, numbers, underscores, dots or hyphens (max 64 characters).',
|
||||
onChange: fn(),
|
||||
},
|
||||
render: (args) => (
|
||||
<div style={{ width: 240 }}>
|
||||
<FormRawJsonFieldInput {...args} />
|
||||
<FormRawJsonFieldInput
|
||||
label="Headers"
|
||||
placeholder="Enter valid json"
|
||||
defaultValue={null}
|
||||
onChange={fn()}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const error = await canvas.findByText(
|
||||
'Use only letters, numbers, underscores, dots or hyphens (max 64 characters).',
|
||||
);
|
||||
|
||||
expect(error).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
label: 'JSON field',
|
||||
|
||||
Reference in New Issue
Block a user