Skip to content

Commit

Permalink
Add toolbar link
Browse files Browse the repository at this point in the history
  • Loading branch information
mj12albert committed Jan 27, 2025
1 parent 9c3111f commit 1f51d47
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 2 deletions.
2 changes: 1 addition & 1 deletion docs/src/app/(private)/experiments/toolbar.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
border: 1px solid var(--color-gray-200);
border-radius: 0.375rem;
background-color: var(--color-gray-50);
padding: 0.125rem;
padding: 0.125rem 0.5rem;
text-wrap: nowrap;
}

Expand Down
3 changes: 3 additions & 0 deletions docs/src/app/(private)/experiments/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ export default function App() {
>
A regular button
</Toolbar.Button>
<Toolbar.Link className={s.Button} href="https://base-ui.com">
Visit base-ui.com
</Toolbar.Link>
<Select.Root defaultValue="sans">
<Toolbar.Button
disabled={DISABLED}
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/toolbar/index.parts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { Separator } from '../separator/Separator';
export { ToolbarRoot as Root } from './root/ToolbarRoot';
export { ToolbarGroup as Group } from './group/ToolbarGroup';
export { ToolbarButton as Button } from './button/ToolbarButton';
export { ToolbarLink as Link } from './link/ToolbarLink';
50 changes: 50 additions & 0 deletions packages/react/src/toolbar/link/ToolbarLink.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import * as React from 'react';
import { expect } from 'chai';
// import { spy } from 'sinon';
// import { act } from '@mui/internal-test-utils';
import { Toolbar } from '@base-ui-components/react/toolbar';
import { screen } from '@mui/internal-test-utils';
import { createRenderer, describeConformance } from '#test-utils';
import { NOOP } from '../../utils/noop';
import { ToolbarRootContext } from '../root/ToolbarRootContext';
import { CompositeRootContext } from '../../composite/root/CompositeRootContext';

const testCompositeContext = {
highlightedIndex: 0,
onHighlightedIndexChange: NOOP,
};

const testToolbarContext: ToolbarRootContext = {
disabled: false,
orientation: 'horizontal',
setItemMap: NOOP,
};

describe('<Toolbar.Link />', () => {
const { render } = createRenderer();

describeConformance(<Toolbar.Link />, () => ({
refInstanceof: window.HTMLAnchorElement,
render: (node) => {
return render(
<ToolbarRootContext.Provider value={testToolbarContext}>
<CompositeRootContext.Provider value={testCompositeContext}>
{node}
</CompositeRootContext.Provider>
</ToolbarRootContext.Provider>,
);
},
}));

describe('ARIA attributes', () => {
it('renders an anchor', async () => {
const { getByTestId } = await render(
<Toolbar.Root>
<Toolbar.Link data-testid="link" />
</Toolbar.Root>,
);

expect(getByTestId('button')).to.equal(screen.getByRole('button'));
});
});
});
49 changes: 49 additions & 0 deletions packages/react/src/toolbar/link/ToolbarLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use client';
import * as React from 'react';
import { useComponentRenderer } from '../../utils/useComponentRenderer';
import { BaseUIComponentProps } from '../../utils/types';
import { useButton } from '../../use-button';
import { CompositeItem } from '../../composite/item/CompositeItem';
import type { ToolbarOrientation } from '../root/ToolbarRoot';
import { useToolbarRootContext } from '../root/ToolbarRootContext';

const ToolbarLink = React.forwardRef(function ToolbarLink(
props: ToolbarLink.Props,
forwardedRef: React.ForwardedRef<HTMLAnchorElement>,
) {
const { className, render, ...otherProps } = props;

const { orientation } = useToolbarRootContext();

const { getButtonProps } = useButton({
buttonRef: forwardedRef,
elementName: 'a',
});

const state: ToolbarLink.State = React.useMemo(
() => ({
orientation,
}),
[orientation],
);

const { renderElement } = useComponentRenderer({
propGetter: getButtonProps,
render: render ?? 'a',
state,
className,
extraProps: otherProps,
});

return <CompositeItem render={renderElement()} />;
});

export namespace ToolbarLink {
export interface State {
orientation: ToolbarOrientation;
}

export interface Props extends BaseUIComponentProps<'a', State> {}
}

export { ToolbarLink };
4 changes: 3 additions & 1 deletion packages/react/src/use-button/useButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ export function useButton(parameters: useButton.Parameters = {}): useButton.Retu
additionalProps.disabled = disabled;
}
} else if (elementName !== '') {
additionalProps.role = 'button';
if (elementName !== 'A') {
additionalProps.role = 'button';
}
additionalProps.tabIndex = tabIndex ?? 0;
if (disabled) {
additionalProps['aria-disabled'] = disabled as boolean;
Expand Down

0 comments on commit 1f51d47

Please sign in to comment.