Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@
"@babel/polyfill": "7.12.1",
"@cypress/snapshot": "^2.1.7",
"@date-fns/tz": "1.4.1",
"@digdir/designsystemet-css": "1.1.10",
"@digdir/designsystemet-react": "1.1.10",
"@digdir/designsystemet-theme": "1.1.10",
"@digdir/designsystemet-css": "1.6.0",
"@digdir/designsystemet-react": "1.6.0",
"@digdir/designsystemet-theme": "1.6.0",
"@navikt/aksel-icons": "7.31.0",
"@tanstack/react-query": "5.90.2",
"@types/cypress": "^1.1.6",
Expand Down
36 changes: 19 additions & 17 deletions src/layout/Dropdown/DropdownComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';

import { EXPERIMENTAL_Suggestion as Suggestion, Label as DSLabel } from '@digdir/designsystemet-react';
import cn from 'classnames';
import type { SuggestionItem } from '@digdir/designsystemet-react';

import { Label } from 'src/app-components/Label/Label';
import { AltinnSpinner } from 'src/components/AltinnSpinner';
Expand All @@ -19,26 +20,19 @@ import comboboxClasses from 'src/styles/combobox.module.css';
import utilClasses from 'src/styles/utils.module.css';
import { useLabel } from 'src/utils/layout/useLabel';
import { useItemWhenType } from 'src/utils/layout/useNodeItem';
import { optionFilter } from 'src/utils/options';
import type { PropsFromGenericComponent } from 'src/layout';

export function DropdownComponent({ baseComponentId, overrideDisplay }: PropsFromGenericComponent<'Dropdown'>) {
const item = useItemWhenType(baseComponentId, 'Dropdown');
const isValid = useIsValid(baseComponentId);
const { id, readOnly, textResourceBindings, alertOnChange, grid, required } = item;
const { langAsString, lang } = useLanguage();

const { labelText, getRequiredComponent, getOptionalComponent, getHelpTextComponent, getDescriptionComponent } =
useLabel({ baseComponentId, overrideDisplay });

const { options, isFetching, selectedValues, setData } = useGetOptions(baseComponentId, 'single');
const debounce = FD.useDebounceImmediately();

const selectedLabels = selectedValues.map((value) => {
const option = options.find((o) => o.value === value);
return option ? langAsString(option.label).toLowerCase() : value;
});

const changeMessageGenerator = (values: string[]) => {
const label = options
.filter((o) => values.includes(o.value))
Expand All @@ -55,17 +49,22 @@ export function DropdownComponent({ baseComponentId, overrideDisplay }: PropsFro
changeMessageGenerator,
);

// return a new array of objects with value and label properties without changing the selectedValues array
function formatSelectedValues(
function formatSelectedValue(
selectedValues: string[],
options: { value: string; label: string }[],
): { value: string; label: string }[] {
return selectedValues.map((value) => {
const option = options.find((o) => o.value === value);
return option ? { value: option.value, label: langAsString(option.label) } : { value, label: value };
});
): string | SuggestionItem | undefined {
// Since this is a single-select dropdown (multiple={false}), return only the first selected value
const value = selectedValues[0];
if (!value) {
return undefined;
}

const option = options.find((o) => o.value === value);
return option ? { value: option.value, label: langAsString(option.label) } : value;
}

const selectedValue = formatSelectedValue(selectedValues, options);

if (isFetching) {
return <AltinnSpinner />;
}
Expand Down Expand Up @@ -105,14 +104,14 @@ export function DropdownComponent({ baseComponentId, overrideDisplay }: PropsFro
</DSLabel>
)}
<Suggestion
filter={(args) => optionFilter(args, selectedLabels)}
multiple={false}
filter={(_) => true}
data-size='sm'
selected={formatSelectedValues(selectedValues, options)}
onSelectedChange={(options) => handleChange(options.map((o) => o.value))}
onBlur={() => debounce}
name={overrideDisplay?.renderedInTable ? langAsString(textResourceBindings?.title) : undefined}
className={cn(comboboxClasses.container, classes.showCaretsWithoutClear, { [classes.readOnly]: readOnly })}
style={{ width: '100%' }}
selected={selectedValue}
>
<Suggestion.Input
id={id}
Expand All @@ -136,6 +135,9 @@ export function DropdownComponent({ baseComponentId, overrideDisplay }: PropsFro
key={option.value}
value={option.value}
label={langAsString(option.label)}
onClick={(_) => {
handleChange(option?.value ? [option?.value] : []);
}}
>
<span className={classes.optionContent}>
<Lang id={option.label} />
Expand Down
48 changes: 28 additions & 20 deletions src/layout/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,27 +71,35 @@ export const Tabs = ({ baseComponentId }: PropsFromGenericComponent<'Tabs'>) =>
/>
))}
</DesignsystemetTabs.List>
{tabs.map((tab) => (
<DesignsystemetTabs.Panel
key={tab.id}
value={tab.id}
role='tabpanel'
className={classes.tabContent}
>
<Flex
container
spacing={6}
alignItems='flex-start'
{tabs.map((tab) => {
if (tab.id !== activeTab) {
// Behavior changed to always render tab panels, so we override to conditionally render on our side. Since
// we override styles, all hidden tabs were displayed after this change.
// @see https://github.com/digdir/designsystemet/pull/3936
return null;
}

return (
<DesignsystemetTabs.Panel
key={tab.id}
value={tab.id}
role='tabpanel'
>
{tab.children.filter(typedBoolean).map((baseId) => (
<GenericComponent
key={baseId}
baseComponentId={baseId}
/>
))}
</Flex>
</DesignsystemetTabs.Panel>
))}
<Flex
container
spacing={6}
alignItems='flex-start'
>
{tab.children.filter(typedBoolean).map((baseId) => (
<GenericComponent
key={baseId}
baseComponentId={baseId}
/>
))}
</Flex>
</DesignsystemetTabs.Panel>
);
})}
</DesignsystemetTabs>
</ComponentStructureWrapper>
);
Expand Down
19 changes: 12 additions & 7 deletions test/e2e/integration/frontend-test/tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,27 @@ describe('Tabs', () => {
cy.goto('changename');
});

