Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@ import { TextareaBaseState } from '@fluentui/react-textarea';
import type { TextareaSlots as TextareaSlots_2 } from '@fluentui/react-textarea';
import type { ToggleButtonBaseProps } from '@fluentui/react-button';
import type { ToggleButtonBaseState } from '@fluentui/react-button';
import type { ToolbarBaseProps } from '@fluentui/react-toolbar';
import { ToolbarBaseState } from '@fluentui/react-toolbar';
import type { ToolbarButtonBaseProps } from '@fluentui/react-toolbar';
import type { ToolbarButtonBaseState } from '@fluentui/react-toolbar';
import { ToolbarContextValue } from '@fluentui/react-toolbar';
import { ToolbarContextValues as ToolbarContextValues_2 } from '@fluentui/react-toolbar';
import type { ToolbarDividerBaseProps } from '@fluentui/react-toolbar';
import type { ToolbarDividerBaseState } from '@fluentui/react-toolbar';
import type { ToolbarGroupProps as ToolbarGroupProps_2 } from '@fluentui/react-toolbar';
import { ToolbarGroupState as ToolbarGroupState_2 } from '@fluentui/react-toolbar';
import type { ToolbarRadioGroupProps as ToolbarRadioGroupProps_2 } from '@fluentui/react-toolbar';
import type { ToolbarRadioGroupState as ToolbarRadioGroupState_2 } from '@fluentui/react-toolbar';
import type { ToolbarSlots as ToolbarSlots_2 } from '@fluentui/react-toolbar';
import type { ToolbarToggleButtonBaseProps } from '@fluentui/react-toolbar';
import type { ToolbarToggleButtonBaseState } from '@fluentui/react-toolbar';
import { useMessageBarBodyContextValues_unstable } from '@fluentui/react-message-bar';
import { useFluent_unstable as useProviderContext } from '@fluentui/react-shared-contexts';

Expand Down Expand Up @@ -679,6 +694,24 @@ export const renderTextarea: (state: TextareaBaseState) => JSXElement;
// @public
export const renderToggleButton: (state: ButtonBaseState) => JSXElement;

// @public
export const renderToolbar: (state: ToolbarBaseState, contextValues: ToolbarContextValues_2) => JSXElement;

// @public
export const renderToolbarButton: (state: ButtonBaseState) => JSXElement;

// @public
export const renderToolbarDivider: (state: DividerBaseState) => JSXElement;

// @public
export const renderToolbarGroup: (state: ToolbarGroupState_2) => JSXElement;

// @public
export const renderToolbarRadioGroup: (state: ToolbarGroupState_2) => JSXElement;

// @public
export const renderToolbarToggleButton: (state: ButtonBaseState) => JSXElement;

// @public
export const SearchBox: ForwardRefComponent<SearchBoxProps>;

Expand Down Expand Up @@ -872,6 +905,98 @@ export type ToggleButtonState = ToggleButtonBaseState & {
};
};

// @public
export const Toolbar: ForwardRefComponent<ToolbarProps>;

// @public
export const ToolbarButton: ForwardRefComponent<ToolbarButtonProps>;

// @public (undocumented)
export type ToolbarButtonProps = ToolbarButtonBaseProps;

// @public (undocumented)
export type ToolbarButtonState = ToolbarButtonBaseState & {
root: {
'data-vertical'?: string;
'data-disabled'?: string;
'data-disabled-focusable'?: string;
'data-icon-only'?: string;
};
};

// @public (undocumented)
export type ToolbarContextValues = ToolbarContextValues_2;

// @public
export const ToolbarDivider: ForwardRefComponent<ToolbarDividerProps>;

// @public (undocumented)
export type ToolbarDividerProps = ToolbarDividerBaseProps;

// @public (undocumented)
export type ToolbarDividerState = ToolbarDividerBaseState & {
root: {
'data-vertical'?: string;
};
};

// @public
export const ToolbarGroup: ForwardRefComponent<ToolbarGroupProps>;

// @public (undocumented)
export type ToolbarGroupProps = ToolbarGroupProps_2;

// @public (undocumented)
export type ToolbarGroupState = ToolbarGroupState_2 & {
root: {
'data-vertical'?: string;
};
};

// @public (undocumented)
export type ToolbarProps = ToolbarBaseProps;

// @public
export const ToolbarRadioGroup: ForwardRefComponent<ToolbarRadioGroupProps>;

// @public (undocumented)
export type ToolbarRadioGroupProps = ToolbarRadioGroupProps_2;

// @public (undocumented)
export type ToolbarRadioGroupState = ToolbarRadioGroupState_2 & {
vertical?: boolean;
root: {
'data-vertical'?: string;
};
};

// @public (undocumented)
export type ToolbarSlots = ToolbarSlots_2;

// @public (undocumented)
export type ToolbarState = ToolbarBaseState & {
root: {
'data-vertical'?: string;
focusgroup?: string;
};
};

// @public
export const ToolbarToggleButton: ForwardRefComponent<ToolbarToggleButtonProps>;

// @public (undocumented)
export type ToolbarToggleButtonProps = ToolbarToggleButtonBaseProps;

