diff --git a/skills/carbon-react/components/button-handle-next.md b/skills/carbon-react/components/button-handle-next.md deleted file mode 100644 index 2d7ff6be0e..0000000000 --- a/skills/carbon-react/components/button-handle-next.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: carbon-component-button-handle-next -description: Carbon ButtonHandleNext component props and usage examples. ---- - -# ButtonHandleNext - -## Import -`import ButtonHandle from "carbon-react/lib/components/button/__next__";` - -## Source -- Export: `./components/button/__next__` -- Props interface: not found - -## Props -No props metadata found. - -## Examples -No Storybook examples found. \ No newline at end of file diff --git a/skills/carbon-react/components/button.md b/skills/carbon-react/components/button.md index 765db77627..bd65b8f564 100644 --- a/skills/carbon-react/components/button.md +++ b/skills/carbon-react/components/button.md @@ -355,7 +355,7 @@ description: Carbon Button component props and usage examples. ```tsx () => { - const buttonRef = useRef(null); + const buttonRef = useRef(null); return ( @@ -364,7 +364,7 @@ description: Carbon Button component props and usage examples. diff --git a/skills/carbon-react/components/dialog.md b/skills/carbon-react/components/dialog.md index b4e23a5ab4..608493283e 100644 --- a/skills/carbon-react/components/dialog.md +++ b/skills/carbon-react/components/dialog.md @@ -171,9 +171,9 @@ description: Carbon Dialog component props and usage examples. height="150px" > - setIsOpenOne(false)}> + {}} /> @@ -334,7 +334,7 @@ function WithScrollableContentExample(args) { ```tsx function DefaultRender({ onCancel, ...args }: DialogProps) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -347,7 +347,7 @@ function DefaultRender({ onCancel, ...args }: DialogProps) { onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} footer={} > @@ -376,7 +376,7 @@ function DefaultRender({ onCancel, ...args }: DialogProps) { ```tsx function DefaultWithFormRender({ onCancel, ...args }: DialogProps) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -389,7 +389,7 @@ function DefaultWithFormRender({ onCancel, ...args }: DialogProps) { onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} >
{ const [isOpen, setIsOpen] = useState(defaultOpenState); - const buttonRef = useRef(null); + const buttonRef = useRef(null); return ( <> @@ -568,7 +568,7 @@ function DefaultWithFormRender({ onCancel, ...args }: DialogProps) { open={isOpen} onCancel={() => { setIsOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} title="Title" subtitle="Subtitle" @@ -602,7 +602,7 @@ function ResponsiveBehaviorRender({ onCancel, ...args }: Partial) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -619,7 +619,7 @@ function ResponsiveBehaviorRender({ onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} > ) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -687,7 +687,7 @@ function SmallScreenBehaviorRender({ onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} footer={} > @@ -734,7 +734,7 @@ function StickyFooterRender({ onCancel, ...args }: Partial) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -747,7 +747,7 @@ function StickyFooterRender({ onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} footer={} > @@ -795,7 +795,7 @@ function StickyFooterWithFormRender({ onCancel, ...args }: Partial) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -808,7 +808,7 @@ function StickyFooterWithFormRender({ onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} > ) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); const [submitted, setSubmitted] = useState(false); @@ -875,7 +875,7 @@ function FormLinkedToFooterButtonsRender({ ev.preventDefault(); setSubmitted(true); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }; return ( @@ -892,7 +892,7 @@ function FormLinkedToFooterButtonsRender({ onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} footer={ @@ -954,7 +954,7 @@ function WithHeaderChildrenRender({ onCancel, ...args }: Partial) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -967,7 +967,7 @@ function WithHeaderChildrenRender({ onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} headerChildren={ diff --git a/skills/carbon-react/index.md b/skills/carbon-react/index.md index 780056f425..6c2b189a6d 100644 --- a/skills/carbon-react/index.md +++ b/skills/carbon-react/index.md @@ -21,7 +21,6 @@ - [Breadcrumbs](components/breadcrumbs.md) - [Button](components/button.md) (deprecated) - [ButtonBar](components/button-bar.md) (deprecated) -- [ButtonHandleNext](components/button-handle-next.md) - [ButtonMinor](components/button-minor.md) (deprecated) - [ButtonNext](components/button-next.md) - [ButtonToggle](components/button-toggle.md) diff --git a/src/__internal__/focus-trap/focus-trap.component.tsx b/src/__internal__/focus-trap/focus-trap.component.tsx index b95244fd46..fa064dd092 100644 --- a/src/__internal__/focus-trap/focus-trap.component.tsx +++ b/src/__internal__/focus-trap/focus-trap.component.tsx @@ -153,29 +153,34 @@ const FocusTrap = ({ useEffect(() => { if (shouldSetFocus && !prevShouldSetFocus) { - const candidateFirstElement = - focusFirstElement && "current" in focusFirstElement - ? focusFirstElement.current - : focusFirstElement; const autoFocusedElement = getFocusableElements( defaultFocusableSelectors, ).find((el) => el.getAttribute("data-has-autofocus") === "true"); - const elementToFocus = - (candidateFirstElement as HTMLElement) || - autoFocusedElement || - wrapperRef.current; + const elementToFocus = autoFocusedElement || wrapperRef.current; // istanbul ignore else if (elementToFocus) { setElementFocus(elementToFocus); } } - }, [ - shouldSetFocus, - prevShouldSetFocus, - getFocusableElements, - focusFirstElement, - wrapperRef, - ]); + }, [shouldSetFocus, prevShouldSetFocus, getFocusableElements, wrapperRef]); + + useEffect(() => { + if (!shouldSetFocus || prevShouldSetFocus) return; + + const candidateFirstElement = + focusFirstElement && "current" in focusFirstElement + ? focusFirstElement.current + : focusFirstElement; + + if ( + !candidateFirstElement || + candidateFirstElement.hasAttribute("disabled") + ) { + return; + } + + setElementFocus(candidateFirstElement); + }, [shouldSetFocus, prevShouldSetFocus, focusFirstElement]); useEffect(() => { const trapFn = (ev: KeyboardEvent) => { diff --git a/src/__internal__/popover-menu/popover-menu.component.tsx b/src/__internal__/popover-menu/popover-menu.component.tsx index 39bb5af0ac..883d7c68f2 100644 --- a/src/__internal__/popover-menu/popover-menu.component.tsx +++ b/src/__internal__/popover-menu/popover-menu.component.tsx @@ -4,7 +4,6 @@ import Popover from "../popover"; import { flip, offset, size } from "@floating-ui/dom"; import wrapChildrenInMenuItems from "./utils"; import useClickAwayListener from "../../hooks/__internal__/useClickAwayListener"; -import { ButtonHandle } from "../../components/button/__next__"; import { useHandleDropdownMenuKeyDown } from "./hooks"; import guid from "../utils/helpers/guid"; import { PopoverMenuContext, type PopoverMenuContextProps } from "./contexts"; @@ -61,22 +60,10 @@ interface PopoverControlProps { "aria-activedescendant"?: string; } -type FocusableHandle = - | NonNullable - | HTMLElement - | HTMLButtonElement - | HTMLAnchorElement - | HTMLInputElement; +type FocusableHandle = HTMLElement; -function isFocusButtonHandle( - handle: FocusableHandle, -): handle is NonNullable { - return "focusButton" in handle; -} - -export interface PopoverMenuProps< - TRef extends FocusableHandle = NonNullable, -> extends TagProps { +export interface PopoverMenuProps + extends TagProps { /** The content of the popover menu */ children: React.ReactNode; /** Whether the popover menu is open or not */ @@ -134,19 +121,10 @@ const menuPopoverMiddleware = (width?: string) => [ ]; const focusControl = (handle: FocusableHandle | null) => { - /* istanbul ignore if */ - if (!handle) { - return; - } - - if (isFocusButtonHandle(handle)) { - handle.focusButton(); - } else { - handle.focus(); - } + handle?.focus(); }; -const PopoverMenu = >({ +const PopoverMenu = ({ children, open, popoverControl, diff --git a/src/__internal__/popover-menu/popover-menu.test.tsx b/src/__internal__/popover-menu/popover-menu.test.tsx index 81fcab3ba5..530127001e 100644 --- a/src/__internal__/popover-menu/popover-menu.test.tsx +++ b/src/__internal__/popover-menu/popover-menu.test.tsx @@ -332,7 +332,7 @@ test("calls onClose when Escape is pressed while open and control is a Button", const user = userEvent.setup(); const onClose = jest.fn(); render( - open onOpen={() => {}} onClose={onClose} diff --git a/src/components/button/__next__/button.component.tsx b/src/components/button/__next__/button.component.tsx index 7cc0aecc09..6c6072e522 100644 --- a/src/components/button/__next__/button.component.tsx +++ b/src/components/button/__next__/button.component.tsx @@ -1,9 +1,4 @@ -import React, { - forwardRef, - ReactNode, - useRef, - useImperativeHandle, -} from "react"; +import React, { forwardRef, ReactNode } from "react"; import { SpaceProps } from "styled-system"; import { ButtonProps as LegacyButtonProps } from "../button.component"; @@ -16,10 +11,7 @@ import { Size, Variant, VariantType } from "./button.config"; import isIconOnly from "./__internal__/utils/is-icon-only"; import Icon from "../../icon"; -export type ButtonHandle = { - /** Programmatically focus the button. */ - focusButton: () => void; -} | null; +type ButtonRef = HTMLButtonElement | HTMLAnchorElement; export interface ButtonProps extends Omit< @@ -149,7 +141,7 @@ const mapButtonTypeToVariantType = ({ } }; -export const Button = forwardRef( +export const Button = forwardRef( ( { "aria-describedby": ariaDescribedBy, @@ -178,21 +170,10 @@ export const Button = forwardRef( }: ButtonProps, ref, ) => { - const buttonRef = useRef(null); const hasChildren = children !== undefined && children !== false; const iconOnly = (!!iconType && !hasChildren) || isIconOnly(children); - useImperativeHandle( - ref, - () => ({ - focusButton: () => { - buttonRef.current?.focus(); - }, - }), - [], - ); - const allowMotion = useMediaQuery( "screen and (prefers-reduced-motion: no-preference)", ); @@ -210,11 +191,19 @@ export const Button = forwardRef( | React.MouseEvent | React.MouseEvent, ) => { - buttonRef.current?.focus({ preventScroll: true }); + event.currentTarget.focus({ preventScroll: true }); onClick?.(event); }; + const setForwardedRef = (node: ButtonRef | null) => { + if (typeof ref === "function") { + ref(node); + } else if (ref) { + ref.current = node; + } + }; + const renderChildren = () => { if (!iconType) { return children; @@ -279,7 +268,7 @@ export const Button = forwardRef( name={name} $noWrap={noWrap} onClick={handleClick} - ref={buttonRef} + ref={setForwardedRef} $size={size} $variant={computedVariant} $variantType={computedVariantType} diff --git a/src/components/button/__next__/button.mdx b/src/components/button/__next__/button.mdx index 542d8f597b..7d7a1b05fe 100644 --- a/src/components/button/__next__/button.mdx +++ b/src/components/button/__next__/button.mdx @@ -30,7 +30,7 @@ Use it to submit a form (Save), to advance to the next step in a process (Next), ## Quick Start ```javascript -import Button, { type ButtonProps, type ButtonHandle } from "carbon-react/lib/components/button/__next__"; +import Button, { type ButtonProps } from "carbon-react/lib/components/button/__next__"; ``` ## Examples @@ -154,7 +154,7 @@ determine the behaviour of the link. ### Programmatic focus -To programmatically set focus on a `Button`, you can use the imperative `focusButton` method available via the component's ref: +To programmatically set focus on a `Button`, use a ref to the underlying DOM element and call `focus()`: @@ -177,10 +177,9 @@ To help with migration, this component can also accept the following -## Ref methods +## Ref +`Button`'s forwarded ref resolves to the underlying DOM element: -`Button`'s forwarded ref exposes the following imperative methods: - -| Method Name | Description | -| ------------- | ----------------------------------- | -| `focusButton` | Programmatically focuses the button. | \ No newline at end of file +| Ref type | Description | +| -------- | ---------------------------------------------------------- | +| DOM ref | `HTMLButtonElement` (or `HTMLAnchorElement` when `href` is set). | \ No newline at end of file diff --git a/src/components/button/__next__/button.stories.tsx b/src/components/button/__next__/button.stories.tsx index a335c14b0c..1edb872428 100644 --- a/src/components/button/__next__/button.stories.tsx +++ b/src/components/button/__next__/button.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryObj } from "@storybook/react-vite"; import React, { useRef, useState } from "react"; -import Button, { ButtonHandle, ButtonProps } from "./button.component"; +import Button, { ButtonProps } from "./button.component"; import Box from "../../box"; import Icon from "../../icon"; import { Loader } from "../../loader/__next__/loader.component"; @@ -231,7 +231,7 @@ export const ButtonAsALink: Story = () => { ButtonAsALink.storyName = "As a Link"; export const ProgrammaticFocus: Story = () => { - const buttonRef = useRef(null); + const buttonRef = useRef(null); return ( @@ -240,7 +240,7 @@ export const ProgrammaticFocus: Story = () => { diff --git a/src/components/button/__next__/button.test.tsx b/src/components/button/__next__/button.test.tsx index 0266d0f9e6..88e76bb07b 100644 --- a/src/components/button/__next__/button.test.tsx +++ b/src/components/button/__next__/button.test.tsx @@ -1,7 +1,7 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import React from "react"; -import Button, { ButtonHandle } from "./button.component"; +import Button from "./button.component"; import Box from "../../box"; import { Loader } from "../../loader/__next__/loader.component"; @@ -278,15 +278,15 @@ test("passes the form prop to the underlying button element", () => { expect(screen.getByRole("button")).toHaveAttribute("form", "my-form"); }); -test("calling exposed focusButton method focuses chosen button", async () => { +test("forwards ref to the underlying element and supports programmatic focus", async () => { const user = userEvent.setup(); const MockComponent = () => { - const buttonHandle = React.useRef(null); + const buttonRef = React.useRef(null); return ( <> - - + @@ -307,6 +307,26 @@ test("calling exposed focusButton method focuses chosen button", async () => { expect(targetButton).toHaveFocus(); }); +test("forwards the underlying button element to a callback ref", () => { + const callbackRef = jest.fn(); + + render(); + + expect(callbackRef).toHaveBeenCalledWith(expect.any(HTMLButtonElement)); +}); + +test("forwards the underlying anchor element to a callback ref when href is set", () => { + const callbackRef = jest.fn(); + + render( + , + ); + + expect(callbackRef).toHaveBeenCalledWith(expect.any(HTMLAnchorElement)); +}); + test("renders correctly with noWrap set", () => { render(); const button = screen.getByRole("button"); diff --git a/src/components/button/__next__/index.ts b/src/components/button/__next__/index.ts index 7d14139e8b..92ca17bf27 100644 --- a/src/components/button/__next__/index.ts +++ b/src/components/button/__next__/index.ts @@ -1,3 +1,2 @@ export { default } from "./button.component"; export type { ButtonProps } from "./button.component"; -export type { ButtonHandle } from "./button.component"; diff --git a/src/components/decimal/__internal__/decimal-popover-button.component.tsx b/src/components/decimal/__internal__/decimal-popover-button.component.tsx index 677c8fbfcf..be8df2466b 100644 --- a/src/components/decimal/__internal__/decimal-popover-button.component.tsx +++ b/src/components/decimal/__internal__/decimal-popover-button.component.tsx @@ -1,11 +1,8 @@ -import React, { forwardRef, useImperativeHandle, useRef } from "react"; +import React, { forwardRef } from "react"; import { ButtonProps } from "../../button/__next__"; import { RenderOpenProps } from "../../popover-container"; -import { - StyledDecimalPopoverButton, - StyledDecimalPopoverButtonWrapper, -} from "./decimal-popover-button.style"; +import StyledDecimalPopoverButton from "./decimal-popover-button.style"; type DecimalPopoverButtonProps = Pick< RenderOpenProps, @@ -35,31 +32,19 @@ const DecimalPopoverButton = forwardRef< }, ref, ) => { - const wrapperRef = useRef(null); - - // PopoverContainer compares openButtonRef.current with document.activeElement - // and uses indexOf() against the DOM's focusable elements list. It therefore - // needs the ref to point at the real - setIsOpenOne(false)}> + {}} /> @@ -334,7 +332,7 @@ export const DefaultStory: Story = { size: "medium", }, render: function DefaultRender({ onCancel, ...args }: DialogProps) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -347,7 +345,7 @@ export const DefaultStory: Story = { onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} footer={} > @@ -367,7 +365,7 @@ export const DefaultWithForm: Story = { size: "medium", }, render: function DefaultWithFormRender({ onCancel, ...args }: DialogProps) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -380,7 +378,7 @@ export const DefaultWithForm: Story = { onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} > { const [isOpen, setIsOpen] = useState(defaultOpenState); - const buttonRef = useRef(null); + const buttonRef = useRef(null); return ( <> @@ -536,7 +534,7 @@ export const FullScreenSize: Story = () => { open={isOpen} onCancel={() => { setIsOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} title="Title" subtitle="Subtitle" @@ -562,7 +560,7 @@ export const ResponsiveBehavior: Story = { onCancel, ...args }: Partial) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -579,7 +577,7 @@ export const ResponsiveBehavior: Story = { onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} > ) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -648,7 +646,7 @@ export const SmallScreenBehavior: Story = { onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} footer={} > @@ -694,7 +692,7 @@ export const StickyFooter: Story = { onCancel, ...args }: Partial) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -707,7 +705,7 @@ export const StickyFooter: Story = { onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} footer={} > @@ -746,7 +744,7 @@ export const StickyFooterWithForm: Story = { onCancel, ...args }: Partial) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -759,7 +757,7 @@ export const StickyFooterWithForm: Story = { onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} > ) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); const [submitted, setSubmitted] = useState(false); @@ -817,7 +815,7 @@ export const FormLinkedToFooterButtons: Story = { ev.preventDefault(); setSubmitted(true); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }; return ( @@ -834,7 +832,7 @@ export const FormLinkedToFooterButtons: Story = { onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} footer={ @@ -887,7 +885,7 @@ export const WithHeaderChildren: Story = { onCancel, ...args }: Partial) { - const buttonRef = useRef(null); + const buttonRef = useRef(null); const [open, setOpen] = useState(args.open || false); return ( <> @@ -900,7 +898,7 @@ export const WithHeaderChildren: Story = { onCancel={(ev) => { onCancel?.(ev); setOpen(false); - setTimeout(() => buttonRef.current?.focusButton(), 0); + setTimeout(() => buttonRef.current?.focus(), 0); }} headerChildren={ diff --git a/src/components/form/form.component.tsx b/src/components/form/form.component.tsx index 3d000c67ba..1718939841 100644 --- a/src/components/form/form.component.tsx +++ b/src/components/form/form.component.tsx @@ -88,22 +88,22 @@ export const Form = ({ ref={formRef} id={id} className={stickyFooter ? "sticky" : ""} - stickyFooter={stickyFooter} + $stickyFooter={stickyFooter} onSubmit={onSubmit} data-component="form" noValidate={noValidate} - height={height} - isInModal={isInModal} + $height={height} + $isInModal={isInModal} {...rest} {...tagComponent("form", rest)} > {children} @@ -112,11 +112,11 @@ export const Form = ({ data-element="form-footer" data-role="form-footer" ref={formFooterRef} - hasFooterChildren={!!footerChildren} - stickyFooter={stickyFooter} - {...(stickyFooter && { stickyFooterVariant })} - buttonAlignment={buttonAlignment} - fullWidthButtons={fullWidthButtons} + $hasFooterChildren={!!footerChildren} + $stickyFooter={stickyFooter} + {...(stickyFooter && { $stickyFooterVariant: stickyFooterVariant })} + $buttonAlignment={buttonAlignment} + $fullWidthButtons={fullWidthButtons} {...footerPadding} > {footerChildren || ( @@ -124,7 +124,7 @@ export const Form = ({ {leftSideButtons && ( {leftSideButtons} @@ -141,7 +141,7 @@ export const Form = ({ {rightSideButtons && ( {rightSideButtons} diff --git a/src/components/form/form.style.ts b/src/components/form/form.style.ts index b2ad3d47ec..5381001825 100644 --- a/src/components/form/form.style.ts +++ b/src/components/form/form.style.ts @@ -10,27 +10,27 @@ import { StyledSelectMultiSelect } from "../select/multi-select/multi-select.sty import { StyledSwitch } from "../switch/switch.style"; interface StyledFormContentProps { - stickyFooter?: boolean; - isInModal?: boolean; - fieldSpacing?: string; + $stickyFooter?: boolean; + $isInModal?: boolean; + $fieldSpacing?: string; } export const StyledFormContent = styled.div` height: 100%; - ${({ stickyFooter, isInModal }) => - stickyFooter && - isInModal && + ${({ $stickyFooter, $isInModal }) => + $stickyFooter && + $isInModal && css` flex-grow: 1; min-height: 0; overflow-y: auto; `} - ${({ fieldSpacing }) => - fieldSpacing && + ${({ $fieldSpacing }) => + $fieldSpacing && css` - --fieldSpacing: ${fieldSpacing}; + --fieldSpacing: ${$fieldSpacing}; ${StyledFormField} { margin-top: var(--spacing000); @@ -47,18 +47,18 @@ export const StyledFormContent = styled.div` `; interface StyledFormFooterProps { - hasFooterChildren?: boolean; - stickyFooter?: boolean; - stickyFooterVariant?: "light" | "grey"; - fullWidthButtons?: boolean; - buttonAlignment?: FormButtonAlignment; + $hasFooterChildren?: boolean; + $stickyFooter?: boolean; + $stickyFooterVariant?: "light" | "grey"; + $fullWidthButtons?: boolean; + $buttonAlignment?: FormButtonAlignment; } export const StyledFormFooter = styled.div.attrs( applyBaseTheme, )` - ${({ hasFooterChildren }) => - !hasFooterChildren && + ${({ $hasFooterChildren }) => + !$hasFooterChildren && css` align-items: center; display: flex; @@ -66,26 +66,26 @@ export const StyledFormFooter = styled.div.attrs( gap: var(--sizing200); `} - ${({ buttonAlignment }) => - buttonAlignment === "right" && + ${({ $buttonAlignment }) => + $buttonAlignment === "right" && css` justify-content: flex-end; `} - ${({ stickyFooter, stickyFooterVariant, fullWidthButtons }) => css` - ${!stickyFooter && + ${({ $stickyFooter, $stickyFooterVariant, $fullWidthButtons }) => css` + ${!$stickyFooter && css` margin-top: 48px; `} - ${stickyFooter && + ${$stickyFooter && css` - background-color: ${stickyFooterVariant === "light" + background-color: ${$stickyFooterVariant === "light" ? "var(--colorsUtilityYang100)" : "var(--colorsUtilityMajor025)"}; box-shadow: var(--boxShadow150); box-sizing: border-box; - ${stickyFooterVariant === "grey" && + ${$stickyFooterVariant === "grey" && "border-top: 1px solid var(--colorsUtilityMajor050);"} padding: 16px 32px; width: 100%; @@ -94,7 +94,7 @@ export const StyledFormFooter = styled.div.attrs( bottom: 0; `} - ${fullWidthButtons && + ${$fullWidthButtons && css` flex-direction: column; align-items: stretch; @@ -105,26 +105,26 @@ export const StyledFormFooter = styled.div.attrs( `; interface StyledFormProps extends StyledFormContentProps { - height?: string; + $height?: string; } export const StyledForm = styled.form.attrs(applyBaseTheme)` ${space} - ${({ height }) => - height && + ${({ $height }) => + $height && css` - height: ${height}; + height: ${$height}; `} - ${({ stickyFooter, isInModal }) => - stickyFooter && + ${({ $stickyFooter, $isInModal }) => + $stickyFooter && css` display: flex; flex-direction: column; position: relative; - ${isInModal && + ${$isInModal && css` flex-grow: 1; min-height: 0; @@ -134,20 +134,20 @@ export const StyledForm = styled.form.attrs(applyBaseTheme)` `; export const StyledRightButtons = styled.div<{ - buttonAlignment?: FormButtonAlignment; + $buttonAlignment?: FormButtonAlignment; }>` display: flex; gap: var(--sizing200); - ${({ buttonAlignment }) => buttonAlignment === "left" && "flex-grow: 1;"} + ${({ $buttonAlignment }) => $buttonAlignment === "left" && "flex-grow: 1;"} `; export const StyledLeftButtons = styled.div<{ - buttonAlignment?: FormButtonAlignment; + $buttonAlignment?: FormButtonAlignment; }>` display: flex; justify-content: flex-end; gap: var(--sizing200); - ${({ buttonAlignment }) => buttonAlignment === "right" && "flex-grow: 1;"} + ${({ $buttonAlignment }) => $buttonAlignment === "right" && "flex-grow: 1;"} `; diff --git a/src/components/pager/__internal__/pagination-navigation.component.tsx b/src/components/pager/__internal__/pagination-navigation.component.tsx index 5927cc80bf..9900afbbfc 100644 --- a/src/components/pager/__internal__/pagination-navigation.component.tsx +++ b/src/components/pager/__internal__/pagination-navigation.component.tsx @@ -11,11 +11,13 @@ import { } from "./pagination-navigation.style"; import Textbox from "../../textbox"; -import Button, { ButtonHandle } from "../../button/__next__"; +import Button from "../../button/__next__"; import Icon from "../../icon"; import Typography from "../../typography"; import guid from "../../../__internal__/utils/helpers/guid"; +type PaginationButtonRef = HTMLButtonElement | HTMLAnchorElement; + /** * Renders navigation Buttons and current page input */ @@ -81,8 +83,8 @@ const PaginationNavigation = ({ const [currentPageInputValue, setCurrentPageInputValue] = useState< string | number >(currentPage); - const previousRef = useRef(null); - const nextRef = useRef(null); + const previousRef = useRef(null); + const nextRef = useRef(null); const { current: currentPageDescriptionId } = useRef(guid()); const showFirst = currentPage > 1 && showFirstAndLastButtons; @@ -101,10 +103,10 @@ const PaginationNavigation = ({ switch (buttonFocusRef.current) { case "next": - nextRef.current?.focusButton(); + nextRef.current?.focus(); break; case "previous": - previousRef.current?.focusButton(); + previousRef.current?.focus(); break; } diff --git a/src/components/search/search.component.tsx b/src/components/search/search.component.tsx index 62cae0c036..e08810201c 100644 --- a/src/components/search/search.component.tsx +++ b/src/components/search/search.component.tsx @@ -9,7 +9,7 @@ import invariant from "invariant"; import { MarginProps } from "styled-system"; import tagComponent, { TagProps } from "../../__internal__/utils/helpers/tags"; import { CommonTextboxProps } from "../textbox"; -import Button, { type ButtonHandle } from "../button/__next__"; +import Button from "../button/__next__"; import { ValidationProps } from "../../__internal__/validations"; import useLocale from "../../hooks/__internal__/useLocale"; import Divider from "../divider"; @@ -132,7 +132,7 @@ export const Search = React.forwardRef( ) => { const locale = useLocale(); const inputRef = useRef(null); - const buttonRef = useRef(null); + const buttonRef = useRef(null); const legacyRef = useRef(null); // in order to support backwards compatibility with the Search component when used within a Menu, @@ -153,7 +153,7 @@ export const Search = React.forwardRef( inputRef.current?.focus(); }, focusButton() { - buttonRef.current?.focusButton(); + buttonRef.current?.focus(); }, }), [inMenu],