Skip to content

Commit 0662c35

Browse files
authored
feat/COMPASS-9898 Add handling for multiple types with inline definition (#138)
1 parent 1d5885c commit 0662c35

File tree

6 files changed

+293
-9
lines changed

6 files changed

+293
-9
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"@emotion/react": "^11.14.0",
5353
"@emotion/styled": "^11.14.0",
5454
"@leafygreen-ui/icon": "^14.3.0",
55+
"@leafygreen-ui/inline-definition": "^9.0.5",
5556
"@leafygreen-ui/leafygreen-provider": "^5.0.2",
5657
"@leafygreen-ui/palette": "^5.0.0",
5758
"@leafygreen-ui/tokens": "^3.2.1",

src/components/field/field-type-content.tsx

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { useMemo } from 'react';
22
import styled from '@emotion/styled';
3+
import LeafyGreenInlineDefinition from '@leafygreen-ui/inline-definition';
4+
import { Body } from '@leafygreen-ui/typography';
35

46
import { useEditableDiagramInteractions } from '@/hooks/use-editable-diagram-interactions';
57
import { PlusWithSquare } from '@/components/icons/plus-with-square';
@@ -12,14 +14,27 @@ const ObjectTypeContainer = styled.div`
1214
line-height: 20px;
1315
`;
1416

17+
const MixedTypeTooltipContentStyles = styled(Body)`
18+
overflow-wrap: anywhere;
19+
text-wrap: wrap;
20+
text-align: left;
21+
font-style: normal;
22+
`;
23+
24+
const InlineDefinition = styled(LeafyGreenInlineDefinition)`
25+
font-style: italic;
26+
text-decoration-color: inherit;
27+
text-underline-offset: 0.25em;
28+
`;
29+
1530
export const FieldTypeContent = ({
1631
type,
1732
nodeId,
1833
id,
1934
}: {
2035
id: string | string[];
2136
nodeId: string;
22-
type: React.ReactNode;
37+
type?: string | string[];
2338
}) => {
2439
const { onClickAddFieldToObjectField: _onClickAddFieldToObjectField } = useEditableDiagramInteractions();
2540

@@ -57,5 +72,26 @@ export const FieldTypeContent = ({
5772
return '[]';
5873
}
5974

75+
if (Array.isArray(type)) {
76+
if (type.length === 0) {
77+
return 'unknown';
78+
}
79+
80+
if (type.length === 1) {
81+
return <>{type}</>;
82+
}
83+
84+
const typesString = type.join(', ');
85+
86+
// We show `mixed` with a tooltip when multiple types exist.
87+
return (
88+
<InlineDefinition
89+
definition={<MixedTypeTooltipContentStyles>Multiple types: {typesString}</MixedTypeTooltipContentStyles>}
90+
>
91+
(mixed)
92+
</InlineDefinition>
93+
);
94+
}
95+
6096
return <>{type}</>;
6197
};

src/components/field/field.test.tsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { palette } from '@leafygreen-ui/palette';
22
import { ComponentProps } from 'react';
33
import { userEvent } from '@testing-library/user-event';
44

5-
import { render, screen } from '@/mocks/testing-utils';
5+
import { render, screen, waitFor } from '@/mocks/testing-utils';
66
import { Field as FieldComponent } from '@/components/field/field';
77
import { DEFAULT_PREVIEW_GROUP_AREA } from '@/utilities/get-preview-group-area';
88
import { EditableDiagramInteractionsProvider } from '@/hooks/use-editable-diagram-interactions';
@@ -88,6 +88,31 @@ describe('field', () => {
8888
expect(screen.getByText('[]')).toBeInTheDocument();
8989
expect(screen.queryByText('array')).not.toBeInTheDocument();
9090
});
91+
92+
it('shows (mixed) with multiple types with a tooltip with more info', async () => {
93+
render(<Field {...DEFAULT_PROPS} type={['string', 'number', 'array']} />);
94+
expect(screen.getByText('(mixed)')).toBeInTheDocument();
95+
expect(screen.queryByText('string')).not.toBeInTheDocument();
96+
97+
// When hovering the (mixed) text, the tooltip content is present in the document.
98+
await userEvent.hover(screen.getByText('(mixed)'));
99+
const tooltipText = 'Multiple types: string, number, array';
100+
await screen.findByText(tooltipText);
101+
await userEvent.unhover(screen.getByText('(mixed)'));
102+
await waitFor(() => expect(screen.queryByText(tooltipText)).not.toBeInTheDocument());
103+
});
104+
105+
it('shows type when a single type in an array is provided', () => {
106+
render(<Field {...DEFAULT_PROPS} type={['string']} />);
107+
expect(screen.getByText('string')).toBeInTheDocument();
108+
expect(screen.queryByText('(mixed)')).not.toBeInTheDocument();
109+
});
110+
111+
it('shows unknown when an empty array type is provided', () => {
112+
render(<Field {...DEFAULT_PROPS} type={[]} />);
113+
expect(screen.getByText('unknown')).toBeInTheDocument();
114+
expect(screen.queryByText('(mixed)')).not.toBeInTheDocument();
115+
});
91116
});
92117

93118
describe('With glyphs', () => {

src/components/node/node.stories.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,22 +225,22 @@ export const DisabledWithHoverVariant: Story = {
225225
},
226226
};
227227

228-
export const NodeWithCustomTypeField: Story = {
228+
export const NodeWithMultipleTypesField: Story = {
229229
args: {
230230
...INTERNAL_NODE,
231231
data: {
232232
title: 'orders',
233233
fields: [
234234
{
235235
name: 'customerId',
236-
type: (
237-
<span>
238-
<strong>custom type display</strong>
239-
</span>
240-
),
236+
type: ['string', 'number'],
241237
variant: 'default',
242238
glyphs: ['key'],
243239
},
240+
{
241+
name: 'customerId',
242+
type: ['string', 'number', 'objectId', 'array', 'date', 'boolean', 'null', 'decimal', 'object', 'regex'],
243+
},
244244
],
245245
},
246246
},

src/types/node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ export interface NodeField {
152152
/**
153153
* The type of the field, for example "objectId".
154154
*/
155-
type?: string | React.ReactNode;
155+
type?: string | string[];
156156

157157
/**
158158
* The depth of the field.

0 commit comments

Comments
 (0)