// @public (undocumented)
export type ToolbarToggleButtonState = ToolbarToggleButtonBaseState & {
root: {
'data-disabled'?: string;
'data-disabled-focusable'?: string;
'data-icon-only'?: string;
'data-checked'?: string;
};
};

// @public
export const useAccordion: (props: AccordionProps, ref: React_2.Ref<HTMLElement>) => AccordionState;

Expand Down Expand Up @@ -1015,6 +1140,30 @@ export const useTextarea: (props: TextareaProps, ref: React_2.Ref<HTMLTextAreaEl
// @public
export const useToggleButton: (props: ToggleButtonProps, ref: React_2.Ref<HTMLButtonElement | HTMLAnchorElement>) => ToggleButtonState;

// @public
export const useToolbar: (props: ToolbarProps, ref: React_2.Ref<HTMLElement>) => ToolbarState;

// @public
export const useToolbarButton: (props: ToolbarButtonProps, ref: React_2.Ref<HTMLButtonElement | HTMLAnchorElement>) => ToolbarButtonState;

// @public
export const useToolbarContext: <T>(selector: ContextSelector<ToolbarContextValue, T>) => T;

// @public
export const useToolbarContextValues: (state: ToolbarState) => ToolbarContextValues;

// @public
export const useToolbarDivider: (props: ToolbarDividerProps, ref: React_2.Ref<HTMLElement>) => ToolbarDividerState;

// @public
export const useToolbarGroup: (props: ToolbarGroupProps, ref: React_2.Ref<HTMLDivElement>) => ToolbarGroupState;

// @public
export const useToolbarRadioGroup: (props: ToolbarRadioGroupProps, ref: React_2.Ref<HTMLDivElement>) => ToolbarRadioGroupState;

// @public
export const useToolbarToggleButton: (props: ToolbarToggleButtonProps, ref: React_2.Ref<HTMLButtonElement | HTMLAnchorElement>) => ToolbarToggleButtonState;

// (No @packageDocumentation comment for this package)

```
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@fluentui/react-tabs": "^9.11.2",
"@fluentui/react-tags": "^9.7.19",
"@fluentui/react-textarea": "^9.7.0",
"@fluentui/react-toolbar": "^9.7.7",
"@fluentui/react-utilities": "^9.26.2",
"@swc/helpers": "^0.5.1"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export { Toolbar, renderToolbar, useToolbar, useToolbarContext, useToolbarContextValues } from './components/Toolbar';
export type { ToolbarSlots, ToolbarProps, ToolbarState, ToolbarContextValues } from './components/Toolbar';

export { ToolbarButton, renderToolbarButton, useToolbarButton } from './components/Toolbar';
export type { ToolbarButtonProps, ToolbarButtonState } from './components/Toolbar';

export { ToolbarDivider, renderToolbarDivider, useToolbarDivider } from './components/Toolbar';
export type { ToolbarDividerProps, ToolbarDividerState } from './components/Toolbar';

export { ToolbarGroup, renderToolbarGroup, useToolbarGroup } from './components/Toolbar';
export type { ToolbarGroupProps, ToolbarGroupState } from './components/Toolbar';

export { ToolbarRadioGroup, renderToolbarRadioGroup, useToolbarRadioGroup } from './components/Toolbar';
export type { ToolbarRadioGroupProps, ToolbarRadioGroupState } from './components/Toolbar';

export { ToolbarToggleButton, renderToolbarToggleButton, useToolbarToggleButton } from './components/Toolbar';
export type { ToolbarToggleButtonProps, ToolbarToggleButtonState } from './components/Toolbar';
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as React from 'react';
import { render } from '@testing-library/react';
import { Toolbar } from '.';
import { ToolbarButton } from './ToolbarButton';
import { ToolbarToggleButton } from './ToolbarToggleButton';

describe('Toolbar', () => {
it('renders unchecked by default', () => {
const { getByRole, getAllByRole } = render(
<Toolbar>
<ToolbarButton name="format" value="bold">
Bold
</ToolbarButton>
<ToolbarToggleButton name="format" value="italic">
Italic
</ToolbarToggleButton>
</Toolbar>,
);

expect(getByRole('toolbar')).toHaveAttribute('focusgroup', 'toolbar inline');
expect(getByRole('toolbar')).not.toHaveAttribute('data-vertical');

expect(getAllByRole('button')).toHaveLength(2);
});

it('renders checked when value is in toolbar checkedValues', () => {
const { getByRole } = render(
<Toolbar defaultCheckedValues={{ format: ['bold'] }} vertical>
<ToolbarToggleButton name="format" value="bold">
Bold
</ToolbarToggleButton>
<ToolbarToggleButton name="format" value="italic" disabled>
Italic
</ToolbarToggleButton>
<ToolbarToggleButton name="format" value="underline" icon="U" aria-label="Underline" />
</Toolbar>,
);

expect(getByRole('toolbar')).toHaveAttribute('focusgroup', 'toolbar block');
expect(getByRole('toolbar')).toHaveAttribute('data-vertical');

const button1 = getByRole('button', { name: 'Bold' });
expect(button1).toHaveAttribute('aria-pressed', 'true');
expect(button1).toHaveAttribute('data-checked');

const button2 = getByRole('button', { name: 'Italic' });
expect(button2).toHaveAttribute('aria-pressed', 'false');
expect(button2).not.toHaveAttribute('data-checked');
expect(button2).toBeDisabled();
expect(button2).toHaveAttribute('data-disabled');

const button3 = getByRole('button', { name: 'Underline' });
expect(button3).toHaveAttribute('aria-pressed', 'false');
expect(button3).not.toHaveAttribute('data-checked');
expect(button3).not.toBeDisabled();
expect(button3).toHaveAttribute('data-icon-only');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use client';

import * as React from 'react';
import type { ForwardRefComponent } from '@fluentui/react-utilities';
import type { ToolbarProps } from './Toolbar.types';
import { useToolbar, useToolbarContextValues } from './useToolbar';
import { renderToolbar } from './renderToolbar';

/**
* A toolbar component that provides a container for grouping a set of controls such as buttons and menu items.
*/
export const Toolbar: ForwardRefComponent<ToolbarProps> = React.forwardRef((props, ref) => {
const state = useToolbar(props, ref);
const contextValues = useToolbarContextValues(state);

return renderToolbar(state, contextValues);
});

Toolbar.displayName = 'Toolbar';
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type {
ToolbarSlots as ToolbarBaseSlots,
ToolbarBaseProps,
ToolbarContextValues as ToolbarBaseContextValues,
ToolbarBaseState,
} from '@fluentui/react-toolbar';

export type ToolbarSlots = ToolbarBaseSlots;

export type ToolbarProps = ToolbarBaseProps;

export type ToolbarState = ToolbarBaseState & {
root: {
/**
* Data attribute set when the toolbar is vertically oriented.
*/
'data-vertical'?: string;

/**
* Data attribute to define the focus behavior of the toolbar's children
*/
focusgroup?: string;
};
};

export type ToolbarContextValues = ToolbarBaseContextValues;
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use client';

import * as React from 'react';
import type { ForwardRefComponent } from '@fluentui/react-utilities';
import type { ToolbarButtonProps } from './ToolbarButton.types';
import { useToolbarButton } from './useToolbarButton';
import { renderToolbarButton } from './renderToolbarButton';

/**
* A button component designed to be used inside a Toolbar, inheriting toolbar context such as size.
*/
export const ToolbarButton: ForwardRefComponent<ToolbarButtonProps> = React.forwardRef((props, ref) => {
const state = useToolbarButton(props, ref);

return renderToolbarButton(state);
// Casting is required due to lack of distributive union to support unions on @types/react
}) as ForwardRefComponent<ToolbarButtonProps>;

ToolbarButton.displayName = 'ToolbarButton';
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { ToolbarButtonBaseProps, ToolbarButtonBaseState } from '@fluentui/react-toolbar';

export type ToolbarButtonProps = ToolbarButtonBaseProps;

export type ToolbarButtonState = ToolbarButtonBaseState & {
root: {
/**
* Data attribute set when the button is in a vertically oriented toolbar.
*/
'data-vertical'?: string;

/**
* Data attribute set when the button is disabled.
*/
'data-disabled'?: string;

/**
* Data attribute set when the button is disabled but still focusable.
*/
'data-disabled-focusable'?: string;

/**
* Data attribute set when the button renders only an icon.
*/
'data-icon-only'?: string;
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { ToolbarButton } from './ToolbarButton';
export { renderToolbarButton } from './renderToolbarButton';
export { useToolbarButton } from './useToolbarButton';
export type { ToolbarButtonProps, ToolbarButtonState } from './ToolbarButton.types';
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { renderButton_unstable } from '@fluentui/react-button';

/**
* Renders the final JSX of the ToolbarButton component, given the state.
*/
export const renderToolbarButton = renderButton_unstable;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use client';

import type * as React from 'react';
import { useToolbarButtonBase_unstable } from '@fluentui/react-toolbar';

import type { ToolbarButtonProps, ToolbarButtonState } from './ToolbarButton.types';
import { stringifyDataAttribute } from '../../../utils';

/**
* Returns the state for a ToolbarButton component, given its props and ref.
* The returned state can be modified with hooks before being passed to `renderToolbarButton`.
*/
export const useToolbarButton = (
props: ToolbarButtonProps,
ref: React.Ref<HTMLButtonElement | HTMLAnchorElement>,
): ToolbarButtonState => {
'use no memo';

const state: ToolbarButtonState = useToolbarButtonBase_unstable(props, ref);

// Set data attributes for vertical, disabled, disabledFocusable, and iconOnly states to simplify styling.
state.root['data-vertical'] = stringifyDataAttribute(state.vertical);
state.root['data-disabled'] = stringifyDataAttribute(state.disabled);
state.root['data-disabled-focusable'] = stringifyDataAttribute(state.disabledFocusable);
state.root['data-icon-only'] = stringifyDataAttribute(state.iconOnly);

return state;
};
Loading
Loading