Skip to content

Commit e3ea724

Browse files
authored
fix: replace styled-components Tooltip with next/Tooltip in TextField and TextArea (#4981)
* fix(next): replace old styled-components Tooltip with next/Tooltip in TextField and TextArea Part of #4978 * fix(next): restore label-row spacing when Tooltip wraps the info button The next/Tooltip wraps children in .eds-tooltip-anchor which becomes the flex item instead of the button, bypassing the existing negative-margin fix. Extend the selector to also target the anchor span. Part of #4978 * fix(eds-core-react): narrow labelInfo to string to match next/Tooltip title prop Part of #4978 * fix(eds-core-react): mock Popover API in TextField tests for jsdom compatibility Part of #4978 * style(eds-core-react): fix prettier formatting in TextField test mock * test: restore Element.prototype.matches after TextField tests Prevents the override from leaking into other test files running in the same worker. * fix: scope text-field header info selector to direct children Prevents margin-block being applied twice when the info button is wrapped in .eds-tooltip-anchor, which caused unintended positioning. * fix: scope text-field info selector to direct children; clean up test polyfill teardown - Use > combinator on .eds-text-field__info to prevent double margin-block when the button is wrapped in .eds-tooltip-anchor - Restore HTMLElement.prototype.matches after tests via Reflect.deleteProperty instead of saving/restoring the method reference (avoids unbound-method lint)
1 parent b9384a5 commit e3ea724

6 files changed

Lines changed: 43 additions & 14 deletions

File tree

packages/eds-core-react/src/components/next/TextArea/TextArea.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import type { TextAreaProps } from './TextArea.types'
55
import { Field, useFieldIds } from '../Field'
66
import { Input } from '../Input'
77
import { Button } from '../Button'
8-
// TODO: swap to next/Tooltip when available
9-
import { Tooltip } from '../../Tooltip'
8+
import { Tooltip } from '../Tooltip'
109
import { Icon } from '../Icon'
1110

1211
export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(

packages/eds-core-react/src/components/next/TextArea/textarea.css

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,35 @@
22
.eds-text-area {
33
& .label-row {
44
display: flex;
5+
gap: var(--eds-typography-gap-horizontal);
56
align-items: center;
67
justify-content: space-between;
7-
gap: var(--eds-typography-gap-horizontal);
8+
89
inline-size: 100%;
910

10-
& > button {
11+
& > button,
12+
& > .eds-tooltip-anchor {
1113
flex-shrink: 0;
1214
margin-block: calc(var(--eds-sizing-icon-xs) / -2);
1315
}
1416
}
1517

1618
& .eds-input-container {
19+
overflow: hidden;
1720
align-items: flex-start;
1821
padding-block: var(--eds-container-space-vertical);
19-
overflow: hidden;
2022

2123
& textarea.eds-input {
22-
box-sizing: border-box;
23-
overflow: auto;
24-
white-space: pre-wrap;
25-
text-overflow: clip;
2624
resize: vertical;
25+
26+
overflow: auto;
27+
28+
box-sizing: border-box;
2729
padding-block-end: var(--eds-container-space-vertical);
2830
padding-inline-end: var(--eds-selectable-space-horizontal);
31+
32+
text-overflow: clip;
33+
white-space: pre-wrap;
2934
}
3035

3136
&:has(+ .helper-row) {
@@ -37,8 +42,8 @@
3742

3843
& .helper-row {
3944
display: flex;
40-
align-items: baseline;
4145
gap: var(--eds-typography-gap-horizontal);
46+
align-items: baseline;
4247
inline-size: 100%;
4348
}
4449

packages/eds-core-react/src/components/next/TextField/TextField.test.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,28 @@ import userEvent from '@testing-library/user-event'
33
import { axe } from 'jest-axe'
44
import { TextField } from './TextField'
55

6+
// jsdom does not implement the Popover API (used by next/Tooltip)
7+
beforeAll(() => {
8+
HTMLElement.prototype.showPopover = function (this: HTMLElement) {
9+
this.setAttribute('data-popover-open', '')
10+
}
11+
HTMLElement.prototype.hidePopover = function (this: HTMLElement) {
12+
this.removeAttribute('data-popover-open')
13+
}
14+
HTMLElement.prototype.matches = function (
15+
this: HTMLElement,
16+
selector: string,
17+
) {
18+
if (selector === ':popover-open')
19+
return this.hasAttribute('data-popover-open')
20+
return Element.prototype.matches.call(this, selector)
21+
}
22+
})
23+
afterAll(() => {
24+
// Remove the own-property override — prototype chain falls back to Element.prototype.matches
25+
Reflect.deleteProperty(HTMLElement.prototype, 'matches')
26+
})
27+
628
describe('TextField (Next EDS 2.0)', () => {
729
it('Matches snapshot', () => {
830
const { container } = render(

packages/eds-core-react/src/components/next/TextField/TextField.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { TextFieldProps } from './TextField.types'
44
import { Field, useFieldIds } from '../Field'
55
import { Input } from '../Input'
66
import { Button } from '../Button'
7-
import { Tooltip } from '../../Tooltip'
7+
import { Tooltip } from '../Tooltip'
88
import { Icon } from '../Icon'
99
import './text-field.css'
1010

packages/eds-core-react/src/components/next/TextField/TextField.types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export type TextFieldProps = {
55
/** Label for the field */
66
label?: ReactNode
77
/** Info tooltip content shown next to the label */
8-
labelInfo?: ReactNode
8+
labelInfo?: string
99
/** Indicator text shown after label, e.g. "(Required)" or "(Optional)" */
1010
indicator?: string
1111
/** Descriptive text that provides additional context for the field */

packages/eds-core-react/src/components/next/TextField/text-field.css

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
@layer eds-components {
22
.eds-text-field__header {
33
display: flex;
4+
gap: var(--eds-typography-gap-horizontal);
45
align-items: center;
56
justify-content: space-between;
6-
gap: var(--eds-typography-gap-horizontal);
7+
78
inline-size: 100%;
89
}
910

10-
.eds-text-field__info {
11+
.eds-text-field__header > .eds-text-field__info,
12+
.eds-text-field__header > .eds-tooltip-anchor {
1113
flex-shrink: 0;
14+
1215
/* Negative margin collapses the button's 24px layout contribution to ~8px,
1316
matching Figma's 8px icon container. Label text-box height determines row height. */
1417
margin-block: calc(var(--eds-sizing-icon-xs) / -2);

0 commit comments

Comments
 (0)