Skip to content

Commit

Permalink
Text cell with help text in grid (#1286)
Browse files Browse the repository at this point in the history
* Help text in grid

* added cypress test

* helpText in grid

* text cell with help
+
labelFrom cell

* update layout schema

* update layout schema

* cypress test

* some cleanup

* feedback - OM
  • Loading branch information
lassopicasso authored Jul 4, 2023
1 parent 60ebb56 commit b622e35
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 23 deletions.
16 changes: 16 additions & 0 deletions schemas/json/layout/layout.schema.v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -515,11 +515,27 @@
"title": "Text",
"description": "The text or text resource ID to be rendered in the cell",
"type": "string"
},
"help": {
"title": "Help text",
"description": "The help text or text resource ID to be rendered in the cell",
"type": "string"
}
},
"$ref": "#/definitions/tableColumnOptions",
"required": ["text"]
},
"gridLabelText": {
"properties": {
"labelFrom": {
"title": "Label from",
"description": "The ID of the component to be used to render text resources in the cell",
"type": "string"
}
},
"$ref": "#/definitions/tableColumnOptions",
"required": ["labelFrom"]
},
"gridCellComponent": {
"properties": {
"component": {
Expand Down
18 changes: 18 additions & 0 deletions src/layout/Grid/Grid.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,21 @@ tr > .fullWidthCellLast {
.tableCellFormatting:last-child {
width: calc(var(--cell-width) + 8.15%);
}

.textCell,
.textLabel,
.textLabel div {
display: flex;
}

.textLabel {
margin-top: 12px;
}

.textLabel div {
flex-wrap: nowrap;
}

.textLabel button {
align-self: flex-start;
}
115 changes: 92 additions & 23 deletions src/layout/Grid/GridComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import { Grid } from '@material-ui/core';
import cn from 'classnames';

import { ConditionalWrapper } from 'src/components/ConditionalWrapper';
import { Description } from 'src/components/form/Description';
import { FullWidthWrapper } from 'src/components/form/FullWidthWrapper';
import { HelpTextContainer } from 'src/components/form/HelpTextContainer';
import { Label } from 'src/components/form/Label';
import { useIsMobile } from 'src/hooks/useIsMobile';
import { useLanguage } from 'src/hooks/useLanguage';
import { GenericComponent } from 'src/layout/GenericComponent';
Expand All @@ -15,6 +18,7 @@ import { isGridRowHidden, nodesFromGrid } from 'src/layout/Grid/tools';
import { getColumnStyles } from 'src/utils/formComponentUtils';
import { LayoutNode } from 'src/utils/layout/LayoutNode';
import { LayoutPage } from 'src/utils/layout/LayoutPage';
import { getPlainTextFromNode } from 'src/utils/stringHelper';
import type { PropsFromGenericComponent } from 'src/layout';
import type { GridComponent, GridRow } from 'src/layout/Grid/types';
import type { ITableColumnFormatting, ITableColumnProperties } from 'src/layout/layout';
Expand Down Expand Up @@ -43,6 +47,7 @@ export function RenderGrid(props: PropsFromGenericComponent<'Grid'>) {
row={row}
isNested={isNested}
mutableColumnSettings={columnSettings}
node={node}
/>
))}
</Table>
Expand All @@ -54,9 +59,10 @@ interface GridRowProps {
row: GridRow<GridComponent>;
isNested: boolean;
mutableColumnSettings: ITableColumnFormatting;
node: LayoutNode;
}

export function GridRowRenderer({ row, isNested, mutableColumnSettings }: GridRowProps) {
export function GridRowRenderer({ row, isNested, mutableColumnSettings, node }: GridRowProps) {
const { lang } = useLanguage();

return isGridRowHidden(row) ? null : (
Expand All @@ -76,29 +82,45 @@ export function GridRowRenderer({ row, isNested, mutableColumnSettings }: GridRo
mutableColumnSettings[cellIdx] = cell.columnOptions;
}

if (cell && 'text' in cell && cell.text) {
if (cell && ('labelFrom' in cell || 'text' in cell)) {
let textCellSettings: ITableColumnProperties = mutableColumnSettings[cellIdx]
? structuredClone(mutableColumnSettings[cellIdx])
: {};
textCellSettings = { ...textCellSettings, ...cell };

return (
<CellWithText
key={`${cell.text}/${cellIdx}`}
className={className}
columnStyleOptions={textCellSettings}
>
{lang(cell.text)}
</CellWithText>
);
}
if ('text' in cell && cell.text) {
return (
<CellWithText
key={`${cell.text}/${cellIdx}`}
className={className}
help={cell?.help}
columnStyleOptions={textCellSettings}
>
{lang(cell.text)}
</CellWithText>
);
}

const node = cell && 'node' in cell && cell?.node;
const componentId = node && node.item.id;
if ('labelFrom' in cell && cell.labelFrom) {
const closestComponent = node
.flat(true)
.find((n) => n.item.id === cell.labelFrom || n.item.baseComponentId === cell.labelFrom);
return (
<CellWithLabel
key={`${cell.labelFrom}/${cellIdx}`}
className={className}
columnStyleOptions={textCellSettings}
referenceComponent={closestComponent}
/>
);
}
}
const componentNode = cell && 'node' in cell && cell?.node;
const componentId = componentNode && componentNode.item.id;
return (
<CellWithComponent
key={`${componentId}/${cellIdx}`}
node={node}
node={componentNode}
className={className}
columnStyleOptions={mutableColumnSettings[cellIdx]}
/>
Expand Down Expand Up @@ -137,6 +159,14 @@ interface CellWithComponentProps extends CellProps {
node?: LayoutNode;
}

interface CellWithTextProps extends PropsWithChildren, CellProps {
help?: string;
}

interface CellWithLabelProps extends CellProps {
referenceComponent?: LayoutNode;
}

function CellWithComponent({ node, className, columnStyleOptions }: CellWithComponentProps) {
if (node && !node.isHidden()) {
const columnStyles = columnStyleOptions && getColumnStyles(columnStyleOptions);
Expand All @@ -160,25 +190,64 @@ function CellWithComponent({ node, className, columnStyleOptions }: CellWithComp
return <TableCell className={className} />;
}

type CellWithTextProps = CellProps & PropsWithChildren;

function CellWithText({ children, className, columnStyleOptions }: CellWithTextProps) {
function CellWithText({ children, className, columnStyleOptions, help }: CellWithTextProps) {
const columnStyles = columnStyleOptions && getColumnStyles(columnStyleOptions);

return (
<TableCell
className={cn(css.tableCellFormatting, className)}
style={columnStyles}
>
<span
className={css.contentFormatting}
style={columnStyles}
>
{children}
<span className={help && css.textCell}>
<span
className={css.contentFormatting}
style={columnStyles}
>
{children}
</span>
{help && (
<HelpTextContainer
title={getPlainTextFromNode(children)}
helpText={help}
/>
)}
</span>
</TableCell>
);
}

function CellWithLabel({ className, columnStyleOptions, referenceComponent }: CellWithLabelProps) {
const columnStyles = columnStyleOptions && getColumnStyles(columnStyleOptions);
const { title, help, description } = referenceComponent?.item.textResourceBindings || {};
const { required } = referenceComponent?.item || {};
const componentId = referenceComponent?.item.id ?? referenceComponent?.item.baseComponentId;

return (
<TableCell
className={cn(css.tableCellFormatting, className)}
style={columnStyles}
>
{componentId && (
<>
<span className={css.textLabel}>
<Label
key={`label-${componentId}`}
labelText={title}
id={componentId}
required={required}
helpText={help}
/>
</span>
<Description
id={componentId}
description={description}
/>
</>
)}
</TableCell>
);
}

function MobileGrid({ node }: PropsFromGenericComponent<'Grid'>) {
return (
<Grid
Expand Down
1 change: 1 addition & 0 deletions src/layout/Grid/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type GridComponentType = GridComponentRef | GridComponent;

export interface GridText {
text: string;
help?: string;
alignText?: 'left' | 'center' | 'right';
textOverflow?: {
lineWrap?: boolean;
Expand Down
1 change: 1 addition & 0 deletions src/layout/Group/RepeatingGroupTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ export function RepeatingGroupTable({
row={{ ...row, cells: [...row.cells, ...extraCells] }}
isNested={isNested}
mutableColumnSettings={columnSettings}
node={node}
/>
))}
</>
Expand Down
29 changes: 29 additions & 0 deletions test/e2e/integration/app-frontend/grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,33 @@ describe('Grid component', () => {
.find('table tr:last-child td:first-child')
.should('contain.text', 'Foreldreraden er prefill: true');
});

it("should allow adding help text to Grid's text cells or referencing a component", () => {
cy.interceptLayout('changename', (component) => {
if (component.type === 'Grid') {
if (component.rows[1].cells[0]) {
component.rows[1].cells[0].help = 'Help text';
}
if (component.rows[2].cells[0]) {
delete component.rows[2].cells[0].text;
component.rows[2].cells[0].labelFrom = 'fordeling-studie';
}
}
if (component.type === 'Input' && component.id === 'fordeling-studie') {
component.textResourceBindings.description = 'Dette er en beskrivende tekst';
component.textResourceBindings.help = 'Dette er en hjelpetekst';
}
});

cy.goto('changename');
cy.navPage('grid').click();

cy.get(appFrontend.grid.grid).find('tr:eq(1) td:eq(0)').find(appFrontend.helpText.open).click();
cy.get(appFrontend.helpText.alert).should('contain.text', 'Help text');

cy.get(appFrontend.grid.grid).find('tr:eq(2) td:eq(0)').should('contain.text', 'Dette er en beskrivende tekst');
cy.get(appFrontend.grid.grid).find('tr:eq(2) td:eq(0)').find(appFrontend.helpText.open).click();
cy.get(appFrontend.grid.grid).find('tr:eq(2) td:eq(0) label').click();
cy.focused().should('have.attr', 'id', 'fordeling-studie');
});
});

0 comments on commit b622e35

Please sign in to comment.