diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/Examples.tsx index 8e715fcc226..31235d5a664 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/Examples.tsx @@ -170,15 +170,21 @@ export const CheckboxWithHelp = () => ( ) export const CheckboxNestingWithLogic = () => ( - - + + - + { @@ -187,10 +193,11 @@ export const CheckboxNestingWithLogic = () => ( : false }, }} - compensateForGap="auto" + animate + compensateForGap="auto" // makes animation smooth >
- +
@@ -199,7 +206,6 @@ export const CheckboxNestingWithLogic = () => ( title="Show additional option" /> { @@ -208,7 +214,8 @@ export const CheckboxNestingWithLogic = () => ( : false }, }} - compensateForGap="auto" + animate + compensateForGap="auto" // makes animation smooth > ( }} >
- +
+ +
) @@ -496,7 +505,6 @@ export const ButtonNestingWithLogic = () => ( { @@ -505,7 +513,8 @@ export const ButtonNestingWithLogic = () => ( : false }, }} - compensateForGap="auto" + animate + compensateForGap="auto" // makes animation smooth >
@@ -517,7 +526,6 @@ export const ButtonNestingWithLogic = () => ( title="Show additional option" /> { @@ -526,7 +534,8 @@ export const ButtonNestingWithLogic = () => ( : false }, }} - compensateForGap="auto" + animate + compensateForGap="auto" // makes animation smooth > ( ) export const RadioNestingWithLogic = () => ( - - + +
- +
( title="Show additional option" /> value === 'showAdditionalOption' || value === 'showMeMore', }} - compensateForGap="auto" + animate + compensateForGap="auto" // makes animation smooth > ( }} >
- +
+ + + + +) + +export const RadioNestingAdvanced = () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/demos.mdx index 44af5827822..3bc5bff81ce 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/demos.mdx @@ -124,12 +124,6 @@ As there are many variants, they are split into separate sections. Here is a sum -#### Radio nesting other fields with logic - -You can nest other fields and show them based on your desired logic. - - - #### Radio button with a path to populate the data @@ -138,6 +132,16 @@ You can nest other fields and show them based on your desired logic. +#### Radio nesting other fields with logic + +You can nest other fields and show them based on your desired logic. + + + +#### Radio nesting advanced + + + --- ### Buttons variant diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/FieldBlock/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/FieldBlock/properties.mdx index ef1bb5b14b0..57ba305ab9b 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/FieldBlock/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/FieldBlock/properties.mdx @@ -4,11 +4,11 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldBlockProperties } from '@dnb/eufemia/src/extensions/forms/FieldBlock/FieldBlockDocs' +import { FieldBlockProperties } from '@dnb/eufemia/src/extensions/forms/FieldBlock/FieldBlockDocs' ## Properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PostalCodeAndCity/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PostalCodeAndCity/properties.mdx index cae26b66b72..2f6f1b63ac4 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PostalCodeAndCity/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PostalCodeAndCity/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldBlockProperties } from '@dnb/eufemia/src/extensions/forms/FieldBlock/FieldBlockDocs' +import { FieldBlockProperties } from '@dnb/eufemia/src/extensions/forms/FieldBlock/FieldBlockDocs' import { PostalCodeAndCityProperties } from '@dnb/eufemia/src/extensions/forms/Field/PostalCodeAndCity/PostalCodeAndCityDocs' ## Properties @@ -15,7 +15,7 @@ import { PostalCodeAndCityProperties } from '@dnb/eufemia/src/extensions/forms/F ### General properties - + ## Translations diff --git a/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-for-sbanken-have-to-match-nested-cards.snap.png b/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-for-sbanken-have-to-match-nested-cards.snap.png index 0f77d85f602..ff04ac4c618 100644 Binary files a/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-for-sbanken-have-to-match-nested-cards.snap.png and b/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-for-sbanken-have-to-match-nested-cards.snap.png differ diff --git a/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-small-screen-for-sbanken-have-to-match-nested-cards.snap.png b/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-small-screen-for-sbanken-have-to-match-nested-cards.snap.png index 3a8b701ce44..b790f320a06 100644 Binary files a/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-small-screen-for-sbanken-have-to-match-nested-cards.snap.png and b/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-small-screen-for-sbanken-have-to-match-nested-cards.snap.png differ diff --git a/packages/dnb-eufemia/src/components/card/style/dnb-card.scss b/packages/dnb-eufemia/src/components/card/style/dnb-card.scss index 9d6362ddc3f..49d9720e8f0 100644 --- a/packages/dnb-eufemia/src/components/card/style/dnb-card.scss +++ b/packages/dnb-eufemia/src/components/card/style/dnb-card.scss @@ -113,4 +113,9 @@ & > .dnb-flex-container--align-stretch > .dnb-button { align-self: flex-start; } + + // Nested Cards + & .dnb-card { + --outline-width: 0.125rem; + } } diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/ArraySelection.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/ArraySelection.tsx index 7847100352e..80cb49daf8a 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/ArraySelection.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/ArraySelection.tsx @@ -108,6 +108,7 @@ function ArraySelection(props: Props) { ) : undefined} ), + disableStatusSummary: true, ...pickSpacingProps(props), } diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/__tests__/ArraySelection.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/__tests__/ArraySelection.test.tsx index 4e8309e78c1..13a53f7aebb 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/__tests__/ArraySelection.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/__tests__/ArraySelection.test.tsx @@ -5,6 +5,9 @@ import { axeComponent } from '../../../../../core/jest/jestSetup' import DataContext from '../../../DataContext/Context' import { Field, FieldBlock, Form } from '../../..' +import nbNO from '../../../constants/locales/nb-NO' +const nb = nbNO['nb-NO'] + describe('ArraySelection', () => { describe('checkbox', () => { it('renders correctly', () => { @@ -381,6 +384,36 @@ describe('ArraySelection', () => { }) }) + it('should show errors in separate FormStatus components', () => { + render( + + + + + ) + + expect(document.querySelectorAll('.dnb-form-status')).toHaveLength(2) + const [first, second] = Array.from( + document.querySelectorAll('.dnb-form-status') + ) + + expect(first.textContent).toBe(nb.Field.errorRequired) + expect(second.textContent).toBe( + nb.NumberField.errorExclusiveMinimum.replace( + '{exclusiveMinimum}', + '900' + ) + ) + }) + describe('ARIA', () => { it('should validate with ARIA rules', async () => { const result = render( diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/__tests__/__image_snapshots__/arrayselection-field-for-sbanken-checkbox-have-to-match-checkbox-nesting-logic.snap.png b/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/__tests__/__image_snapshots__/arrayselection-field-for-sbanken-checkbox-have-to-match-checkbox-nesting-logic.snap.png index d581ead3e7e..c3b150c7f26 100644 Binary files a/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/__tests__/__image_snapshots__/arrayselection-field-for-sbanken-checkbox-have-to-match-checkbox-nesting-logic.snap.png and b/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/__tests__/__image_snapshots__/arrayselection-field-for-sbanken-checkbox-have-to-match-checkbox-nesting-logic.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/__tests__/__image_snapshots__/arrayselection-field-for-ui-checkbox-have-to-match-checkbox-nesting-logic.snap.png b/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/__tests__/__image_snapshots__/arrayselection-field-for-ui-checkbox-have-to-match-checkbox-nesting-logic.snap.png index 7e86881b2bb..95b8e842f45 100644 Binary files a/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/__tests__/__image_snapshots__/arrayselection-field-for-ui-checkbox-have-to-match-checkbox-nesting-logic.snap.png and b/packages/dnb-eufemia/src/extensions/forms/Field/ArraySelection/__tests__/__image_snapshots__/arrayselection-field-for-ui-checkbox-have-to-match-checkbox-nesting-logic.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/Composition/CompositionDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Field/Composition/CompositionDocs.ts index 78567d738e3..e040f710c86 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Field/Composition/CompositionDocs.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Field/Composition/CompositionDocs.ts @@ -1,8 +1,8 @@ import { PropertiesTableProps } from '../../../../shared/types' -import { fieldBlockProperties } from '../../FieldBlock/FieldBlockDocs' +import { FieldBlockProperties } from '../../FieldBlock/FieldBlockDocs' export const CompositionProperties: PropertiesTableProps = { - ...fieldBlockProperties, + ...FieldBlockProperties, align: { doc: '`center` or `bottom` for aligning the contents vertically. Defaults to `bottom`.', type: ['string', 'false'], diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/Selection/Selection.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/Selection/Selection.tsx index f1740fae264..1cc70a699fc 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Field/Selection/Selection.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Field/Selection/Selection.tsx @@ -171,6 +171,7 @@ function Selection(props: Props) { const fieldBlockProps: FieldBlockProps = { forId: id, className: cn, + disableStatusSummary: true, ...pickSpacingProps(props), } diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/Selection.screenshot.test.ts b/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/Selection.screenshot.test.ts index 62616aea422..0f6d68e7731 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/Selection.screenshot.test.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/Selection.screenshot.test.ts @@ -78,6 +78,15 @@ describe('Selection', () => { }) expect(screenshot).toMatchImageSnapshot() }) + + it('have to match selection-radio-advanced-nesting-logic', async () => { + const screenshot = await makeScreenshot({ + selector: + '[data-visual-test="selection-radio-advanced-nesting-logic"]', + recalculateHeightAfterSimulate: true, + }) + expect(screenshot).toMatchImageSnapshot() + }) }) describe('button', () => { diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/Selection.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/Selection.test.tsx index f42d0b3e806..5da99492a49 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/Selection.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/Selection.test.tsx @@ -13,6 +13,9 @@ import DrawerListProvider from '../../../../../fragments/drawer-list/DrawerListP import { makeOptions } from '../Selection' import { Field, Form } from '../../..' +import nbNO from '../../../constants/locales/nb-NO' +const nb = nbNO['nb-NO'] + describe('Selection', () => { it('renders selected option', () => { render( @@ -1741,6 +1744,45 @@ describe('validation and error handling', () => { 'dnb-toggle-button__status--error' ) }) + + it('should show error under the nested field', () => { + render( + + + + + ) + + expect(document.querySelectorAll('.dnb-form-status')).toHaveLength(1) + expect(document.querySelector('.dnb-form-status').textContent).toBe( + nb.NumberField.errorExclusiveMinimum.replace( + '{exclusiveMinimum}', + '900' + ) + ) + }) + + it('should show errors in separate FormStatus components', () => { + render( + + + + + ) + + expect(document.querySelectorAll('.dnb-form-status')).toHaveLength(2) + const [first, second] = Array.from( + document.querySelectorAll('.dnb-form-status') + ) + + expect(first.textContent).toBe(nb.Field.errorRequired) + expect(second.textContent).toBe( + nb.NumberField.errorExclusiveMinimum.replace( + '{exclusiveMinimum}', + '900' + ) + ) + }) }) describe('makeOptions', () => { diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/__image_snapshots__/selection-radio-have-to-match-radio-nesting-logic.snap.png b/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/__image_snapshots__/selection-radio-have-to-match-radio-nesting-logic.snap.png index e1261ef4972..4a4f31a7bcd 100644 Binary files a/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/__image_snapshots__/selection-radio-have-to-match-radio-nesting-logic.snap.png and b/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/__image_snapshots__/selection-radio-have-to-match-radio-nesting-logic.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/__image_snapshots__/selection-radio-have-to-match-selection-radio-advanced-nesting-logic.snap.png b/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/__image_snapshots__/selection-radio-have-to-match-selection-radio-advanced-nesting-logic.snap.png new file mode 100644 index 00000000000..110cdccf640 Binary files /dev/null and b/packages/dnb-eufemia/src/extensions/forms/Field/Selection/__tests__/__image_snapshots__/selection-radio-have-to-match-selection-radio-advanced-nesting-logic.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/Selection/stories/Selection.stories.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/Selection/stories/Selection.stories.tsx index 94964b6ea3a..42d7f954993 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Field/Selection/stories/Selection.stories.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Field/Selection/stories/Selection.stories.tsx @@ -133,9 +133,9 @@ export function NestingWithLogic() {
@@ -147,13 +147,13 @@ export function NestingWithLogic() { title="Show additional option" /> value === 'showAdditionalOption' || value === 'showMeMore', }} - compensateForGap="auto" + animate + compensateForGap="auto" // makes animation smooth > ( 'field-block-props-' + (props.id ?? props.forId) @@ -144,6 +153,7 @@ function FieldBlock(props: Props) { info, warning, error: errorProp, + disableStatusSummary, fieldState, disabled, width, @@ -523,6 +533,7 @@ function FieldBlock(props: Props) { fieldStateIdsRef, mountedFieldsRef, composition, + disableStatusSummary, }} > void hasErrorProp?: boolean composition?: true + disableStatusSummary?: boolean fieldStateIdsRef?: React.MutableRefObject mountedFieldsRef?: React.MutableRefObject } diff --git a/packages/dnb-eufemia/src/extensions/forms/FieldBlock/FieldBlockDocs.ts b/packages/dnb-eufemia/src/extensions/forms/FieldBlock/FieldBlockDocs.ts index e1ba4b58e20..9832c1b02b7 100644 --- a/packages/dnb-eufemia/src/extensions/forms/FieldBlock/FieldBlockDocs.ts +++ b/packages/dnb-eufemia/src/extensions/forms/FieldBlock/FieldBlockDocs.ts @@ -26,11 +26,6 @@ export const FieldBlockSharedProperties: PropertiesTableProps = { type: 'object', status: 'optional', }, - labelHeight: { - doc: 'Defines the height of an component (size prop), so the label can be aligned correctly. Can be `default`, `small`, `medium`, `large`.', - type: 'string', - status: 'optional', - }, width: { doc: 'Will set the width for the whole block. Use `small`, `medium`, `large` for predefined standard widths. You can also set a custom width `{number}rem` or use `stretch` or `false`.', type: ['string', 'false'], @@ -48,13 +43,19 @@ export const FieldBlockSharedProperties: PropertiesTableProps = { }, } -export const fieldBlockProperties: PropertiesTableProps = { +/** For internal use only */ +export const FieldBlockProperties: PropertiesTableProps = { ...FieldBlockSharedProperties, labelSize: { doc: 'Define one of the following [heading sizes](/uilib/elements/heading/): `medium` or `large`.', type: ['string', 'false'], status: 'optional', }, + labelHeight: { + doc: 'Defines the height of an component (size prop), so the label can be aligned correctly. Can be `default`, `small`, `medium`, `large`.', + type: 'string', + status: 'optional', + }, asFieldset: { doc: 'Use `true` when you have several form elements. This way a `fieldset` with a `legend` is used.', type: 'boolean', @@ -65,6 +66,11 @@ export const fieldBlockProperties: PropertiesTableProps = { type: ['string', 'false'], status: 'optional', }, + disableStatusSummary: { + doc: 'Use `true` to disable the error summary.', + type: 'boolean', + status: 'optional', + }, composition: { doc: 'Use `true` for when you have more than one field wrapped.', type: 'string', diff --git a/packages/dnb-eufemia/src/extensions/forms/FieldBlock/__tests__/FieldBlock.test.tsx b/packages/dnb-eufemia/src/extensions/forms/FieldBlock/__tests__/FieldBlock.test.tsx index 48e459e1f1b..371823e6a18 100644 --- a/packages/dnb-eufemia/src/extensions/forms/FieldBlock/__tests__/FieldBlock.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/FieldBlock/__tests__/FieldBlock.test.tsx @@ -880,6 +880,81 @@ describe('FieldBlock', () => { log.mockRestore() }) + + it('should summarize errors in one FormStatus components', () => { + const MockComponent = () => { + useFieldProps({ + required: true, + validateInitially: true, + }) + + return null + } + + render( + + + + ) + + expect(document.querySelectorAll('.dnb-form-status')).toHaveLength(1) + expect(document.querySelector('.dnb-form-status').textContent).toBe( + nb.Field.errorSummary + 'Error message' + nb.Field.errorRequired + ) + }) + + it('should summarize errors for nested FieldBlocks', () => { + const nested = new Error('Nested') + const outer = new Error('Outer') + + const MockComponent = () => { + useFieldProps({ + id: 'unique', + error: nested, + }) + + return content + } + + render( + + + + ) + + expect(document.querySelectorAll('.dnb-form-status')).toHaveLength(1) + expect(document.querySelector('.dnb-form-status').textContent).toBe( + nb.Field.errorSummary + 'Outer' + 'Nested' + ) + }) + + it('should not summarize errors when "disableStatusSummary" is true', () => { + const nested = new Error('Nested') + const outer = new Error('Outer') + + const MockComponent = () => { + useFieldProps({ + id: 'unique', + error: nested, + }) + + return content + } + + render( + + + + ) + + expect(document.querySelectorAll('.dnb-form-status')).toHaveLength(2) + expect( + document.querySelectorAll('.dnb-form-status')[0].textContent + ).toBe('Outer') + expect( + document.querySelectorAll('.dnb-form-status')[1].textContent + ).toBe('Nested') + }) }) function MockComponent({ label = null, id = null }) { diff --git a/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts b/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts index b1b97cceee5..4aa47d776e1 100644 --- a/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts +++ b/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts @@ -32,7 +32,9 @@ import FieldProviderContext from '../Field/Provider/FieldProviderContext' import { combineDescribedBy, warn } from '../../../shared/component-helper' import useId from '../../../shared/helpers/useId' import useUpdateEffect from '../../../shared/helpers/useUpdateEffect' -import FieldBlockContext from '../FieldBlock/FieldBlockContext' +import FieldBlockContext, { + FieldBlockContextProps, +} from '../FieldBlock/FieldBlockContext' import IterateElementContext from '../Iterate/IterateItemContext' import SectionContext from '../Form/Section/SectionContext' import FieldBoundaryContext from '../DataContext/FieldBoundary/FieldBoundaryContext' @@ -208,12 +210,14 @@ export default function useFieldProps( const onChangeContext = dataContext?.props?.onChange const disabled = disabledProp ?? props.readOnly - const inFieldBlock = Boolean(fieldBlockContext) + const inFieldBlock = Boolean( + fieldBlockContext && fieldBlockContext.disableStatusSummary !== true + ) const { setFieldState: setFieldStateFieldBlock, showFieldError: showFieldErrorFieldBlock, mountedFieldsRef: mountedFieldsRefFieldBlock, - } = fieldBlockContext || {} + } = inFieldBlock ? fieldBlockContext : ({} as FieldBlockContextProps) const { handleChange: handleChangeIterateContext, index: iterateIndex,