Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Textarea: resize immediately upon receiving resize event #3463

Merged
merged 7 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cool-trains-care.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@navikt/ds-react": patch
---

Textarea: resize immediately upon receiving resize event (eg. inside modal opening).
21 changes: 21 additions & 0 deletions @navikt/core/react/src/form/textarea/textarea.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,27 @@ AutoScrollbar.argTypes = {
minRows: { type: "number" },
};

export const InsideModal: StoryFn<typeof Textarea> = () => {
const ref = React.useRef<HTMLDialogElement>(null);

return (
<>
<Button onClick={() => ref.current?.showModal()}>Open modal</Button>
<React.StrictMode>
<Modal
ref={ref}
header={{ heading: "Skjema" }}
aria-label="Modal med textarea"
>
<Modal.Body>
<Textarea label="Har du noen tilbakemeldinger?" />
</Modal.Body>
</Modal>
</React.StrictMode>
</>
);
};

export const ModalStrictMode: StoryFn<typeof Textarea> = () => {
// Story added after fixing an issue where TextareaAutoSize would reach max re-renders
// and set the height to 2px when used in StrictMode in a Modal that is initially open.
Expand Down
26 changes: 15 additions & 11 deletions @navikt/core/react/src/util/TextareaAutoSize.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,23 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
});
};

const handleResize = debounce(() => {
renders.current = 0;

if (inputRef.current?.style.height || inputRef.current?.style.width) {
// User has resized manually
if (inputRef.current?.style.overflow === "hidden") {
setState((oldState) => ({ ...oldState, overflow: false })); // The state update isn't important, we just need to trigger a rerender
const handleResize = debounce(
() => {
renders.current = 0;

if (inputRef.current?.style.height || inputRef.current?.style.width) {
// User has resized manually
if (inputRef.current?.style.overflow === "hidden") {
setState((oldState) => ({ ...oldState, overflow: false })); // The state update isn't important, we just need to trigger a rerender
}
return;
}
return;
}

syncHeightWithFlushSync();
});
syncHeightWithFlushSync();
},
166,
true,
);

const input = inputRef.current!;
const containerWindow = ownerWindow(input);
Expand Down
14 changes: 11 additions & 3 deletions @navikt/core/react/src/util/debounce.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
"use client";
// https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/debounce.js
export default function debounce(func, wait = 166) {
let timeout: ReturnType<typeof setTimeout>;
function debounced(this: any, ...args) {
export default function debounce<T extends unknown[]>(
func: (...args: T) => void,
wait = 166,
leading = false,
) {
let timeout: ReturnType<typeof setTimeout> | undefined;
function debounced(this: any, ...args: T) {
const later = () => {
timeout = undefined;
func.apply(this, args);
};
if (!timeout && leading) {
later();
}
clearTimeout(timeout);
timeout = setTimeout(later, wait);
}
Expand Down
Loading