fix(ui): array fields not respecting width styles in row layouts (#13986)
### What? This PR applies `mergeFieldStyles` to the `ArrayFieldComponent` component, ensuring that custom admin styles such as `width` are correctly respected when Array fields are placed inside row layouts. ### Why? Previously, Array fields did not inherit or apply their `admin.width` (or other merged field styles). For example, when placing two array fields side by side inside a row with `width: '50%'`, the widths were ignored, causing layout issues. ### How? - Imported and used `mergeFieldStyles` within `ArrayFieldComponent`. - Applied the merged styles to the root `<div>` via the `style` prop, consistent with how other field components (like `TextField`) handle styles. Fixes #13973 --- - To see the specific tasks where the Asana app for GitHub is being used, see below: - https://app.asana.com/0/0/1211511898438801
This commit is contained in:
@@ -6,7 +6,7 @@ import type {
|
||||
} from 'payload'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import React, { Fragment, useCallback } from 'react'
|
||||
import React, { Fragment, useCallback, useMemo } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import type { ClipboardPasteData } from '../../elements/ClipboardAction/types.js'
|
||||
@@ -36,6 +36,7 @@ import { useDocumentInfo } from '../../providers/DocumentInfo/index.js'
|
||||
import { useLocale } from '../../providers/Locale/index.js'
|
||||
import { useTranslation } from '../../providers/Translation/index.js'
|
||||
import { scrollToID } from '../../utilities/scrollToID.js'
|
||||
import { mergeFieldStyles } from '../mergeFieldStyles.js'
|
||||
import { fieldBaseClass } from '../shared/index.js'
|
||||
import { ArrayRow } from './ArrayRow.js'
|
||||
import './index.scss'
|
||||
@@ -44,6 +45,7 @@ const baseClass = 'array-field'
|
||||
|
||||
export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => {
|
||||
const {
|
||||
field,
|
||||
field: {
|
||||
name,
|
||||
type,
|
||||
@@ -299,6 +301,8 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => {
|
||||
const showRequired = (readOnly || disabled) && rows.length === 0
|
||||
const showMinRows = (rows.length && rows.length < minRows) || (required && rows.length === 0)
|
||||
|
||||
const styles = useMemo(() => mergeFieldStyles(field), [field])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
@@ -310,6 +314,7 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => {
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
id={`field-${path.replace(/\./g, '__')}`}
|
||||
style={styles}
|
||||
>
|
||||
{showError && (
|
||||
<RenderCustomComponent
|
||||
|
||||
@@ -224,8 +224,49 @@ describe('Row', () => {
|
||||
getComputedStyle(el).getPropertyValue('--field-width').trim(),
|
||||
)
|
||||
|
||||
expect(leftVar).toBe('50%')
|
||||
expect(rightVar).toBe('50%')
|
||||
await expect(() => {
|
||||
expect(leftVar).toBe('50%')
|
||||
expect(rightVar).toBe('50%')
|
||||
}).toPass()
|
||||
|
||||
// Also assert inline style contains the var (robust to other inline styles)
|
||||
await expect(left).toHaveAttribute('style', /--field-width:\s*50%/)
|
||||
await expect(right).toHaveAttribute('style', /--field-width:\s*50%/)
|
||||
|
||||
// 2) Layout reflects the widths (same row, equal widths)
|
||||
const leftBox = await left.boundingBox()
|
||||
const rightBox = await right.boundingBox()
|
||||
|
||||
await expect(() => {
|
||||
// Same row
|
||||
expect(Math.round(leftBox.y)).toEqual(Math.round(rightBox.y))
|
||||
// Equal width (tolerate sub-pixel differences)
|
||||
expect(Math.round(leftBox.width)).toEqual(Math.round(rightBox.width))
|
||||
}).toPass()
|
||||
})
|
||||
|
||||
test('should respect admin.width for array fields inside a row', async () => {
|
||||
await page.goto(url.create)
|
||||
|
||||
// Target the Array field wrappers
|
||||
const left = page.locator('#field-arrayLeftColumn')
|
||||
const right = page.locator('#field-arrayRightColumn')
|
||||
|
||||
await expect(left).toBeVisible()
|
||||
await expect(right).toBeVisible()
|
||||
|
||||
// 1) CSS variable is applied (via mergeFieldStyles)
|
||||
const leftVar = await left.evaluate((el) =>
|
||||
getComputedStyle(el).getPropertyValue('--field-width').trim(),
|
||||
)
|
||||
const rightVar = await right.evaluate((el) =>
|
||||
getComputedStyle(el).getPropertyValue('--field-width').trim(),
|
||||
)
|
||||
|
||||
await expect(() => {
|
||||
expect(leftVar).toBe('50%')
|
||||
expect(rightVar).toBe('50%')
|
||||
}).toPass()
|
||||
|
||||
// Also assert inline style contains the var (robust to other inline styles)
|
||||
await expect(left).toHaveAttribute('style', /--field-width:\s*50%/)
|
||||
|
||||
@@ -178,6 +178,37 @@ const RowFields: CollectionConfig = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'row',
|
||||
fields: [
|
||||
{
|
||||
name: 'arrayLeftColumn',
|
||||
type: 'array',
|
||||
admin: {
|
||||
width: '50%',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'leftArrayChild',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'arrayRightColumn',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'rightArrayChild',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
admin: {
|
||||
width: '50%',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -1194,6 +1194,18 @@ export interface RowField {
|
||||
blockType: 'rightTextBlock';
|
||||
}[]
|
||||
| null;
|
||||
arrayLeftColumn?:
|
||||
| {
|
||||
leftArrayChild?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
arrayRightColumn?:
|
||||
| {
|
||||
rightArrayChild?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
@@ -2904,6 +2916,18 @@ export interface RowFieldsSelect<T extends boolean = true> {
|
||||
blockName?: T;
|
||||
};
|
||||
};
|
||||
arrayLeftColumn?:
|
||||
| T
|
||||
| {
|
||||
leftArrayChild?: T;
|
||||
id?: T;
|
||||
};
|
||||
arrayRightColumn?:
|
||||
| T
|
||||
| {
|
||||
rightArrayChild?: T;
|
||||
id?: T;
|
||||
};
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user