Skip to content

Commit

Permalink
Allow Composite to override tabIndex in useButton
Browse files Browse the repository at this point in the history
  • Loading branch information
mj12albert committed Feb 3, 2025
1 parent f263515 commit 61dc192
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 27 deletions.
19 changes: 0 additions & 19 deletions docs/src/app/(private)/experiments/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,25 +189,6 @@ export default function App() {
</Menu.Root>
</Toolbar.Root>
<textarea name="" id="" />
<MySeparator />
<a href="#two-column">two-column toolbar</a>
<Toolbar.Root className={classNames(s.Root, s.Grid)} cols={2}>
<Toolbar.Button disabled={DISABLED} className={s.Button}>
<MoveIcon className={s.Icon} />
</Toolbar.Button>

<Toolbar.Button disabled={DISABLED} className={s.Button}>
<MarqueeIcon className={s.Icon} />
</Toolbar.Button>

<Toolbar.Button disabled={DISABLED} className={s.Button}>
<LassoIcon className={s.Icon} />
</Toolbar.Button>

<Toolbar.Button disabled={DISABLED} className={s.Button}>
<CropIcon className={s.Icon} />
</Toolbar.Button>
</Toolbar.Root>
</React.Fragment>
);
}
Expand Down
6 changes: 4 additions & 2 deletions packages/react/src/composite/root/CompositeRootContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ if (process.env.NODE_ENV !== 'production') {
CompositeRootContext.displayName = 'CompositeRootContext';
}

export function useCompositeRootContext() {
export function useCompositeRootContext(optional: true): CompositeRootContext | undefined;
export function useCompositeRootContext(optional?: false): CompositeRootContext;
export function useCompositeRootContext(optional = false) {
const context = React.useContext(CompositeRootContext);
if (context === undefined) {
if (context === undefined && !optional) {
throw new Error(
'Base UI: CompositeRootContext is missing. Composite parts must be placed within <Composite.Root>.',
);
Expand Down
19 changes: 13 additions & 6 deletions packages/react/src/use-button/useButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { mergeReactProps } from '../utils/mergeReactProps';
import { useEventCallback } from '../utils/useEventCallback';
import { useRootElementName } from '../utils/useRootElementName';
import { GenericHTMLProps } from '../utils/types';
import { useCompositeRootContext } from '../composite/root/CompositeRootContext';

export function useButton(parameters: useButton.Parameters = {}): useButton.ReturnValue {
const {
Expand All @@ -22,6 +23,8 @@ export function useButton(parameters: useButton.Parameters = {}): useButton.Retu
rootElementName: elementNameProp,
});

const isCompositeItem = useCompositeRootContext(true) !== undefined;

const isNativeButton = useEventCallback(() => {
const element = buttonRef.current;

Expand All @@ -43,7 +46,7 @@ export function useButton(parameters: useButton.Parameters = {}): useButton.Retu
const buttonProps = React.useMemo(() => {
const additionalProps: AdditionalButtonProps = {};

if (tabIndex !== undefined) {
if (tabIndex !== undefined && !isCompositeItem) {
additionalProps.tabIndex = tabIndex;
}

Expand All @@ -56,18 +59,22 @@ export function useButton(parameters: useButton.Parameters = {}): useButton.Retu
} else if (elementName !== '') {
if (elementName !== 'A') {
additionalProps.role = 'button';
additionalProps.tabIndex = tabIndex ?? 0;
} else if (tabIndex) {
if (!isCompositeItem) {
additionalProps.tabIndex = tabIndex ?? 0;
}
} else if (tabIndex && !isCompositeItem) {
additionalProps.tabIndex = tabIndex;
}
if (disabled) {
additionalProps['aria-disabled'] = disabled as boolean;
additionalProps.tabIndex = focusableWhenDisabled ? (tabIndex ?? 0) : -1;
if (!isCompositeItem) {
additionalProps.tabIndex = focusableWhenDisabled ? (tabIndex ?? 0) : -1;
}
}
}

return additionalProps;
}, [disabled, elementName, focusableWhenDisabled, tabIndex]);
}, [disabled, elementName, focusableWhenDisabled, isCompositeItem, tabIndex]);

const getButtonProps = React.useCallback(
(externalProps: GenericButtonProps = {}): GenericButtonProps => {
Expand Down Expand Up @@ -133,7 +140,7 @@ interface AdditionalButtonProps
'aria-disabled': React.AriaAttributes['aria-disabled'];
disabled: boolean;
role: React.AriaRole;
tabIndex: number;
tabIndex?: number;
}> {}

export namespace useButton {
Expand Down

0 comments on commit 61dc192

Please sign in to comment.