diff --git a/.changeset/afraid-mugs-lay.md b/.changeset/afraid-mugs-lay.md new file mode 100644 index 0000000000..c2a3671f47 --- /dev/null +++ b/.changeset/afraid-mugs-lay.md @@ -0,0 +1,5 @@ +--- +"@navikt/ds-react": patch +--- + +Button: Fix edge-case where setting "loading={true}" in a Modal caused the button to get 0 width and not show spinner diff --git a/@navikt/core/css/button.css b/@navikt/core/css/button.css index fc8811fdfe..0f2e66779c 100644 --- a/@navikt/core/css/button.css +++ b/@navikt/core/css/button.css @@ -109,7 +109,7 @@ margin-right: var(--ac-button-icon-margin); } -.navds-button__icon:only-child { +.navds-button--icon-only .navds-button__icon { margin: 0; } @@ -497,6 +497,10 @@ } /* Loader overrides */ +.navds-button .navds-loader { + position: absolute; +} + .navds-button .navds-loader .navds-loader__foreground { stroke: var(--ac-button-loader-stroke, currentColor); } @@ -506,6 +510,10 @@ stroke: var(--ac-button-primary-loader-stroke-bg, rgb(255 255 255 / 0.3)); } +.navds-button--loading > :not(.navds-loader) { + visibility: hidden; +} + @media (forced-colors: active) { .navds-button:not(.navds-button--loading):where(:disabled, .navds-button--disabled) { opacity: 1; diff --git a/@navikt/core/css/darkside/button.darkside.css b/@navikt/core/css/darkside/button.darkside.css index bd292d82df..9021dbb055 100644 --- a/@navikt/core/css/darkside/button.darkside.css +++ b/@navikt/core/css/darkside/button.darkside.css @@ -69,7 +69,7 @@ margin-right: var(--__axc-button-icon-margin); } - &:only-child { + .navds-button--icon-only & { margin: 0; } } @@ -264,6 +264,10 @@ } /* Loader overrides */ +.navds-button .navds-loader { + position: absolute; +} + .navds-button .navds-loader .navds-loader__foreground { stroke: currentColor; } @@ -273,6 +277,10 @@ stroke: rgb(255 255 255 / 0.3); } +.navds-button--loading > :not(.navds-loader) { + visibility: hidden; +} + @media (forced-colors: active) { .navds-button:not(.navds-button--loading):where(:disabled, .navds-button--disabled) { opacity: 1; diff --git a/@navikt/core/react/src/button/Button.tsx b/@navikt/core/react/src/button/Button.tsx index 0f197f5799..4811a2f15a 100644 --- a/@navikt/core/react/src/button/Button.tsx +++ b/@navikt/core/react/src/button/Button.tsx @@ -1,11 +1,9 @@ import cl from "clsx"; -import React, { forwardRef, useRef, useState } from "react"; +import React, { forwardRef } from "react"; import { Loader } from "../loader"; import { Label } from "../typography"; import { omit } from "../util"; import { composeEventHandlers } from "../util/composeEventHandlers"; -import { useClientLayoutEffect } from "../util/hooks"; -import { useMergeRefs } from "../util/hooks/useMergeRefs"; import { OverridableComponent } from "../util/types"; export interface ButtonProps @@ -74,37 +72,18 @@ export const Button: OverridableComponent = size = "medium", loading = false, disabled, - style, icon, iconPosition = "left", + onKeyUp, ...rest }, ref, ) => { - const buttonRef = useRef(null); - const [widthOverride, setWidthOverride] = useState(); - - const mergedRef = useMergeRefs(buttonRef, ref); - - useClientLayoutEffect(() => { - if (loading) { - const requestID = window.requestAnimationFrame(() => { - setWidthOverride( - buttonRef?.current?.getBoundingClientRect()?.width, - ); - }); - return () => { - setWidthOverride(undefined); - cancelAnimationFrame(requestID); - }; - } - }, [loading, children]); - const filterProps: React.ButtonHTMLAttributes = - disabled ?? widthOverride ? omit(rest, ["href"]) : rest; + disabled || loading ? omit(rest, ["href"]) : rest; const handleKeyUp = (e: React.KeyboardEvent) => { - if (e.key === " " && !disabled && !widthOverride) { + if (e.key === " " && !disabled && !loading) { e.currentTarget.click(); } }; @@ -113,41 +92,32 @@ export const Button: OverridableComponent = - {widthOverride ? ( - - ) : ( - <> - {icon && iconPosition === "left" && ( - {icon} - )} - {children && ( - - )} - {icon && iconPosition === "right" && ( - {icon} - )} - + {icon && iconPosition === "left" && ( + {icon} + )} + {loading && } + {children && ( + + )} + {icon && iconPosition === "right" && ( + {icon} )} ); diff --git a/@navikt/core/react/src/button/button.stories.tsx b/@navikt/core/react/src/button/button.stories.tsx index a38e01441b..becd8bf8f0 100644 --- a/@navikt/core/react/src/button/button.stories.tsx +++ b/@navikt/core/react/src/button/button.stories.tsx @@ -2,6 +2,8 @@ import { StoryObj } from "@storybook/react"; import React from "react"; import { StarIcon as BaseStarIcon } from "@navikt/aksel-icons"; import { HStack, VStack } from "../layout/stack"; +import { Modal } from "../modal"; +import { BodyLong } from "../typography"; import { Button } from "./index"; export default { @@ -154,6 +156,51 @@ export const DisabledAsLink: Story = { render: () => , }; +export const InsideModal: Story = { + render: () => { + const ref = React.useRef(null); + + return ( +
+ + + + + + Culpa aliquip ut cupidatat laborum minim quis ex in aliqua. Qui + incididunt dolor do ad ut. Incididunt eiusmod nostrud deserunt + duis laborum. Proident aute culpa qui nostrud velit adipisicing + minim. Consequat aliqua aute dolor do sit Lorem nisi mollit velit. + Aliqua exercitation non minim minim pariatur sunt laborum ipsum. + Exercitation nostrud est laborum magna non non aliqua qui esse. + + + + + + + + +
+ ); + }, +}; + export const Chromatic: Story = { render: () => (