it('Has correct number of tabs', () => {
it('Tabs component should work', () => {
// Has correct number of tabs
cy.findByRole('tablist').children().should('have.length', 2);
});

it('Displays the correct tabs and default tab content', () => {
// Displays the correct tabs and default tab content
const tab1 = /Nytt mellomnavn/i;
cy.findByRole('tab', { name: tab1 }).invoke('attr', 'aria-selected').should('equal', 'true');
cy.findByRole('tab', { name: tab1 }).findByAltText('').should('exist'); // Check if icon is present
cy.findByRole('tab', { name: tab1 }).should('have.text', 'Nytt mellomnavn'); // check if text is present

// Regression test for one time when all tabs were visible at the same time
cy.findAllByRole('tabpanel').should('have.length', 1);
cy.get('#form-content-newMiddleName').should('be.visible');
cy.get('#form-content-newLastName').should('not.exist');

cy.findByRole('textbox', { name: /Nytt mellomnavn/i });

cy.get('label').should('contain.text', 'Nytt mellomnavn');
cy.findByRole('tabpanel').should('contain.text', 'Nytt mellomnavn');
});

it('Displays the correct tab content when clicking on a tab', () => {
// Displays the correct tab content when clicking on a tab
cy.findByRole('textbox', { name: /Nytt mellomnavn/i }).should('exist');
cy.findByRole('textbox', { name: /Nytt etternavn/i }).should('not.exist');
cy.findByRole('tab', { name: /nytt etternavn/i })
Expand All @@ -33,9 +37,10 @@ describe('Tabs', () => {
.should('equal', 'true');
cy.findByRole('textbox', { name: /Nytt mellomnavn/i }).should('not.exist');
cy.findByRole('textbox', { name: /Nytt etternavn/i }).should('exist');
});

it('Navigates to the correct tab when clicking on a validation error of an input field in that tab', () => {
cy.findByRole('tab', { name: /nytt mellomnavn/i }).click();

// Navigates to the correct tab when clicking on a validation error of an input field in that tab
cy.findByRole('tab', { name: /nytt etternavn/i })
.invoke('attr', 'aria-selected')
.should('equal', 'false');
Expand Down
81 changes: 37 additions & 44 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1949,37 +1949,37 @@ __metadata:
languageName: node
linkType: hard

"@digdir/designsystemet-css@npm:1.1.10":
version: 1.1.10
resolution: "@digdir/designsystemet-css@npm:1.1.10"
checksum: 10c0/d467a714f73bc005f8bea3ea5c1ea11104175f5b5360272f21f74b201b6284602c4b951163a47de9bf86c00532b15329446698d12100978907feab8d78a24bc8
"@digdir/designsystemet-css@npm:1.6.0":
version: 1.6.0
resolution: "@digdir/designsystemet-css@npm:1.6.0"
checksum: 10c0/0db3467edf0e53b0f43d33e927771304ff61881d721bd2fb75d9760ca7be48d480be5f5e24a293c834b5138ada9985d0706462c8c3eab460523a37994a01f4cf
languageName: node
linkType: hard

"@digdir/designsystemet-react@npm:1.1.10":
version: 1.1.10
resolution: "@digdir/designsystemet-react@npm:1.1.10"
"@digdir/designsystemet-react@npm:1.6.0":
version: 1.6.0
resolution: "@digdir/designsystemet-react@npm:1.6.0"
dependencies:
"@floating-ui/dom": "npm:^1.7.3"
"@floating-ui/dom": "npm:^1.7.4"
"@floating-ui/react": "npm:0.26.23"
"@navikt/aksel-icons": "npm:^7.25.1"
"@navikt/aksel-icons": "npm:^7.30.1"
"@radix-ui/react-slot": "npm:^1.2.3"
"@tanstack/react-virtual": "npm:^3.13.12"
"@u-elements/u-combobox": "npm:^0.0.20"
"@u-elements/u-datalist": "npm:^1.0.12"
"@u-elements/u-details": "npm:^0.1.1"
"@u-elements/u-combobox": "npm:^1.0.1"
"@u-elements/u-datalist": "npm:^1.0.14"
"@u-elements/u-details": "npm:^0.1.5"
clsx: "npm:^2.1.1"
peerDependencies:
react: ">=18.3.1 || ^19.0.0"
react-dom: ">=18.3.1 || ^19.0.0"
checksum: 10c0/3cd87931e8dc11756b6ebd3a45be71bba9091dc75a7f5b5d960ea6852ed79575694fb60e1259daf5e8a03e40524d7bbb3fd778aa7a6909df339578e3101647d1
checksum: 10c0/653c10410af4a811508aeca54ad3c502ba46398b3931e4a3cc5c1142e3c6343d00f855e080279b750ccbde641c18567adf6989c5d2e484c73f6fa2daf8dc311c
languageName: node
linkType: hard

"@digdir/designsystemet-theme@npm:1.1.10":
version: 1.1.10
resolution: "@digdir/designsystemet-theme@npm:1.1.10"
checksum: 10c0/116cc996ae46e36bb078d5025dac84522a6d9ced899b05e9115934a28dd1249c6e7556e3a92eeed88708ead552ba3fafd162abb15946503b5cbe6be99f97f26a
"@digdir/designsystemet-theme@npm:1.6.0":
version: 1.6.0
resolution: "@digdir/designsystemet-theme@npm:1.6.0"
checksum: 10c0/9433b5a2272c46323fe7f84b547a9eaf3041b1d53560a97e99c7834c8a7b472ac15c67426d87af324a8fdbb0b5b73a08795c9959ce62e98165c40b9cfb23d447
languageName: node
linkType: hard

Expand Down Expand Up @@ -2355,13 +2355,13 @@ __metadata:
languageName: node
linkType: hard

"@floating-ui/dom@npm:^1.7.3":
version: 1.7.3
resolution: "@floating-ui/dom@npm:1.7.3"
"@floating-ui/dom@npm:^1.7.4":
version: 1.7.4
resolution: "@floating-ui/dom@npm:1.7.4"
dependencies:
"@floating-ui/core": "npm:^1.7.3"
"@floating-ui/utils": "npm:^0.2.10"
checksum: 10c0/cba30e9af1a52fb7cb443ae516d7aec032b33da2fa50914dcb18fc834dc31c71922f5c7653431e70d493f347018b2ce6435c98b3f154d92082345689b4458e59
checksum: 10c0/da6166c25f9b0729caa9f498685a73a0e28251613b35d27db8de8014bc9d045158a23c092b405321a3d67c2064909b6e2a7e6c1c9cc0f62967dca5779f5aef30
languageName: node
linkType: hard

Expand Down Expand Up @@ -3184,20 +3184,13 @@ __metadata:
languageName: node
linkType: hard

"@navikt/aksel-icons@npm:7.31.0":
"@navikt/aksel-icons@npm:7.31.0, @navikt/aksel-icons@npm:^7.30.1":
version: 7.31.0
resolution: "@navikt/aksel-icons@npm:7.31.0"
checksum: 10c0/10488569dec7c49ace82eab9684f122ccfded18fc99f290ea62589d52dc2b63c6c0be8f524308a63cf36cb235b827d2eab96f3079c65643fd34ff9e93552177a
languageName: node
linkType: hard

"@navikt/aksel-icons@npm:^7.25.1":
version: 7.25.1
resolution: "@navikt/aksel-icons@npm:7.25.1"
checksum: 10c0/ab1f6e020869d32165c616b3b70cf76fbde9a45bfc26f65a2e53b678160683b57ff7b060626e2b034e2421539020a2b57a9171ec913487c3fd160a5e647a83b5
languageName: node
linkType: hard

"@nodelib/fs.scandir@npm:2.1.5":
version: 2.1.5
resolution: "@nodelib/fs.scandir@npm:2.1.5"
Expand Down Expand Up @@ -4870,24 +4863,24 @@ __metadata:
languageName: node
linkType: hard

"@u-elements/u-combobox@npm:^0.0.20":
version: 0.0.20
resolution: "@u-elements/u-combobox@npm:0.0.20"
checksum: 10c0/0abb187f6ce5af67be15d5e2b3b399ade9f0b31df9cc0275b1f05fc726bf8668956a40fe6b6a8a219a472a1fbca12e7d0b3877501f6e4af27b7afd5fa76c1daf
"@u-elements/u-combobox@npm:^1.0.1":
version: 1.0.2
resolution: "@u-elements/u-combobox@npm:1.0.2"
checksum: 10c0/22fe3322d52e8322a76be13dcbd931d2b3ce0e4c354a2a504b30c00b24beb99f846c7fb1534a835bd68cfb8ffcc30704d114783df918b2ac9e917c328b051875
languageName: node
linkType: hard

"@u-elements/u-datalist@npm:^1.0.12":
version: 1.0.13
resolution: "@u-elements/u-datalist@npm:1.0.13"
checksum: 10c0/0a3f58517e1fedf470e7c53f76c6d73fffdcfd6af1658b412b00f6e168f3ef97a41c1bcf70c8167f4b1babdf92d0ccb4792c114d17c7cc8bab42b641b304e2cc
"@u-elements/u-datalist@npm:^1.0.14":
version: 1.0.14
resolution: "@u-elements/u-datalist@npm:1.0.14"
checksum: 10c0/d9190f969c564fb88b1b94c1b9992fed58ca3c865543fdbcf70f688f3e87dedfcb3f96582f70a61f1bd68ee3b4c964b340412671597dea659471982354131b4a
languageName: node
linkType: hard

"@u-elements/u-details@npm:^0.1.1":
version: 0.1.1
resolution: "@u-elements/u-details@npm:0.1.1"
checksum: 10c0/df382b61dc31f44d6b093193afe0e5ba795d27009158a71440e0a53cb47a7aa0c6ebba03ce44186a77e18c3cbdb7e8f4c312018a837f7e5ee41cf5bb1f349c2d
"@u-elements/u-details@npm:^0.1.5":
version: 0.1.5
resolution: "@u-elements/u-details@npm:0.1.5"
checksum: 10c0/285342d86f8c4b9503ca707a368f07ef43d0d6370869098b59e1147c067fd0f475b0662a877a88a6a135c74624fc918971050f0715af67c0a2a88022fa85dbc0
languageName: node
linkType: hard

Expand Down Expand Up @@ -5576,9 +5569,9 @@ __metadata:
"@babel/runtime-corejs3": "npm:7.28.4"
"@cypress/snapshot": "npm:^2.1.7"
"@date-fns/tz": "npm:1.4.1"
"@digdir/designsystemet-css": "npm:1.1.10"
"@digdir/designsystemet-react": "npm:1.1.10"
"@digdir/designsystemet-theme": "npm:1.1.10"
"@digdir/designsystemet-css": "npm:1.6.0"
"@digdir/designsystemet-react": "npm:1.6.0"
"@digdir/designsystemet-theme": "npm:1.6.0"
"@eslint/compat": "npm:1.4.0"
"@faker-js/faker": "npm:10.0.0"
"@navikt/aksel-icons": "npm:7.31.0"
Expand Down
Loading