diff --git a/.changeset/heavy-shrimps-destroy.md b/.changeset/heavy-shrimps-destroy.md new file mode 100644 index 0000000000..81b6390a3c --- /dev/null +++ b/.changeset/heavy-shrimps-destroy.md @@ -0,0 +1,6 @@ +--- +"@navikt/ds-react": minor +"@navikt/ds-css": minor +--- + +Tag: Har nå innebygd støtte for ikoner diff --git a/.changeset/quick-monkeys-repeat.md b/.changeset/quick-monkeys-repeat.md new file mode 100644 index 0000000000..2a6c564a6d --- /dev/null +++ b/.changeset/quick-monkeys-repeat.md @@ -0,0 +1,5 @@ +--- +"@navikt/ds-react": patch +--- + +Intern-API: Erstattet `mergeRefs` i `useMemo` med lokal `useMergeRefs`-hook diff --git a/@navikt/core/css/tag.css b/@navikt/core/css/tag.css index 4a843f8135..9000584d9c 100644 --- a/@navikt/core/css/tag.css +++ b/@navikt/core/css/tag.css @@ -1,4 +1,7 @@ .navds-tag { + --__ac-tag-icon-size: 1.5rem; + --__ac-tag-icon-margin: -2px; + border: 1px solid; border-radius: var(--a-border-radius-small); display: inline-flex; @@ -12,11 +15,26 @@ .navds-tag--small { min-height: 1.5rem; padding: 0 var(--a-spacing-1-alt); + + --__ac-tag-icon-size: 1.25rem; } .navds-tag--xsmall { min-height: 1.25rem; padding: 0 var(--a-spacing-1); + + --__ac-tag-icon-size: 1rem; + --__ac-tag-icon-margin: -1px; +} + +.navds-tag:has(.navds-tag__icon--left) { + gap: var(--a-spacing-05); +} + +.navds-tag__icon--left { + font-size: var(--__ac-tag-icon-size); + margin-inline-start: var(--__ac-tag-icon-margin); + display: flex; } .navds-tag--error { diff --git a/@navikt/core/react/src/button/Button.tsx b/@navikt/core/react/src/button/Button.tsx index 1a7eb52f26..10db264374 100644 --- a/@navikt/core/react/src/button/Button.tsx +++ b/@navikt/core/react/src/button/Button.tsx @@ -1,14 +1,10 @@ import cl from "clsx"; -import React, { forwardRef, useMemo, useRef, useState } from "react"; +import React, { forwardRef, useRef, useState } from "react"; import { Loader } from "../loader"; import { Label } from "../typography"; -import { - OverridableComponent, - mergeRefs, - omit, - useClientLayoutEffect, -} from "../util"; +import { OverridableComponent, omit, useClientLayoutEffect } from "../util"; import { composeEventHandlers } from "../util/composeEventHandlers"; +import { useMergeRefs } from "../util/hooks/useMergeRefs"; export interface ButtonProps extends React.ButtonHTMLAttributes { @@ -85,7 +81,7 @@ export const Button: OverridableComponent = const buttonRef = useRef(null); const [widthOverride, setWidthOverride] = useState(); - const mergedRef = useMemo(() => mergeRefs([buttonRef, ref]), [ref]); + const mergedRef = useMergeRefs(buttonRef, ref); useClientLayoutEffect(() => { if (loading) { diff --git a/@navikt/core/react/src/date/datepicker/DatePicker.tsx b/@navikt/core/react/src/date/datepicker/DatePicker.tsx index 7fa5cf15ab..b4106feb2a 100644 --- a/@navikt/core/react/src/date/datepicker/DatePicker.tsx +++ b/@navikt/core/react/src/date/datepicker/DatePicker.tsx @@ -1,8 +1,9 @@ import cl from "clsx"; import isWeekend from "date-fns/isWeekend"; -import React, { forwardRef, useMemo, useRef, useState } from "react"; +import React, { forwardRef, useRef, useState } from "react"; import { DateRange, DayPicker, isMatch } from "react-day-picker"; -import { mergeRefs, omit, useId } from "../../util"; +import { omit, useId } from "../../util"; +import { useMergeRefs } from "../../util/hooks/useMergeRefs"; import { DateContext } from "../context"; import { DatePickerInput } from "../parts/DateInput"; import { DateWrapper } from "../parts/DateWrapper"; @@ -88,7 +89,7 @@ export const DatePicker = forwardRef( const [open, setOpen] = useState(_open ?? false); const wrapperRef = useRef(null); - const mergedRef = useMemo(() => mergeRefs([wrapperRef, ref]), [ref]); + const mergedRef = useMergeRefs(wrapperRef, ref); const [selectedDates, setSelectedDates] = React.useState< Date | Date[] | DateRange | undefined diff --git a/@navikt/core/react/src/date/monthpicker/MonthPicker.tsx b/@navikt/core/react/src/date/monthpicker/MonthPicker.tsx index 380b79f734..95e9c011a0 100644 --- a/@navikt/core/react/src/date/monthpicker/MonthPicker.tsx +++ b/@navikt/core/react/src/date/monthpicker/MonthPicker.tsx @@ -1,7 +1,8 @@ import cl from "clsx"; -import React, { forwardRef, useMemo, useRef, useState } from "react"; +import React, { forwardRef, useRef, useState } from "react"; import { RootProvider } from "react-day-picker"; -import { mergeRefs, useId } from "../../util"; +import { useId } from "../../util"; +import { useMergeRefs } from "../../util/hooks/useMergeRefs"; import { DateContext, SharedMonthProvider } from "../context"; import { MonthPickerInput } from "../parts/DateInput"; import { DateWrapper } from "../parts/DateWrapper"; @@ -81,7 +82,7 @@ export const MonthPicker = forwardRef( const [open, setOpen] = useState(_open ?? false); const wrapperRef = useRef(null); - const mergedRef = useMemo(() => mergeRefs([wrapperRef, ref]), [ref]); + const mergedRef = useMergeRefs(wrapperRef, ref); const [selectedMonth, setSelectedMonth] = useState( defaultSelected, diff --git a/@navikt/core/react/src/form/combobox/Combobox.tsx b/@navikt/core/react/src/form/combobox/Combobox.tsx index f387c45250..1b63de3fe8 100644 --- a/@navikt/core/react/src/form/combobox/Combobox.tsx +++ b/@navikt/core/react/src/form/combobox/Combobox.tsx @@ -1,7 +1,7 @@ import cl from "clsx"; -import React, { forwardRef, useMemo, useRef } from "react"; +import React, { forwardRef, useRef } from "react"; import { BodyShort, ErrorMessage, Label } from "../../typography"; -import { mergeRefs } from "../../util"; +import { useMergeRefs } from "../../util/hooks/useMergeRefs"; import ClearButton from "./ClearButton"; import ComboboxWrapper from "./ComboboxWrapper"; import FilteredOptions from "./FilteredOptions/FilteredOptions"; @@ -50,10 +50,7 @@ export const Combobox = forwardRef< size = "medium", } = useInputContext(); - const mergedInputRef = useMemo( - () => mergeRefs([inputRef, ref]), - [inputRef, ref], - ); + const mergedInputRef = useMergeRefs(inputRef, ref); return ( ( } = props; const searchRef = useRef(null); - const mergedRef = useMemo(() => mergeRefs([searchRef, ref]), [ref]); + const mergedRef = useMergeRefs(searchRef, ref); const [internalValue, setInternalValue] = useState(defaultValue ?? ""); diff --git a/@navikt/core/react/src/help-text/HelpText.tsx b/@navikt/core/react/src/help-text/HelpText.tsx index 175779e0dd..fe55c09ced 100644 --- a/@navikt/core/react/src/help-text/HelpText.tsx +++ b/@navikt/core/react/src/help-text/HelpText.tsx @@ -1,8 +1,8 @@ import cl from "clsx"; -import React, { forwardRef, useMemo, useRef, useState } from "react"; +import React, { forwardRef, useRef, useState } from "react"; import { Popover, PopoverProps } from "../popover"; -import { mergeRefs } from "../util"; import { composeEventHandlers } from "../util/composeEventHandlers"; +import { useMergeRefs } from "../util/hooks/useMergeRefs"; import { HelpTextIcon } from "./HelpTextIcon"; export interface HelpTextProps @@ -48,7 +48,8 @@ export const HelpText = forwardRef( ref, ) => { const buttonRef = useRef(null); - const mergedRef = useMemo(() => mergeRefs([buttonRef, ref]), [ref]); + const mergedRef = useMergeRefs(buttonRef, ref); + const [open, setOpen] = useState(false); return ( diff --git a/@navikt/core/react/src/help-text/help-text.stories.tsx b/@navikt/core/react/src/help-text/help-text.stories.tsx index 6b49f9c3f6..3a3619f869 100644 --- a/@navikt/core/react/src/help-text/help-text.stories.tsx +++ b/@navikt/core/react/src/help-text/help-text.stories.tsx @@ -1,63 +1,57 @@ +import { Meta, StoryFn, StoryObj } from "@storybook/react"; import React, { useEffect, useRef } from "react"; import { BodyLong, Heading, HelpText } from ".."; -export default { +const meta: Meta = { title: "ds-react/HelpText", component: HelpText, parameters: { chromatic: { delay: 300 }, }, +}; +export default meta; + +export const Default: StoryObj = { + render: (props) => ( + Id ullamco excepteur elit fugiat labore. + ), + + args: { + title: "Show tooltip", + }, argTypes: { placement: { - control: { - type: "radio", - options: [ - "top", - "bottom", - "right", - "left", - "top-start", - "top-end", - "bottom-start", - "bottom-end", - "right-start", - "right-end", - "left-start", - "left-end", - ], - }, + control: { type: "radio" }, + options: [ + "top", + "bottom", + "right", + "left", + "top-start", + "top-end", + "bottom-start", + "bottom-end", + "right-start", + "right-end", + "left-start", + "left-end", + ], }, strategy: { - control: { - type: "radio", - options: ["fixed", "absolute"], - }, + control: { type: "radio" }, + options: ["fixed", "absolute"], }, }, }; -export const Default = { - render: (props: any) => { - return ( - - Id ullamco excepteur elit fugiat labore. - - ); - }, - - args: { - title: "show tooltip", - }, -}; - -export const Open = () => { +export const Open: StoryFn = () => { const ref = useRef(null); useEffect(() => { ref.current && ref.current.click(); }, []); return ( - + Incididunt laborum eiusmod ullamco id aliquip officia ex irure aliqua laboris id ea do nisi. Ex esse ad duis culpa non aliquip exercitation eu culpa cupidatat nisi. Deserunt voluptate consectetur cillum elit qui ad @@ -66,35 +60,31 @@ export const Open = () => { ); }; -export const WrapperClassName = { - render: () => { - return ( -
- - Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta - perspiciatis vero voluptatum, asperiores cumque, deserunt accusantium - ullam ipsa accusamus officia cupiditate quae unde esse culpa, ratione - ab quam ea quas? - +export const WrapperClassName: StoryFn = () => ( +
+ + Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta + perspiciatis vero voluptatum, asperiores cumque, deserunt accusantium + ullam ipsa accusamus officia cupiditate quae unde esse culpa, ratione ab + quam ea quas? + - - 67 år og 1 måneder øklasdjkl askdak døkasøk daøkdkølasøkld asølkdøka - - Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta - perspiciatis vero voluptatum, asperiores cumque, deserunt - accusantium ullam ipsa accusamus officia cupiditate quae unde esse - culpa, ratione ab quam ea quas? - - - + + 67 år og 1 måneder øklasdjkl askdak døkasøk daøkdkølasøkld asølkdøka + + Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta + perspiciatis vero voluptatum, asperiores cumque, deserunt accusantium + ullam ipsa accusamus officia cupiditate quae unde esse culpa, ratione ab + quam ea quas? + + + - - Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta - perspiciatis vero voluptatum, asperiores cumque, deserunt accusantium - ullam ipsa accusamus officia cupiditate quae unde esse culpa, ratione - ab quam ea quas? - -
- ); - }, -}; + + Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta + perspiciatis vero voluptatum, asperiores cumque, deserunt accusantium + ullam ipsa accusamus officia cupiditate quae unde esse culpa, ratione ab + quam ea quas? + +
+); diff --git a/@navikt/core/react/src/modal/Modal.tsx b/@navikt/core/react/src/modal/Modal.tsx index 40911ffb7b..340e2bfe6f 100644 --- a/@navikt/core/react/src/modal/Modal.tsx +++ b/@navikt/core/react/src/modal/Modal.tsx @@ -1,18 +1,13 @@ import { useFloatingPortalNode } from "@floating-ui/react"; import cl from "clsx"; -import React, { - forwardRef, - useContext, - useEffect, - useMemo, - useRef, -} from "react"; +import React, { forwardRef, useContext, useEffect, useRef } from "react"; import { createPortal } from "react-dom"; import { DateContext } from "../date/context"; import { useProvider } from "../provider"; import { Detail, Heading } from "../typography"; -import { mergeRefs, useId } from "../util"; +import { useId } from "../util"; import { composeEventHandlers } from "../util/composeEventHandlers"; +import { useMergeRefs } from "../util/hooks/useMergeRefs"; import ModalBody from "./ModalBody"; import { ModalContext } from "./ModalContext"; import ModalFooter from "./ModalFooter"; @@ -96,7 +91,8 @@ export const Modal = forwardRef( ref, ) => { const modalRef = useRef(null); - const mergedRef = useMemo(() => mergeRefs([modalRef, ref]), [ref]); + const mergedRef = useMergeRefs(modalRef, ref); + const ariaLabelId = useId(); const rootElement = useProvider()?.rootElement; const portalNode = useFloatingPortalNode({ root: rootElement }); diff --git a/@navikt/core/react/src/popover/Popover.tsx b/@navikt/core/react/src/popover/Popover.tsx index 5f18e9b67c..c90d6d80a0 100644 --- a/@navikt/core/react/src/popover/Popover.tsx +++ b/@navikt/core/react/src/popover/Popover.tsx @@ -15,12 +15,12 @@ import React, { forwardRef, useCallback, useContext, - useMemo, useRef, } from "react"; import { DateContext } from "../date/context"; import { ModalContext } from "../modal/ModalContext"; -import { mergeRefs, useClientLayoutEffect, useEventListener } from "../util"; +import { useClientLayoutEffect, useEventListener } from "../util"; +import { useMergeRefs } from "../util/hooks/useMergeRefs"; import PopoverContent, { PopoverContentType } from "./PopoverContent"; export interface PopoverProps extends HTMLAttributes { @@ -163,10 +163,7 @@ export const Popover = forwardRef( refs.setReference(anchorEl); }, [anchorEl]); - const floatingRef = useMemo( - () => mergeRefs([refs.setFloating, ref]), - [refs.setFloating, ref], - ); + const floatingRef = useMergeRefs(refs.setFloating, ref); useClientLayoutEffect(() => { if (!refs.reference.current || !refs.floating.current || !open) return; diff --git a/@navikt/core/react/src/tabs/TabList.tsx b/@navikt/core/react/src/tabs/TabList.tsx index 61140775eb..ad297ee7c8 100644 --- a/@navikt/core/react/src/tabs/TabList.tsx +++ b/@navikt/core/react/src/tabs/TabList.tsx @@ -9,7 +9,8 @@ import React, { useState, } from "react"; import { ChevronLeftIcon, ChevronRightIcon } from "@navikt/aksel-icons"; -import { debounce, mergeRefs } from "../util"; +import { debounce } from "../util"; +import { useMergeRefs } from "../util/hooks/useMergeRefs"; import { TabsContext } from "./context"; export interface TabListProps extends React.HTMLAttributes { @@ -23,7 +24,8 @@ export const TabList = forwardRef( ({ className, ...rest }, ref) => { const context = useContext(TabsContext); const listRef = useRef(null); - const mergedRef = useMemo(() => mergeRefs([listRef, ref]), [ref]); + const mergedRef = useMergeRefs(listRef, ref); + const [displayScroll, setDisplayScroll] = useState({ start: false, end: false, diff --git a/@navikt/core/react/src/tag/Tag.tsx b/@navikt/core/react/src/tag/Tag.tsx index 601e3100b5..35a1256fa6 100644 --- a/@navikt/core/react/src/tag/Tag.tsx +++ b/@navikt/core/react/src/tag/Tag.tsx @@ -36,6 +36,10 @@ export interface TagProps extends HTMLAttributes { * @default "medium" */ size?: "medium" | "small" | "xsmall"; + /** + * Tag Icon + */ + icon?: React.ReactNode; } /** @@ -50,7 +54,7 @@ export interface TagProps extends HTMLAttributes { * ``` */ export const Tag = forwardRef( - ({ className, variant, size = "medium", ...rest }, ref) => ( + ({ children, className, variant, size = "medium", icon, ...rest }, ref) => ( ( `navds-tag--${variant}`, `navds-tag--${size}`, )} - /> + > + {icon && {icon}} + {children} + ), ); diff --git a/@navikt/core/react/src/tag/tag.stories.tsx b/@navikt/core/react/src/tag/tag.stories.tsx index 18433a6ed0..3d0882e24d 100644 --- a/@navikt/core/react/src/tag/tag.stories.tsx +++ b/@navikt/core/react/src/tag/tag.stories.tsx @@ -1,6 +1,10 @@ import type { Meta } from "@storybook/react"; import React from "react"; +import { ComponentIcon } from "@navikt/aksel-icons"; import { Tag, TagProps } from "."; +import { HStack } from "../layout/stack"; + +const sizes: TagProps["size"][] = ["xsmall", "small", "medium"]; const variants: TagProps["variant"][] = [ "warning", @@ -52,7 +56,11 @@ export default { export const Default = { render: (props) => ( - + } + > {props.children} ), @@ -60,6 +68,7 @@ export const Default = { args: { children: "Id elit esse", variant: "info", + icon: false, }, }; @@ -98,3 +107,20 @@ export const Variants = () => { ); }; + +export const WithIcons = () => { + return ( + + {sizes.reverse().map((size) => ( + } + > + {size} + + ))} + + ); +}; diff --git a/@navikt/core/react/src/timeline/Pin.tsx b/@navikt/core/react/src/timeline/Pin.tsx index cfadcab997..d44c76d983 100644 --- a/@navikt/core/react/src/timeline/Pin.tsx +++ b/@navikt/core/react/src/timeline/Pin.tsx @@ -14,8 +14,8 @@ import { useRole, } from "@floating-ui/react"; import { format } from "date-fns"; -import React, { forwardRef, useMemo, useRef, useState } from "react"; -import { mergeRefs } from "../util"; +import React, { forwardRef, useRef, useState } from "react"; +import { useMergeRefs } from "../util/hooks/useMergeRefs"; import { useTimelineContext } from "./hooks/useTimelineContext"; import { position } from "./utils/calc"; import { TimelineComponentTypes } from "./utils/types.internal"; @@ -81,10 +81,7 @@ export const Pin = forwardRef( role, ]); - const mergedRef = useMemo( - () => mergeRefs([refs.setReference, ref]), - [ref, refs.setReference], - ); + const mergedRef = useMergeRefs(refs.setReference, ref); const staticSide = { top: "bottom", diff --git a/@navikt/core/react/src/timeline/period/ClickablePeriod.tsx b/@navikt/core/react/src/timeline/period/ClickablePeriod.tsx index 0bc69c9ab2..5f5e4cd66b 100644 --- a/@navikt/core/react/src/timeline/period/ClickablePeriod.tsx +++ b/@navikt/core/react/src/timeline/period/ClickablePeriod.tsx @@ -14,8 +14,8 @@ import { useRole, } from "@floating-ui/react"; import cl from "clsx"; -import React, { useMemo, useRef, useState } from "react"; -import { mergeRefs } from "../../util"; +import React, { useRef, useState } from "react"; +import { useMergeRefs } from "../../util/hooks/useMergeRefs"; import { usePeriodContext } from "../hooks/usePeriodContext"; import { useRowContext } from "../hooks/useRowContext"; import { useTimelineContext } from "../hooks/useTimelineContext"; @@ -89,10 +89,7 @@ const ClickablePeriod = React.memo( role, ]); - const mergedRef = useMemo( - () => mergeRefs([refs.setReference, periodRef]), - [periodRef, refs.setReference], - ); + const mergedRef = useMergeRefs(refs.setReference, periodRef); const staticSide = { top: "bottom", diff --git a/@navikt/core/react/src/tooltip/Tooltip.tsx b/@navikt/core/react/src/tooltip/Tooltip.tsx index 7828fc0573..830ce495b1 100644 --- a/@navikt/core/react/src/tooltip/Tooltip.tsx +++ b/@navikt/core/react/src/tooltip/Tooltip.tsx @@ -18,14 +18,14 @@ import React, { cloneElement, forwardRef, useContext, - useMemo, useRef, } from "react"; import { ModalContext } from "../modal/ModalContext"; import { useProvider } from "../provider"; import { Detail } from "../typography"; -import { mergeRefs, useId } from "../util"; +import { useId } from "../util"; import { useControllableState } from "../util/hooks/useControllableState"; +import { useMergeRefs } from "../util/hooks/useMergeRefs"; export interface TooltipProps extends HTMLAttributes { /** @@ -166,14 +166,8 @@ export const Tooltip = forwardRef( const ariaId = useId(id); - const mergedRef = useMemo( - () => mergeRefs([ref, refs.setFloating]), - [refs.setFloating, ref], - ); - const childMergedRef = useMemo( - () => mergeRefs([(children as any).ref, refs.setReference]), - [children, refs.setReference], - ); + const mergedRef = useMergeRefs(ref, refs.setFloating); + const childMergedRef = useMergeRefs(children.ref, refs.setReference); if ( !children || diff --git a/@navikt/core/react/src/util/Slot.tsx b/@navikt/core/react/src/util/Slot.tsx index afa5a9d5f9..b4863eb6c9 100644 --- a/@navikt/core/react/src/util/Slot.tsx +++ b/@navikt/core/react/src/util/Slot.tsx @@ -1,6 +1,6 @@ // https://github.com/radix-ui/primitives/blob/main/packages/react/slot/src/Slot.tsx import * as React from "react"; -import mergeRefs from "./mergeRefs"; +import { mergeRefs } from "./hooks/useMergeRefs"; interface SlotProps extends React.HTMLAttributes { children?: React.ReactNode; diff --git a/@navikt/core/react/src/util/TextareaAutoSize.tsx b/@navikt/core/react/src/util/TextareaAutoSize.tsx index 6d295a80b1..08b357ff89 100644 --- a/@navikt/core/react/src/util/TextareaAutoSize.tsx +++ b/@navikt/core/react/src/util/TextareaAutoSize.tsx @@ -1,7 +1,8 @@ /* https://github.com/mui/material-ui/blob/master/packages/mui-base/src/TextareaAutosize/TextareaAutosize.tsx */ -import React, { forwardRef, useEffect, useMemo, useRef, useState } from "react"; +import React, { forwardRef, useEffect, useRef, useState } from "react"; import ReactDOM from "react-dom"; -import { debounce, mergeRefs, useClientLayoutEffect } from "../util"; +import { debounce, useClientLayoutEffect } from "../util"; +import { useMergeRefs } from "./hooks/useMergeRefs"; type State = { outerHeightStyle: number; @@ -90,7 +91,9 @@ const TextareaAutosize = forwardRef( ) => { const { current: isControlled } = useRef(value != null); const inputRef = useRef(null); - const handleRef = useMemo(() => mergeRefs([inputRef, ref]), [ref]); + + const handleRef = useMergeRefs(inputRef, ref); + const shadowRef = useRef(null); const renders = useRef(0); const [state, setState] = useState({ outerHeightStyle: 0 }); diff --git a/@navikt/core/react/src/util/hooks/useMergeRefs.ts b/@navikt/core/react/src/util/hooks/useMergeRefs.ts new file mode 100644 index 0000000000..c8a885c7ef --- /dev/null +++ b/@navikt/core/react/src/util/hooks/useMergeRefs.ts @@ -0,0 +1,32 @@ +/* https://github.com/radix-ui/primitives/blob/main/packages/react/compose-refs/src/composeRefs.tsx */ +import React from "react"; + +type PossibleRef = React.Ref | undefined; + +// https://github.com/gregberge/react-merge-refs +/** + * Use `useMergeRefs` + * @internal + */ +export function mergeRefs(refs: PossibleRef[]): React.RefCallback { + return (value) => { + refs.forEach((ref) => { + if (typeof ref === "function") { + ref(value); + } else if (ref !== null && ref !== undefined) { + (ref as React.MutableRefObject).current = value; + } + }); + }; +} + +/** + * Merges refs within useCallback + * @internal + * @param ...refs: React.Ref | undefined + * @returns React.useCallback(mergeRefs(refs), refs) + */ +export function useMergeRefs(...refs: PossibleRef[]) { + // eslint-disable-next-line react-hooks/exhaustive-deps + return React.useCallback(mergeRefs(refs), refs); +} diff --git a/@navikt/core/react/src/util/index.ts b/@navikt/core/react/src/util/index.ts index 45f032babc..c908b0d6dc 100644 --- a/@navikt/core/react/src/util/index.ts +++ b/@navikt/core/react/src/util/index.ts @@ -1,6 +1,5 @@ export * from "./OverridableComponent"; export { default as debounce } from "./debounce"; -export { default as mergeRefs } from "./mergeRefs"; export * from "./omit"; export * from "./useClientLayoutEffect"; export * from "./useEventListener"; diff --git a/@navikt/core/react/src/util/mergeRefs.tsx b/@navikt/core/react/src/util/mergeRefs.tsx deleted file mode 100644 index 720de5da5d..0000000000 --- a/@navikt/core/react/src/util/mergeRefs.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react"; - -// https://github.com/gregberge/react-merge-refs -export default function mergeRefs( - refs: Array | React.LegacyRef>, -): React.RefCallback { - return (value) => { - refs.forEach((ref) => { - if (typeof ref === "function") { - ref(value); - } else if (ref !== null && ref !== undefined) { - (ref as React.MutableRefObject).current = value; - } - }); - }; -} diff --git a/aksel.nav.no/website/components/sanity-modules/token-tabell/parts/ShowMore.tsx b/aksel.nav.no/website/components/sanity-modules/token-tabell/parts/ShowMore.tsx index df5d9a9586..4d7cb980c4 100644 --- a/aksel.nav.no/website/components/sanity-modules/token-tabell/parts/ShowMore.tsx +++ b/aksel.nav.no/website/components/sanity-modules/token-tabell/parts/ShowMore.tsx @@ -1,7 +1,7 @@ import { ChevronDownIcon, ChevronUpIcon } from "@navikt/aksel-icons"; -import { Button, mergeRefs, useId, type HeadingProps } from "@navikt/ds-react"; +import { Button, useId, type HeadingProps } from "@navikt/ds-react"; import cl from "clsx"; -import React, { forwardRef, useMemo, useRef, useState } from "react"; +import React, { forwardRef, useRef, useState } from "react"; export interface ShowMoreProps extends Omit, "onClick"> { @@ -78,10 +78,10 @@ export const ShowMore = forwardRef( "aria-labelledby": ariaLabelledby, ...rest }, - ref, + /* ref, */ ) => { const localRef = useRef(null); - const mergedRef = useMemo(() => mergeRefs([localRef, ref]), [ref]); + /* const mergedRef = useMemo(() => mergeRefs([localRef, ref]), [ref]); */ const [isOpen, setIsOpen] = useState(false); const ariaLabelId = useId(); @@ -89,7 +89,7 @@ export const ShowMore = forwardRef( return ( { + const [checked, setChecked] = useState(false); + + return ( + setChecked(e.target.checked)}> + Varsle med SMS + + ); +}; + +// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE +export default withDsExample(Example); + +/* Storybook story */ +export const Demo = { + render: Example, +}; + +export const args = { + index: 7, +}; diff --git a/aksel.nav.no/website/pages/eksempler/switch/controlled-value.tsx b/aksel.nav.no/website/pages/eksempler/switch/controlled-value.tsx new file mode 100644 index 0000000000..da33564ea8 --- /dev/null +++ b/aksel.nav.no/website/pages/eksempler/switch/controlled-value.tsx @@ -0,0 +1,29 @@ +import { useState } from "react"; +import { Switch } from "@navikt/ds-react"; +import { withDsExample } from "@/web/examples/withDsExample"; + +const Example = () => { + const [checkedValue, setCheckedValue] = useState(""); + + return ( + setCheckedValue((x) => (x ? "" : e.target.value))} + > + Varsle med SMS + + ); +}; + +// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE +export default withDsExample(Example); + +/* Storybook story */ +export const Demo = { + render: Example, +}; + +export const args = { + index: 6, +}; diff --git a/aksel.nav.no/website/pages/eksempler/switch/loading.tsx b/aksel.nav.no/website/pages/eksempler/switch/loading.tsx index fc0407b9e7..106867ed20 100644 --- a/aksel.nav.no/website/pages/eksempler/switch/loading.tsx +++ b/aksel.nav.no/website/pages/eksempler/switch/loading.tsx @@ -14,5 +14,5 @@ export const Demo = { }; export const args = { - index: 6, + index: 8, }; diff --git a/aksel.nav.no/website/pages/eksempler/tag/ikon.tsx b/aksel.nav.no/website/pages/eksempler/tag/ikon.tsx new file mode 100644 index 0000000000..8d52d7bcd2 --- /dev/null +++ b/aksel.nav.no/website/pages/eksempler/tag/ikon.tsx @@ -0,0 +1,40 @@ +import { withDsExample } from "@/web/examples/withDsExample"; +import { ComponentIcon } from "@navikt/aksel-icons"; +import { HStack, Tag } from "@navikt/ds-react"; + +const Example = () => { + return ( + + }> + Ikon + + } + > + Ikon + + } + > + Ikon + + + ); +}; + +// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE +export default withDsExample(Example); + +/* Storybook story */ +export const Demo = { + render: Example, +}; + +export const args = { + index: 5, + desc: "Hvis ikon bare er illustrativt, husk å legge til 'aria-hidden'.", +};