Skip to content

Commit 72c5f78

Browse files
authored
fix(eds-core-react, eds-utils)!: Improve onChange handler typing for TextField component and remove multiline support (#4134)
* feat(eds-core-react): export the Textarea component * feat(eds-core-react): make Textarea isolated and supporting all props * chore(eds-core-react): mock React.useId for consistent snapshot IDs in tests * feat(eds-utils)!: remove custom useId * feat(eds-utils)!: update useAutoResize to return a callback ref * feat(eds-utils): enhance OverridableComponent type to include HTML attributes for better flexibility
1 parent 335c767 commit 72c5f78

31 files changed

Lines changed: 1710 additions & 437 deletions

.cursorrules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Cursor AI Instructions for Equinor Design System
2+
3+
Follow all guidelines from `.github/copilot-instructions.md`

CODEMOD.md

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
# Codemod for TextField multiline to Textarea Migration
2+
3+
This codemod helps automate the migration from `TextField` with `multiline` prop to the `Textarea` component.
4+
5+
## Prerequisites
6+
7+
- Node.js 14 or higher
8+
- jscodeshift installed globally or as a dev dependency
9+
10+
```bash
11+
npm install -g jscodeshift
12+
# or
13+
pnpm add -D jscodeshift
14+
```
15+
16+
## Usage
17+
18+
### Quick Start
19+
20+
```bash
21+
# Run on a single file
22+
npx jscodeshift -t textfield-to-textarea.codemod.js src/components/MyComponent.tsx
23+
24+
# Run on a directory
25+
npx jscodeshift -t textfield-to-textarea.codemod.js src/
26+
27+
# With TypeScript parser
28+
npx jscodeshift -t textfield-to-textarea.codemod.js --parser=tsx src/
29+
```
30+
31+
### Options
32+
33+
```bash
34+
# Dry run (see what would change without modifying files)
35+
npx jscodeshift -t textfield-to-textarea.codemod.js --dry src/
36+
37+
# Show diff
38+
npx jscodeshift -t textfield-to-textarea.codemod.js --print src/
39+
40+
# Verbose output
41+
npx jscodeshift -t textfield-to-textarea.codemod.js -v 2 src/
42+
```
43+
44+
## What the Codemod Does
45+
46+
1. **Finds TextField components** with `multiline` prop set to `true`
47+
2. **Replaces component name** from `TextField` to `Textarea`
48+
3. **Removes multiline prop**
49+
4. **Renames textareaRef to ref** (if present)
50+
5. **Updates imports** to include `Textarea` instead of (or in addition to) `TextField`
51+
6. **Removes TextField import** if no longer used in the file
52+
53+
## Examples
54+
55+
### Example 1: Basic Transformation
56+
57+
**Before:**
58+
```tsx
59+
import { TextField } from '@equinor/eds-core-react'
60+
61+
function MyComponent() {
62+
return (
63+
<TextField
64+
multiline
65+
label="Description"
66+
placeholder="Enter text"
67+
/>
68+
)
69+
}
70+
```
71+
72+
**After:**
73+
```tsx
74+
import { Textarea } from '@equinor/eds-core-react'
75+
76+
function MyComponent() {
77+
return (
78+
<Textarea
79+
label="Description"
80+
placeholder="Enter text"
81+
/>
82+
)
83+
}
84+
```
85+
86+
### Example 2: With Refs
87+
88+
**Before:**
89+
```tsx
90+
import { TextField } from '@equinor/eds-core-react'
91+
import { useRef } from 'react'
92+
93+
function MyComponent() {
94+
const ref = useRef<HTMLTextAreaElement>(null)
95+
96+
return (
97+
<TextField
98+
multiline
99+
textareaRef={ref}
100+
label="Notes"
101+
/>
102+
)
103+
}
104+
```
105+
106+
**After:**
107+
```tsx
108+
import { Textarea } from '@equinor/eds-core-react'
109+
import { useRef } from 'react'
110+
111+
function MyComponent() {
112+
const ref = useRef<HTMLTextAreaElement>(null)
113+
114+
return (
115+
<Textarea
116+
ref={ref}
117+
label="Notes"
118+
/>
119+
)
120+
}
121+
```
122+
123+
### Example 3: Mixed Usage (TextField kept for single-line)
124+
125+
**Before:**
126+
```tsx
127+
import { TextField } from '@equinor/eds-core-react'
128+
129+
function MyComponent() {
130+
return (
131+
<>
132+
<TextField label="Name" />
133+
<TextField multiline label="Description" />
134+
</>
135+
)
136+
}
137+
```
138+
139+
**After:**
140+
```tsx
141+
import { TextField, Textarea } from '@equinor/eds-core-react'
142+
143+
function MyComponent() {
144+
return (
145+
<>
146+
<TextField label="Name" />
147+
<Textarea label="Description" />
148+
</>
149+
)
150+
}
151+
```
152+
153+
## Limitations
154+
155+
The codemod handles most common cases but has limitations:
156+
157+
### Not Handled Automatically
158+
159+
1. **Conditional multiline prop:**
160+
```tsx
161+
<TextField multiline={someCondition} />
162+
```
163+
→ Manual review needed
164+
165+
2. **Dynamic prop spreading:**
166+
```tsx
167+
const props = { multiline: true, label: "Text" }
168+
<TextField {...props} />
169+
```
170+
→ Manual review needed
171+
172+
3. **Props not available on Textarea:**
173+
```tsx
174+
<TextField multiline inputIcon={<Icon />} />
175+
```
176+
→ Manual refactoring needed (remove inputIcon)
177+
178+
4. **Complex ref patterns:**
179+
```tsx
180+
<TextField multiline ref={combineRefs(ref1, ref2)} />
181+
```
182+
→ Manual review needed
183+
184+
## Manual Review Checklist
185+
186+
After running the codemod, review the following:
187+
188+
- [ ] Check for TextField components with conditional `multiline` props
189+
- [ ] Verify all Textarea components have correct props
190+
- [ ] Remove any Textarea-incompatible props (inputIcon, unit, meta)
191+
- [ ] Update TypeScript types if using TextFieldProps
192+
- [ ] Test all migrated components
193+
- [ ] Update tests if they reference TextField with multiline
194+
- [ ] Check console for any warnings
195+
196+
## Prompts for Common Scenarios
197+
198+
### Find all TextField with multiline in your codebase
199+
200+
```bash
201+
# Using grep
202+
grep -r "TextField.*multiline" src/
203+
204+
# Using ripgrep (faster)
205+
rg "TextField.*multiline" src/
206+
207+
# Using ag (the silver searcher)
208+
ag "TextField.*multiline" src/
209+
```
210+
211+
### Find potential missed cases
212+
213+
```bash
214+
# Find TextField with multiline spread in props
215+
rg "TextField.*\{\.\.\..*\}" src/
216+
217+
# Find conditional multiline
218+
rg "multiline=\{" src/
219+
```
220+
221+
## Testing the Codemod
222+
223+
Test the codemod on sample files before running on your entire codebase:
224+
225+
```bash
226+
# Create a test file
227+
cat > test-file.tsx << 'EOF'
228+
import { TextField } from '@equinor/eds-core-react'
229+
230+
export const TestComponent = () => (
231+
<TextField multiline label="Test" />
232+
)
233+
EOF
234+
235+
# Run codemod
236+
npx jscodeshift -t textfield-to-textarea.codemod.js --dry test-file.tsx
237+
238+
# Check the output
239+
cat test-file.tsx
240+
```
241+
242+
## Rollback
243+
244+
If you need to rollback the changes:
245+
246+
```bash
247+
# If you have git
248+
git checkout -- src/
249+
250+
# If you made a backup
251+
cp -r src.backup/* src/
252+
```
253+
254+
## Support
255+
256+
If you encounter issues with the codemod:
257+
258+
1. Check the limitations section above
259+
2. Review the manual review checklist
260+
3. Try running with `-v 2` for verbose output
261+
4. Create an issue with a minimal reproduction case
262+
263+
## Advanced Usage
264+
265+
### Custom Parser Options
266+
267+
```bash
268+
# For JavaScript files
269+
npx jscodeshift -t textfield-to-textarea.codemod.js --parser=babylon src/
270+
271+
# For Flow
272+
npx jscodeshift -t textfield-to-textarea.codemod.js --parser=flow src/
273+
```
274+
275+
### Ignore Patterns
276+
277+
```bash
278+
# Ignore specific directories
279+
npx jscodeshift -t textfield-to-textarea.codemod.js \
280+
--ignore-pattern="**/node_modules/**" \
281+
--ignore-pattern="**/build/**" \
282+
src/
283+
```
284+
285+
### Process Specific File Types
286+
287+
```bash
288+
# Only .tsx files
289+
find src -name "*.tsx" -exec npx jscodeshift -t textfield-to-textarea.codemod.js {} \;
290+
291+
# Both .tsx and .ts files
292+
npx jscodeshift -t textfield-to-textarea.codemod.js \
293+
--extensions=tsx,ts \
294+
src/
295+
```

0 commit comments

Comments
 (0)