Skip to content

Commit 4f5dcda

Browse files
feat(ClipboardCopy): added textinput callbacks and props (#12180)
1 parent 8c91c15 commit 4f5dcda

File tree

3 files changed

+89
-2
lines changed

3 files changed

+89
-2
lines changed

packages/react-core/src/components/ClipboardCopy/ClipboardCopy.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ export interface ClipboardCopyProps extends Omit<React.HTMLProps<HTMLDivElement>
5555
textAriaLabel?: string;
5656
/** Aria-label to use on the ClipboardCopyToggle. */
5757
toggleAriaLabel?: string;
58+
/** ID to use on the TextInput. */
59+
inputId?: string;
60+
/** Name attribute to use on the TextInput. */
61+
inputName?: string;
5862
/** Flag to show if the input is read only. */
5963
isReadOnly?: boolean;
6064
/** Flag to determine if clipboard copy is in the expanded state initially */
@@ -91,6 +95,10 @@ export interface ClipboardCopyProps extends Omit<React.HTMLProps<HTMLDivElement>
9195
onCopy?: (event: React.ClipboardEvent<HTMLDivElement>, text?: React.ReactNode) => void;
9296
/** A function that is triggered on changing the text. */
9397
onChange?: (event: React.FormEvent, text?: string) => void;
98+
/** Callback function when text input is focused */
99+
onInputFocus?: (event?: any) => void;
100+
/** Callback function when text input is blurred (focus leaves) */
101+
onInputBlur?: (event?: any) => void;
94102
/** The text which is copied. */
95103
children: string | string[];
96104
/** Additional actions for inline clipboard copy. Should be wrapped with ClipboardCopyAction. */
@@ -177,6 +185,8 @@ class ClipboardCopy extends Component<ClipboardCopyProps, ClipboardCopyState> {
177185
/* eslint-disable @typescript-eslint/no-unused-vars */
178186
isExpanded,
179187
onChange, // Don't pass to <div>
188+
onInputFocus, // Don't pass to <div>
189+
onInputBlur, // Don't pass to <div>
180190
/* eslint-enable @typescript-eslint/no-unused-vars */
181191
isReadOnly,
182192
isCode,
@@ -189,6 +199,8 @@ class ClipboardCopy extends Component<ClipboardCopyProps, ClipboardCopyState> {
189199
clickTip,
190200
textAriaLabel,
191201
toggleAriaLabel,
202+
inputId,
203+
inputName,
192204
variant,
193205
position,
194206
className,
@@ -295,8 +307,11 @@ class ClipboardCopy extends Component<ClipboardCopyProps, ClipboardCopyState> {
295307
readOnlyVariant={isReadOnly || this.state.expanded ? 'default' : undefined}
296308
onChange={this.updateText}
297309
value={this.state.expanded ? this.state.textWhenExpanded : copyableText}
298-
id={`text-input-${id}`}
310+
id={inputId ?? `text-input-${id}`}
311+
name={inputName}
299312
aria-label={textAriaLabel}
313+
onFocus={onInputFocus}
314+
onBlur={onInputBlur}
300315
{...(isCode && { dir: 'ltr' })}
301316
/>
302317
<ClipboardCopyButton

packages/react-core/src/components/ClipboardCopy/__tests__/ClipboardCopy.test.tsx

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,18 @@ test('Passes textAriaLabel to TextInput', () => {
309309
expect(screen.getByRole('textbox')).toHaveAccessibleName('text label');
310310
});
311311

312+
test('Passes inputId to TextInput', () => {
313+
render(<ClipboardCopy inputId="custom-input-id">{children}</ClipboardCopy>);
314+
315+
expect(screen.getByRole('textbox')).toHaveAttribute('id', 'custom-input-id');
316+
});
317+
318+
test('Passes inputName to TextInput', () => {
319+
render(<ClipboardCopy inputName="custom-input-name">{children}</ClipboardCopy>);
320+
321+
expect(screen.getByRole('textbox')).toHaveAttribute('name', 'custom-input-name');
322+
});
323+
312324
test('Calls onChange when ClipboardCopy textinput is typed in', async () => {
313325
const onChangeMock = jest.fn();
314326
const user = userEvent.setup();
@@ -338,6 +350,66 @@ test('Does not call onChange when ClipboardCopy textinput is not typed in', asyn
338350
expect(onChangeMock).not.toHaveBeenCalled();
339351
});
340352

353+
test('Calls onFocus when ClipboardCopy textinput is focused', async () => {
354+
const onFocusMock = jest.fn();
355+
const user = userEvent.setup();
356+
357+
render(<ClipboardCopy onInputFocus={onFocusMock}>{children}</ClipboardCopy>);
358+
359+
await user.click(screen.getByRole('textbox'));
360+
361+
expect(onFocusMock).toHaveBeenCalledTimes(1);
362+
});
363+
364+
test('Does not call onFocus when ClipboardCopy textinput is not focused', async () => {
365+
const onFocusMock = jest.fn();
366+
const user = userEvent.setup();
367+
368+
render(
369+
<>
370+
<ClipboardCopy onInputFocus={onFocusMock}>{children}</ClipboardCopy>
371+
<input aria-label="native input" />
372+
</>
373+
);
374+
375+
await user.click(screen.getByRole('textbox', { name: 'native input' }));
376+
377+
expect(onFocusMock).not.toHaveBeenCalled();
378+
});
379+
380+
test('Calls onBlur when ClipboardCopy textinput loses focus', async () => {
381+
const onBlurMock = jest.fn();
382+
const user = userEvent.setup();
383+
384+
render(
385+
<>
386+
<ClipboardCopy onInputBlur={onBlurMock}>{children}</ClipboardCopy>
387+
<input aria-label="native input" />
388+
</>
389+
);
390+
391+
await user.click(screen.getByRole('textbox', { name: 'Copyable input' }));
392+
await user.click(screen.getByRole('textbox', { name: 'native input' }));
393+
394+
expect(onBlurMock).toHaveBeenCalledTimes(1);
395+
});
396+
397+
test('Does not call onBlur when ClipboardCopy textinput does not lose focus', async () => {
398+
const onBlurMock = jest.fn();
399+
const user = userEvent.setup();
400+
401+
render(
402+
<>
403+
<ClipboardCopy onInputBlur={onBlurMock}>{children}</ClipboardCopy>
404+
<input aria-label="native input" />
405+
</>
406+
);
407+
408+
await user.click(screen.getByRole('textbox', { name: 'native input' }));
409+
410+
expect(onBlurMock).not.toHaveBeenCalled();
411+
});
412+
341413
test('Calls onCopy when ClipboardCopyButton is clicked', async () => {
342414
const onCopyMock = jest.fn();
343415
const user = userEvent.setup();

packages/react-core/src/components/ClipboardCopy/__tests__/__snapshots__/ClipboardCopy.test.tsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ exports[`Matches snapshot 1`] = `
1818
<input
1919
aria-invalid="false"
2020
aria-label="Copyable input"
21-
data-ouia-component-id="OUIA-Generated-TextInputBase-36"
21+
data-ouia-component-id="OUIA-Generated-TextInputBase-42"
2222
data-ouia-component-type="PF6/TextInput"
2323
data-ouia-safe="true"
2424
id="text-input-generated-id"

0 commit comments

Comments
 (0)