diff --git a/.changeset/happy-ducks-walk.md b/.changeset/happy-ducks-walk.md new file mode 100644 index 0000000000..784d81f2a6 --- /dev/null +++ b/.changeset/happy-ducks-walk.md @@ -0,0 +1,5 @@ +--- +"@navikt/ds-react": minor +--- + +Intern state: Komponenter respekterer nå `e.preventDefault()` bedre når event overskrives internt i komponent. diff --git a/@navikt/aksel/src/codemod/transforms/v2.0.0/update-js-tokens/update-js-tokens.ts b/@navikt/aksel/src/codemod/transforms/v2.0.0/update-js-tokens/update-js-tokens.ts index 4953796ac5..b6fb03f1bd 100644 --- a/@navikt/aksel/src/codemod/transforms/v2.0.0/update-js-tokens/update-js-tokens.ts +++ b/@navikt/aksel/src/codemod/transforms/v2.0.0/update-js-tokens/update-js-tokens.ts @@ -21,7 +21,7 @@ export default function transformer(file: JSCodeshift, api) { const jsImport = root.find(j.ImportDeclaration).filter((x) => { return ["@navikt/ds-tokens/dist/tokens"].includes( - x.node.source.value as string + x.node.source.value as string, ); }); @@ -36,7 +36,7 @@ export default function transformer(file: JSCodeshift, api) { let foundName: string = ""; getImportSpecifier(j, root, name, "@navikt/ds-tokens/dist/tokens").forEach( - (x) => (foundName = x.node.imported.name) + (x) => (foundName = x.node.imported.name), ); if (name === foundName) { @@ -45,7 +45,7 @@ export default function transformer(file: JSCodeshift, api) { j, root, name, - "@navikt/ds-tokens/dist/tokens" + "@navikt/ds-tokens/dist/tokens", ) || name; renameImportSpecifier( @@ -53,7 +53,7 @@ export default function transformer(file: JSCodeshift, api) { root, name, out, - "@navikt/ds-tokens/dist/tokens" + "@navikt/ds-tokens/dist/tokens", ); let code = root.toSource(getLineTerminator(file.source)); diff --git a/@navikt/aksel/src/codemod/utils/check.ts b/@navikt/aksel/src/codemod/utils/check.ts index 4149f2b8f5..213988fcac 100644 --- a/@navikt/aksel/src/codemod/utils/check.ts +++ b/@navikt/aksel/src/codemod/utils/check.ts @@ -12,7 +12,7 @@ interface TestT { export function check( dirName: string, - { fixture, migration, extension = "js", options = {} }: TestT + { fixture, migration, extension = "js", options = {} }: TestT, ) { describe(migration, () => { it(fixture, async () => { @@ -22,7 +22,7 @@ export function check( const source = fs.readFileSync(inputPath, "utf8"); const expected = fs.readFileSync( path.join(fixtureDir, `${fixture}.output.${extension}`), - "utf8" + "utf8", ); // Assumes transform is one level up from tests directory const module = await import(path.join(dirName, "..", migration)); @@ -34,11 +34,11 @@ export function check( expect( await prettier.format(output, { parser: parser === "js" ? "typescript" : parser, - }) + }), ).toBe( await prettier.format(expected, { parser: parser === "js" ? "typescript" : parser, - }) + }), ); }); }); diff --git a/@navikt/core/react/src/accordion/AccordionHeader.tsx b/@navikt/core/react/src/accordion/AccordionHeader.tsx index dff62d7ebf..08f91d6d91 100644 --- a/@navikt/core/react/src/accordion/AccordionHeader.tsx +++ b/@navikt/core/react/src/accordion/AccordionHeader.tsx @@ -2,6 +2,7 @@ import cl from "clsx"; import React, { forwardRef, useContext } from "react"; import { ChevronDownIcon } from "@navikt/aksel-icons"; import { Heading } from "../typography"; +import { composeEventHandlers } from "../util/composeEventHandlers"; import { AccordionContext } from "./AccordionContext"; import { AccordionItemContext } from "./AccordionItem"; @@ -30,10 +31,7 @@ const AccordionHeader = forwardRef( ref={ref} {...rest} className={cl("navds-accordion__header", className)} - onClick={(e: React.MouseEvent) => { - itemContext.toggleOpen(); - onClick && onClick(e); - }} + onClick={composeEventHandlers(onClick, itemContext.toggleOpen)} aria-expanded={itemContext.open} type="button" > diff --git a/@navikt/core/react/src/accordion/AccordionItem.tsx b/@navikt/core/react/src/accordion/AccordionItem.tsx index 1d613097b4..e049a9fa32 100644 --- a/@navikt/core/react/src/accordion/AccordionItem.tsx +++ b/@navikt/core/react/src/accordion/AccordionItem.tsx @@ -38,7 +38,7 @@ export const AccordionItemContext = const AccordionItem = forwardRef( ( { children, className, open, defaultOpen = false, onOpenChange, ...rest }, - ref + ref, ) => { const [_open, _setOpen] = useControllableState({ defaultValue: defaultOpen, @@ -78,7 +78,7 @@ const AccordionItem = forwardRef( ); - } + }, ); export default AccordionItem; diff --git a/@navikt/core/react/src/button/Button.tsx b/@navikt/core/react/src/button/Button.tsx index cc577ade12..10db264374 100644 --- a/@navikt/core/react/src/button/Button.tsx +++ b/@navikt/core/react/src/button/Button.tsx @@ -3,6 +3,7 @@ import React, { forwardRef, useRef, useState } from "react"; import { Loader } from "../loader"; import { Label } from "../typography"; import { OverridableComponent, omit, useClientLayoutEffect } from "../util"; +import { composeEventHandlers } from "../util/composeEventHandlers"; import { useMergeRefs } from "../util/hooks/useMergeRefs"; export interface ButtonProps @@ -99,22 +100,18 @@ export const Button: OverridableComponent = const filterProps: React.ButtonHTMLAttributes = disabled ?? widthOverride ? omit(rest, ["href"]) : rest; + const handleKeyUp = (e: React.KeyboardEvent) => { + if (e.key === " " && !disabled && !widthOverride) { + e.currentTarget.click(); + } + }; + return ( ) => { - filterProps.onKeyUp?.(e); - if ( - e.key === " " && - !disabled && - !widthOverride && - !e.isDefaultPrevented() - ) { - e.currentTarget.click(); - } - }} + onKeyUp={composeEventHandlers(filterProps.onKeyUp, handleKeyUp)} className={cl( className, "navds-button", diff --git a/@navikt/core/react/src/chips/Removable.tsx b/@navikt/core/react/src/chips/Removable.tsx index 1221f1d76e..19cbf99a15 100644 --- a/@navikt/core/react/src/chips/Removable.tsx +++ b/@navikt/core/react/src/chips/Removable.tsx @@ -1,6 +1,7 @@ import cl from "clsx"; import React, { forwardRef } from "react"; import { XMarkIcon } from "@navikt/aksel-icons"; +import { composeEventHandlers } from "../util/composeEventHandlers"; export interface RemovableChipsProps extends React.ButtonHTMLAttributes { @@ -33,6 +34,7 @@ export const RemovableChips = forwardRef< removeLabel = "slett", onDelete, type = "button", + onClick, ...rest }, ref, @@ -48,10 +50,7 @@ export const RemovableChips = forwardRef< `navds-chips__removable--${variant}`, )} aria-label={`${children} ${removeLabel}`} - onClick={(e) => { - onDelete?.(); - rest?.onClick?.(e); - }} + onClick={composeEventHandlers(onClick, onDelete)} > {children} diff --git a/@navikt/core/react/src/copybutton/CopyButton.tsx b/@navikt/core/react/src/copybutton/CopyButton.tsx index a4fe983bf4..a82b11b459 100644 --- a/@navikt/core/react/src/copybutton/CopyButton.tsx +++ b/@navikt/core/react/src/copybutton/CopyButton.tsx @@ -8,6 +8,7 @@ import React, { } from "react"; import { CheckmarkIcon, FilesIcon } from "@navikt/aksel-icons"; import { Label } from "../typography"; +import { composeEventHandlers } from "../util/composeEventHandlers"; import copy from "../util/copy"; export interface CopyButtonProps @@ -97,6 +98,7 @@ export const CopyButton = forwardRef( title = "Kopier", activeTitle = "Kopiert", iconPosition = "left", + onClick, ...rest }, ref, @@ -110,14 +112,11 @@ export const CopyButton = forwardRef( }; }, []); - const handleClick = ( - event: React.MouseEvent, - ) => { + const handleClick = () => { timeoutRef.current && clearTimeout(timeoutRef.current); copy(copyText); setActive(true); onActiveChange?.(true); - rest.onClick?.(event); timeoutRef.current = window.setTimeout(() => { setActive(false); @@ -160,7 +159,7 @@ export const CopyButton = forwardRef( "navds-copybutton--active": active, }, )} - onClick={handleClick} + onClick={composeEventHandlers(onClick, handleClick)} > {iconPosition === "left" && copyIcon} diff --git a/@navikt/core/react/src/dropdown/Menu/GroupedList/GroupedItem.tsx b/@navikt/core/react/src/dropdown/Menu/GroupedList/GroupedItem.tsx index 5969a6fcab..ff3bdf6f02 100644 --- a/@navikt/core/react/src/dropdown/Menu/GroupedList/GroupedItem.tsx +++ b/@navikt/core/react/src/dropdown/Menu/GroupedList/GroupedItem.tsx @@ -1,6 +1,7 @@ import cl from "clsx"; import React, { forwardRef, useContext } from "react"; import { OverridableComponent } from "../../../util"; +import { composeEventHandlers } from "../../../util/composeEventHandlers"; import { DropdownContext } from "../../context"; export interface GroupedItemProps @@ -14,28 +15,27 @@ export interface GroupedItemProps export const GroupedItem: OverridableComponent< GroupedItemProps, HTMLButtonElement -> = forwardRef(({ as: Component = "button", className, ...rest }, ref) => { - const context = useContext(DropdownContext); +> = forwardRef( + ({ as: Component = "button", className, onClick, ...rest }, ref) => { + const context = useContext(DropdownContext); - return ( -
- ) => { - context?.onSelect?.(event); - rest?.onClick?.(event); - }} - ref={ref} - className={cl( - "navds-dropdown__item", - "navds-body-short", - "navds-body-short--small", - className, - )} - /> -
- ); -}); + return ( +
+ +
+ ); + }, +); export default GroupedItem; diff --git a/@navikt/core/react/src/dropdown/Menu/List/Item.tsx b/@navikt/core/react/src/dropdown/Menu/List/Item.tsx index 9b4c61bbec..5139ad293c 100644 --- a/@navikt/core/react/src/dropdown/Menu/List/Item.tsx +++ b/@navikt/core/react/src/dropdown/Menu/List/Item.tsx @@ -1,6 +1,7 @@ import cl from "clsx"; import React, { forwardRef, useContext } from "react"; import { OverridableComponent } from "../../../util"; +import { composeEventHandlers } from "../../../util/composeEventHandlers"; import { DropdownContext } from "../../context"; export interface ListItemProps extends React.ButtonHTMLAttributes { @@ -11,28 +12,27 @@ export interface ListItemProps extends React.ButtonHTMLAttributes { } export const ListItem: OverridableComponent = - forwardRef(({ as: Component = "button", className, ...rest }, ref) => { - const context = useContext(DropdownContext); + forwardRef( + ({ as: Component = "button", className, onClick, ...rest }, ref) => { + const context = useContext(DropdownContext); - return ( -
  • - ) => { - context?.onSelect?.(event); - rest?.onClick?.(event); - }} - ref={ref} - className={cl( - "navds-dropdown__item", - "navds-body-short", - "navds-body-short--small", - className, - )} - /> -
  • - ); - }); + return ( +
  • + +
  • + ); + }, + ); export default ListItem; diff --git a/@navikt/core/react/src/dropdown/Toggle.tsx b/@navikt/core/react/src/dropdown/Toggle.tsx index effdcea9c6..fcf73b0a3e 100644 --- a/@navikt/core/react/src/dropdown/Toggle.tsx +++ b/@navikt/core/react/src/dropdown/Toggle.tsx @@ -1,5 +1,6 @@ import cl from "clsx"; import React, { forwardRef, useContext } from "react"; +import { composeEventHandlers } from "../util/composeEventHandlers"; import { DropdownContext } from "./context"; export interface ToggleProps @@ -21,6 +22,13 @@ export const Toggle = forwardRef( const { setAnchorEl, handleToggle, isOpen } = context; + const handleClick = ( + e: React.MouseEvent, + ) => { + setAnchorEl(e.currentTarget); + handleToggle(!isOpen); + }; + return (