Skip to content
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/public-ducks-stay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@digdir/designsystemet-react": patch
---

**Details**: use `DetailsHTMLAttributes` type to allow `name` attribute
8 changes: 4 additions & 4 deletions packages/react/src/components/avatar-stack/avatar-stack.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import cl from 'clsx/lite';
import type { HTMLAttributes } from 'react';
import type { CSSProperties, HTMLAttributes } from 'react';
import { Children, forwardRef } from 'react';

export type AvatarStackProps = {
Expand Down Expand Up @@ -28,7 +28,7 @@ export type AvatarStackProps = {
* @default undefined
*/
expandable?: 'fixed' | true;
} & HTMLAttributes<HTMLDivElement>;
} & HTMLAttributes<HTMLElement>;

/**
* Use `AvatarStack` to constrain Avatars into a stack.
Expand All @@ -45,7 +45,7 @@ export type AvatarStackProps = {
* </EXPERIMENTAL_AvatarStack>
*/
export const EXPERIMENTAL_AvatarStack = forwardRef<
HTMLDivElement,
HTMLElement,
AvatarStackProps
>(function AvatarStack(
{
Expand All @@ -68,7 +68,7 @@ export const EXPERIMENTAL_AvatarStack = forwardRef<
overlap !== undefined ? `${overlap}` : undefined,
'--dsc-avatar-count':
expandable === 'fixed' ? Children.count(children) : undefined,
} as React.CSSProperties;
} as CSSProperties;
return (
<figure
tabIndex={
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/components/details/details.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import cl from 'clsx/lite';
import type { HTMLAttributes, ReactNode } from 'react';
import type { DetailsHTMLAttributes, ReactNode } from 'react';
import { forwardRef, useEffect, useRef } from 'react';
import { useMergeRefs } from '../../utilities/hooks';
import '@digdir/designsystemet-web'; // Load details polyfill
import type { DefaultProps } from '../../types';
import type { MergeRight } from '../../utilities';

export type DetailsProps = MergeRight<
DefaultProps & HTMLAttributes<HTMLDetailsElement>,
DefaultProps & DetailsHTMLAttributes<HTMLDetailsElement>,
{
/**
* Change the background color of the details.
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/components/dialog/dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Slot } from '@radix-ui/react-slot';
import cl from 'clsx/lite';
import type { DialogHTMLAttributes } from 'react';
import type { AnimationEvent, DialogHTMLAttributes } from 'react';
import { forwardRef, useContext, useEffect, useId, useRef } from 'react';
import type { DefaultProps } from '../../types';
import type { MergeRight } from '../../utilities';
Expand Down Expand Up @@ -128,7 +128,7 @@ export const Dialog = forwardRef<HTMLDialogElement, DialogProps>(
);
}
}}
onAnimationEnd={(event: React.AnimationEvent<HTMLDialogElement>) => {
onAnimationEnd={(event: AnimationEvent<HTMLDialogElement>) => {
const { currentTarget: dialog } = event;
const autofocus = dialog.querySelector<HTMLElement>('[autofocus]');
if (document.activeElement !== autofocus) autofocus?.focus(); // Handle autofocus on open
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Slot } from '@radix-ui/react-slot';
import cl from 'clsx/lite';
import type { HTMLAttributes } from 'react';
import type { HTMLAttributes, ReactNode } from 'react';
import { forwardRef } from 'react';
import type { DefaultProps } from '../../types';

export type ErrorSummaryProps = {
/**
* @deprecated This is not supported anymore, as the element needs to be `ds-error-summary`
*/
asChild?: React.ReactNode;
asChild?: ReactNode;
} & Omit<HTMLAttributes<HTMLDivElement> & DefaultProps, 'data-color'>;

/**
Expand Down
9 changes: 7 additions & 2 deletions packages/react/src/components/popover/popover-trigger.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { Slot } from '@radix-ui/react-slot';
import { forwardRef, type HTMLAttributes, useContext, version } from 'react';
import {
type ButtonHTMLAttributes,
forwardRef,
useContext,
version,
} from 'react';
import type { DefaultProps } from '../../types';
import { Button, type ButtonProps } from '../button/button';
import { Context } from './popover-trigger-context';
Expand All @@ -16,7 +21,7 @@ export type PopoverTriggerProps =
* @default false
*/
asChild?: boolean;
} & HTMLAttributes<HTMLButtonElement> &
} & ButtonHTMLAttributes<HTMLButtonElement> &
DefaultProps)
| ({
/**
Expand Down
6 changes: 2 additions & 4 deletions packages/react/src/components/search/search-clear.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { forwardRef } from 'react';
import { forwardRef, type MouseEvent } from 'react';
import { Button, type ButtonProps } from '../button/button';
import { setReactInputValue } from '../Combobox/utilities';

Expand All @@ -22,9 +22,7 @@ export type SearchClearProps = Omit<ButtonProps, 'variant' | 'children'> & {
*/
export const SearchClear = forwardRef<HTMLButtonElement, SearchClearProps>(
function SearchClear({ 'aria-label': label = 'Tøm', onClick, ...rest }, ref) {
const handleClear = (
e: React.MouseEvent<HTMLButtonElement, MouseEvent>,
) => {
const handleClear = (e: MouseEvent<HTMLButtonElement>) => {
const target = e.target;
let input: HTMLElement | null | undefined = null;

Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/components/search/search-input.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { forwardRef } from 'react';
import { forwardRef, type InputHTMLAttributes } from 'react';
import type { DefaultProps } from '../../types';
import { Input } from '../input/input';

export type SearchInputProps = DefaultProps &
Omit<React.InputHTMLAttributes<HTMLInputElement>, 'readOnly' | 'type'>;
Omit<InputHTMLAttributes<HTMLInputElement>, 'readOnly' | 'type'>;

/**
* SearchInput component, used to display a search input within the Search component.
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/components/search/search.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import cl from 'clsx/lite';
import { forwardRef } from 'react';
import { forwardRef, type HTMLAttributes } from 'react';

import type { DefaultProps } from '../../types';

export type SearchProps = DefaultProps & React.HTMLAttributes<HTMLDivElement>;
export type SearchProps = DefaultProps & HTMLAttributes<HTMLDivElement>;

/**
* Search component, use to display different variations of a search input
Expand Down
3 changes: 2 additions & 1 deletion packages/react/src/components/suggestion/suggestion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
forwardRef,
type HTMLAttributes,
type ReactNode,
type RefObject,
useCallback,
useEffect,
useId,
Expand Down Expand Up @@ -52,7 +53,7 @@ type Filter = (args: {
type SuggestionContextType = {
handleFilter: (input?: HTMLInputElement | null) => void;
isEmpty?: boolean;
dsSuggestionRef?: React.RefObject<DSSuggestionElement | null>;
dsSuggestionRef?: RefObject<DSSuggestionElement | null>;
};

type SuggestionValue<T extends { multiple: boolean }> =
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/components/tabs/tabs-tab.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { DSTabElement } from '@digdir/designsystemet-web';
import type { HTMLAttributes } from 'react';
import type { HTMLAttributes, MouseEvent } from 'react';
import '@digdir/designsystemet-web'; // Import ds-tab custom element
import { forwardRef, useContext } from 'react';
import { Context } from './tabs';
Expand Down Expand Up @@ -30,7 +30,7 @@ export const TabsTab = forwardRef<DSTabElement, TabsTabProps>(function TabsTab(
data-value={value}
ref={ref}
suppressHydrationWarning // Since <ds-tablist> adds attributes
onClick={(e: React.MouseEvent<DSTabElement>) => {
onClick={(e: MouseEvent<DSTabElement>) => {
if (e.isTrusted) onChange?.(value); // Only call onChange is user actually clicked, not when programmatically clicked/controlled
onClick?.(e);
}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import type { ChangeEvent, ReactNode } from 'react';
import type {
ChangeEvent,
Dispatch,
ForwardedRef,
ReactNode,
SetStateAction,
} from 'react';
import { useEffect, useId, useRef, useState } from 'react';
import type { CheckboxProps } from '../../../components';

Expand Down Expand Up @@ -59,7 +65,7 @@ export type GetCheckboxProps = Omit<
> & {
/** Enables indeterminate handling for this `Checkbox` and `CheckboxGroup` */
allowIndeterminate?: boolean;
ref?: React.ForwardedRef<HTMLInputElement>; // Use this to match Ref from `Checkbox`, remove when `Checkbox` no longer uses `forwardRef`
ref?: ForwardedRef<HTMLInputElement>; // Use this to match Ref from `Checkbox`, remove when `Checkbox` no longer uses `forwardRef`
checked?: boolean;
value?: string;
};
Expand All @@ -80,7 +86,7 @@ const toggleIndeterminate = (

type useCheckboxGroupReturn = {
value: string[];
setValue: React.Dispatch<React.SetStateAction<string[]>>;
setValue: Dispatch<SetStateAction<string[]>>;
getCheckboxProps: (
propsOrValue?: string | GetCheckboxProps,
) => GetCheckboxProps;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import type { ReactNode } from 'react';
import type {
ChangeEvent,
Dispatch,
ForwardedRef,
ReactNode,
SetStateAction,
} from 'react';
import { useId, useState } from 'react';
import type { RadioProps } from '../../../components';

Expand Down Expand Up @@ -40,13 +46,13 @@ export type GetRadioProps = Omit<
| 'checked'
| 'value'
> & {
ref?: React.ForwardedRef<HTMLInputElement>; // Use this to match Ref from `Radio`, remove when `Radio` no longer uses `forwardRef`
ref?: ForwardedRef<HTMLInputElement>; // Use this to match Ref from `Radio`, remove when `Radio` no longer uses `forwardRef`
value?: string;
};

type useRadioGroupReturn = {
value: string;
setValue: React.Dispatch<React.SetStateAction<string>>;
setValue: Dispatch<SetStateAction<string>>;
getRadioProps: (propsOrValue: string | GetRadioProps) => GetRadioProps;
validationMessageProps: {
children: ReactNode;
Expand Down Expand Up @@ -122,7 +128,7 @@ export function useRadioGroup({
}
};

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
if (e.target.name === radioGroupName) {
setGroupValue((prevValue) => {
onChange?.(e.target.value, prevValue);
Expand All @@ -143,7 +149,7 @@ export function useRadioGroup({
required: required || rest.required,
readOnly: readOnly || rest.readOnly,
disabled: disabled || rest.disabled,
onChange: (e: React.ChangeEvent<HTMLInputElement>) => {
onChange: (e: ChangeEvent<HTMLInputElement>) => {
rest.onChange?.(e);
if (e.defaultPrevented) return;
handleChange(e);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Logic from: https://www.joshuawootonn.com/react-roving-tabindex
// Inspired by: https://github.com/radix-ui/primitives/tree/main/packages/react/roving-focus/src

import type { HTMLAttributes } from 'react';
import type { FocusEvent, HTMLAttributes, KeyboardEvent } from 'react';
import { useContext } from 'react';

import { RovingFocusContext } from './roving-focus-root';
Expand Down Expand Up @@ -32,14 +32,14 @@ export const useRovingFocus = (value: string) => {
elements.current.delete(value);
}
},
onKeyDown: (e: React.KeyboardEvent<T>) => {
onKeyDown: (e: KeyboardEvent<T>) => {
props?.onKeyDown?.(e);
if (e.shiftKey && e.key === 'Tab') {
onShiftTab();
return;
}
},
onFocus: (e: React.FocusEvent<T>) => {
onFocus: (e: FocusEvent<T>) => {
props?.onFocus?.(e);
setFocusableValue(value);
},
Expand Down
Loading