diff --git a/.changeset/collection-row-baseline.md b/.changeset/collection-row-baseline.md new file mode 100644 index 0000000000..18c159efe0 --- /dev/null +++ b/.changeset/collection-row-baseline.md @@ -0,0 +1,7 @@ +--- +'@coveord/plasma-mantine': patch +--- + +Fix `Collection` horizontal rows shifting out of alignment when an input shows a validation error + +The drag handle and remove button are now also vertically centered on the inputs in the horizontal and legacy layouts. diff --git a/packages/mantine/src/components/Collection/Collection.module.css b/packages/mantine/src/components/Collection/Collection.module.css index b5776d5e46..459f6435a8 100644 --- a/packages/mantine/src/components/Collection/Collection.module.css +++ b/packages/mantine/src/components/Collection/Collection.module.css @@ -10,6 +10,8 @@ } .item { + --collection-control-offset: 3px; + align-items: baseline; flex-wrap: nowrap; @@ -19,6 +21,13 @@ } } +/* Baseline-aligned rows put the icon's bottom edge on the text baseline; the offset centers it on the input instead */ +.dragHandle, +.removeButton { + position: relative; + top: var(--collection-control-offset, 0); +} + .dragHandle { cursor: grab; display: flex; diff --git a/packages/mantine/src/components/Collection/layouts/horizontal-layout/HorizontalLayout.module.css b/packages/mantine/src/components/Collection/layouts/horizontal-layout/HorizontalLayout.module.css index 06f497ebc1..ea58708bd6 100644 --- a/packages/mantine/src/components/Collection/layouts/horizontal-layout/HorizontalLayout.module.css +++ b/packages/mantine/src/components/Collection/layouts/horizontal-layout/HorizontalLayout.module.css @@ -22,9 +22,11 @@ } .row { + --collection-control-offset: 3px; + display: flex; gap: var(--mantine-spacing-sm); - align-items: center; + align-items: baseline; } .row[data-isdragging='true'] { diff --git a/packages/mantine/src/components/Collection/layouts/vertical-layout/VerticalLayout.module.css b/packages/mantine/src/components/Collection/layouts/vertical-layout/VerticalLayout.module.css index d73ce96a42..711d14365d 100644 --- a/packages/mantine/src/components/Collection/layouts/vertical-layout/VerticalLayout.module.css +++ b/packages/mantine/src/components/Collection/layouts/vertical-layout/VerticalLayout.module.css @@ -1,4 +1,6 @@ .item { + --collection-control-offset: 0; + border: 1px solid var(--mantine-color-gray-3); border-radius: var(--mantine-radius-default); padding: var(--mantine-spacing-md); diff --git a/packages/storybook/src/components/forms-and-inputs/array/Collection.stories.tsx b/packages/storybook/src/components/forms-and-inputs/array/Collection.stories.tsx index c33e302734..debf29ebf5 100644 --- a/packages/storybook/src/components/forms-and-inputs/array/Collection.stories.tsx +++ b/packages/storybook/src/components/forms-and-inputs/array/Collection.stories.tsx @@ -89,6 +89,12 @@ export const Demo: StoryObj = { {name: 'Bob Johnson', email: 'bob@example.com'}, ], }, + validate: { + contacts: { + email: (value) => (/^\S+@\S+\.\S+$/.test(value) ? null : 'Invalid email'), + }, + }, + validateInputOnBlur: true, enhanceGetInputProps: (payload) => ({ ...enhanceWithCollectionProps(payload, 'contacts'), readOnly: props.readOnly, @@ -141,6 +147,47 @@ export const Demo: StoryObj = { }, }; +export const CollectionValidationErrors: Story = { + tags: ['!dev'], + render: () => { + const form = useForm({ + initialValues: { + contacts: [ + {name: 'Alice Smith', email: 'alice@'}, + {name: '', email: 'bob@example.com'}, + ], + }, + initialErrors: { + 'contacts.0.email': 'Invalid email', + 'contacts.1.name': 'Name is required', + }, + enhanceGetInputProps: (payload) => enhanceWithCollectionProps(payload, 'contacts'), + }); + + return ( + + {...form.getInputProps('contacts')} + w={600} + label="Rows stay aligned when a cell shows an error" + draggable + newItem={{name: '', email: ''}} + layout={Collection.Layouts.Horizontal} + columns={[ + { + header: 'Name', + cell: (item, index) => , + maxSize: 150, + }, + { + header: 'Email', + cell: (item, index) => , + }, + ]} + /> + ); + }, +}; + /** * Legacy children render prop pattern. *