diff --git a/pages/key-value-pairs/permutations.page.tsx b/pages/key-value-pairs/permutations.page.tsx index deb2bde5056..440669b0a11 100644 --- a/pages/key-value-pairs/permutations.page.tsx +++ b/pages/key-value-pairs/permutations.page.tsx @@ -393,6 +393,16 @@ const permutations = createPermutations([ ], ], }, + { + columns: [5, 6], + minColumnWidth: [undefined, 100], + items: [ + Array.from({ length: 7 }, (_, i) => ({ + label: `Label for key ${i + 1}`, + value: `Value ${i + 1}`, + })), + ], + }, ]); export default function KeyValueScenario() { diff --git a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap index 84b2d76f567..0ae94d9f841 100644 --- a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap +++ b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap @@ -18611,8 +18611,9 @@ Don't use \`ariaLabel\` and \`ariaLabelledby\` at the same time.", }, { "defaultValue": "1", - "description": "Specifies the number of columns in each grid row. -Valid values are any integer between 1 and 4. It defaults to 1.", + "description": "Specifies the number of columns in each grid row. It defaults to 1. + +The number of columns is reduced as the available space narrows, based on \`minColumnWidth\`.", "name": "columns", "optional": true, "type": "number", @@ -18652,7 +18653,10 @@ Each group definition has the following properties: The number of columns is determined by the value of this property, the available space, and the maximum number of columns as defined by the \`columns\` property. -If not set, defaults to 150.", +If not set, defaults to 150. + +While reducing the count, odd numbers are skipped, so 5 columns becomes 4 and then 2. +A requested odd count is kept when it fits.", "name": "minColumnWidth", "optional": true, "type": "number", diff --git a/src/key-value-pairs/__tests__/key-value-pairs.test.tsx b/src/key-value-pairs/__tests__/key-value-pairs.test.tsx index d75250c16e9..db54a7cd3e7 100644 --- a/src/key-value-pairs/__tests__/key-value-pairs.test.tsx +++ b/src/key-value-pairs/__tests__/key-value-pairs.test.tsx @@ -106,22 +106,26 @@ describe('KeyValuePairs', () => { }); }); - describe('warnOnce when columns property exceeds max', () => { - test.each([ - { columns: 1, warnOnceMessage: false }, - { columns: 2, warnOnceCalled: false }, - { - columns: 3, - warnOnceCalled: false, - }, - { columns: 4, warnOnceCalled: false }, - { - columns: 5, - warnOnceCalled: true, - }, - ])(`warnOnce called = $warnOnceCalled when columns is set to $columns`, ({ columns, warnOnceCalled }) => { + describe('columns property', () => { + test.each([1, 2, 3, 4, 5, 6, 12])('does not warn when columns is set to %i', columns => { renderKeyValuePairs(); - expect(warnOnce).toHaveBeenCalledTimes(warnOnceCalled ? 1 : 0); + expect(warnOnce).not.toHaveBeenCalled(); + }); + + // Asserts the resolved grid rather than the number of items, because every item renders either + // way + test.each([3, 6, 12])('lays out %i columns', columns => { + const { wrapper } = renderKeyValuePairs( + ({ + label: `Label ${index}`, + value: `Value ${index}`, + }))} + /> + ); + + expect(wrapper.find('dl')!.getElement().style.gridTemplateColumns).toBe(`repeat(${columns}, minmax(0, 1fr))`); }); }); diff --git a/src/key-value-pairs/interfaces.ts b/src/key-value-pairs/interfaces.ts index d7431872084..23192ea6d44 100644 --- a/src/key-value-pairs/interfaces.ts +++ b/src/key-value-pairs/interfaces.ts @@ -6,8 +6,9 @@ import { BaseComponentProps } from '../types/base-component'; export interface KeyValuePairsProps extends BaseComponentProps { /** - * Specifies the number of columns in each grid row. - * Valid values are any integer between 1 and 4. It defaults to 1. + * Specifies the number of columns in each grid row. It defaults to 1. + * + * The number of columns is reduced as the available space narrows, based on `minColumnWidth`. */ columns?: number; /** @@ -46,6 +47,9 @@ export interface KeyValuePairsProps extends BaseComponentProps { * The number of columns is determined by the value of this property, the available space, * and the maximum number of columns as defined by the `columns` property. * If not set, defaults to 150. + * + * While reducing the count, odd numbers are skipped, so 5 columns becomes 4 and then 2. + * A requested odd count is kept when it fits. */ minColumnWidth?: number; } diff --git a/src/key-value-pairs/internal.tsx b/src/key-value-pairs/internal.tsx index 318a8ff02bb..ccb3fb1f21f 100644 --- a/src/key-value-pairs/internal.tsx +++ b/src/key-value-pairs/internal.tsx @@ -3,7 +3,7 @@ import React from 'react'; import clsx from 'clsx'; -import { useUniqueId, warnOnce } from '@cloudscape-design/component-toolkit/internal'; +import { useUniqueId } from '@cloudscape-design/component-toolkit/internal'; import Box from '../box/internal'; import ColumnLayout from '../column-layout/internal'; @@ -48,18 +48,9 @@ const InternalKeyValuePairs = React.forwardRef( ariaLabelledby, minColumnWidth, ...rest - }: KeyValuePairsProps & Required>, + }: KeyValuePairsProps & Required>, ref: React.Ref ) => { - const MAX_COLUMNS = 4; - - if (columns > MAX_COLUMNS) { - warnOnce( - 'Key-value pairs', - `\`columns\` (${columns}) must be <= ${MAX_COLUMNS}. Using ${MAX_COLUMNS} as default.` - ); - } - return (
{/* - minColumnWidth={150} is set to use FlexibleColumnLayout which has only 1 nested div wrapper for column items, - otherwise GridColumnLayout will be used, which has 2 nested div, therefore it is not a11y compatible for dl -> dt/dd relationship + A minColumnWidth is always passed (KeyValuePairs defaults it to 150) so that ColumnLayout + picks FlexibleColumnLayout, which wraps each column item in a single div. GridColumnLayout + wraps in two, which breaks the dl -> dt/dd relationship a11y relies on. */} - + {items.map((pair, index) => { if (pair.type === 'group') { return (