diff --git a/change/@fluentui-react-toolbar-87c0c30d-e652-4dd1-8f2c-27bb19adcbe5.json b/change/@fluentui-react-toolbar-87c0c30d-e652-4dd1-8f2c-27bb19adcbe5.json new file mode 100644 index 0000000000000..1b44a287f59cd --- /dev/null +++ b/change/@fluentui-react-toolbar-87c0c30d-e652-4dd1-8f2c-27bb19adcbe5.json @@ -0,0 +1,7 @@ +{ + "type": "none", + "comment": "feat: replace ToolbarRadio implementation by usage of toggle button as radio", + "packageName": "@fluentui/react-toolbar", + "email": "chassunc@microsoft.com", + "dependentChangeType": "none" +} diff --git a/packages/react-components/react-toolbar/etc/react-toolbar.api.md b/packages/react-components/react-toolbar/etc/react-toolbar.api.md index 51c3017aa5dce..327a369fd9d79 100644 --- a/packages/react-components/react-toolbar/etc/react-toolbar.api.md +++ b/packages/react-components/react-toolbar/etc/react-toolbar.api.md @@ -14,24 +14,12 @@ import type { ComponentState } from '@fluentui/react-utilities'; import { DividerSlots } from '@fluentui/react-divider'; import { DividerState } from '@fluentui/react-divider'; import type { ForwardRefComponent } from '@fluentui/react-utilities'; -import { RadioGroupProps } from '@fluentui/react-radio'; -import { RadioGroupState } from '@fluentui/react-radio'; -import { RadioProps } from '@fluentui/react-radio'; -import { RadioState } from '@fluentui/react-radio'; import * as React_2 from 'react'; import type { Slot } from '@fluentui/react-utilities'; import { SlotClassNames } from '@fluentui/react-utilities'; import { ToggleButtonProps } from '@fluentui/react-button'; import { ToggleButtonState } from '@fluentui/react-button'; -// @public (undocumented) -export type RadioGroupContextValue = Pick; - -// @public (undocumented) -export type RadioGroupContextValues = { - radioGroup: RadioGroupContextValue; -}; - // @public export const renderToolbar_unstable: (state: ToolbarState, contextValues: ToolbarContextValues) => JSX.Element; @@ -55,6 +43,7 @@ export const toolbarClassNames: SlotClassNames; // @public (undocumented) export type ToolbarContextValue = Pick & { handleToggleButton?: ToggableHandler; + handleRadio?: ToggableHandler; }; // @public (undocumented) @@ -83,26 +72,17 @@ export type ToolbarProps = ComponentProps & { }; // @public -export const ToolbarRadio: ForwardRefComponent; - -// @public -export const ToolbarRadioGroup: ForwardRefComponent; - -// @public -export type ToolbarRadioGroupProps = RadioGroupProps; +export const ToolbarRadioButton: ForwardRefComponent; // @public -export type ToolbarRadioGroupState = RadioGroupState; - -// @public -export type ToolbarRadioProps = RadioProps & { - size?: 'small' | 'medium'; +export type ToolbarRadioButtonProps = ComponentProps & Partial> & { + appearance?: 'primary' | 'subtle'; + name: string; + value: string; }; // @public -export type ToolbarRadioState = RadioState & { - size?: 'small' | 'medium'; -}; +export type ToolbarRadioButtonState = ComponentState> & ToggleButtonState & Required> & Pick; // @public (undocumented) export type ToolbarSlots = { @@ -112,6 +92,7 @@ export type ToolbarSlots = { // @public export type ToolbarState = ComponentState & Required> & Pick & { handleToggleButton: ToggableHandler; + handleRadio: ToggableHandler; }; // @public diff --git a/packages/react-components/react-toolbar/package.json b/packages/react-components/react-toolbar/package.json index c98929c5b8dee..77ed6b8ebe60f 100644 --- a/packages/react-components/react-toolbar/package.json +++ b/packages/react-components/react-toolbar/package.json @@ -38,6 +38,7 @@ "@fluentui/react-theme": "^9.1.1", "@fluentui/react-utilities": "^9.1.2", "@fluentui/react-context-selector": "^9.0.5", + "@fluentui/react-hooks": "^8.6.12", "@fluentui/react-radio": "^9.0.9", "@fluentui/react-tabster": "^9.2.0", "@griffel/react": "^1.4.1", diff --git a/packages/react-components/react-toolbar/src/ToolbarRadio.ts b/packages/react-components/react-toolbar/src/ToolbarRadio.ts deleted file mode 100644 index 8195a1bb6c3ed..0000000000000 --- a/packages/react-components/react-toolbar/src/ToolbarRadio.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './components/ToolbarRadio/index'; diff --git a/packages/react-components/react-toolbar/src/ToolbarRadioButton.ts b/packages/react-components/react-toolbar/src/ToolbarRadioButton.ts new file mode 100644 index 0000000000000..2f5842a8c450c --- /dev/null +++ b/packages/react-components/react-toolbar/src/ToolbarRadioButton.ts @@ -0,0 +1 @@ +export * from './components/ToolbarRadioButton/index'; diff --git a/packages/react-components/react-toolbar/src/ToolbarRadioGroup.ts b/packages/react-components/react-toolbar/src/ToolbarRadioGroup.ts deleted file mode 100644 index f88bc1454546d..0000000000000 --- a/packages/react-components/react-toolbar/src/ToolbarRadioGroup.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './components/ToolbarRadioGroup/index'; diff --git a/packages/react-components/react-toolbar/src/components/Toolbar/Toolbar.types.ts b/packages/react-components/react-toolbar/src/components/Toolbar/Toolbar.types.ts index b5bc5288aa4ea..6f022ae8b7f4c 100644 --- a/packages/react-components/react-toolbar/src/components/Toolbar/Toolbar.types.ts +++ b/packages/react-components/react-toolbar/src/components/Toolbar/Toolbar.types.ts @@ -60,22 +60,27 @@ export type ToolbarState = ComponentState & * Toggles the state of a ToggleButton item */ handleToggleButton: ToggableHandler; + /* + * Toggles the state of a ToggleButton item + */ + handleRadio: ToggableHandler; }; export type ToolbarContextValue = Pick & { handleToggleButton?: ToggableHandler; + handleRadio?: ToggableHandler; }; export type ToolbarContextValues = { toolbar: ToolbarContextValue; }; -export type UninitializedToolbarState = Omit & +export type UninitializedToolbarState = Omit & Partial>; export type ToggableHandler = ( e: React.MouseEvent | React.KeyboardEvent, - name?: string, - value?: string, + name: string, + value: string, checked?: boolean, ) => void; diff --git a/packages/react-components/react-toolbar/src/components/Toolbar/ToolbarContext.ts b/packages/react-components/react-toolbar/src/components/Toolbar/ToolbarContext.ts index 5201fd334bde1..59e68867353bc 100644 --- a/packages/react-components/react-toolbar/src/components/Toolbar/ToolbarContext.ts +++ b/packages/react-components/react-toolbar/src/components/Toolbar/ToolbarContext.ts @@ -7,6 +7,7 @@ export const ToolbarContext = createContext(und const toolbarContextDefaultValue: ToolbarContextValue = { size: 'medium' as 'medium', handleToggleButton: () => null, + handleRadio: () => null, vertical: false, checkedValues: {}, }; diff --git a/packages/react-components/react-toolbar/src/components/Toolbar/useToolbar.ts b/packages/react-components/react-toolbar/src/components/Toolbar/useToolbar.ts index 7bff9a5d37fb8..abddbac54afcc 100644 --- a/packages/react-components/react-toolbar/src/components/Toolbar/useToolbar.ts +++ b/packages/react-components/react-toolbar/src/components/Toolbar/useToolbar.ts @@ -48,7 +48,7 @@ export const useToolbar_unstable = (props: ToolbarProps, ref: React.Ref { + (e: React.MouseEvent | React.KeyboardEvent, name: string, value: string, checked?: boolean) => { if (name && value) { const checkedItems = checkedValues?.[name] || []; const newCheckedItems = [...checkedItems]; @@ -64,9 +64,22 @@ export const useToolbar_unstable = (props: ToolbarProps, ref: React.Ref { + if (name && value) { + onCheckedValueChange?.(e, { + name, + checkedItems: checkedValues?.[name], + }); + setCheckedValues(s => ({ ...s, [name]: [value] })); + } + }, + ); + return { ...initialState, handleToggleButton, + handleRadio, checkedValues: checkedValues ?? {}, }; }; diff --git a/packages/react-components/react-toolbar/src/components/Toolbar/useToolbarContextValues.tsx b/packages/react-components/react-toolbar/src/components/Toolbar/useToolbarContextValues.tsx index c31cefe2d8dee..7426e78e1af82 100644 --- a/packages/react-components/react-toolbar/src/components/Toolbar/useToolbarContextValues.tsx +++ b/packages/react-components/react-toolbar/src/components/Toolbar/useToolbarContextValues.tsx @@ -1,12 +1,13 @@ import type { ToolbarContextValue, ToolbarContextValues, ToolbarState } from './Toolbar.types'; export function useToolbarContextValues_unstable(state: ToolbarState): ToolbarContextValues { - const { size, handleToggleButton, vertical, checkedValues } = state; + const { size, handleToggleButton, vertical, checkedValues, handleRadio } = state; // This context is created with "@fluentui/react-context-selector", these is no sense to memoize it const toolbar: ToolbarContextValue = { size, vertical, handleToggleButton, + handleRadio, checkedValues, }; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadio/ToolbarRadio.test.tsx b/packages/react-components/react-toolbar/src/components/ToolbarRadio/ToolbarRadio.test.tsx deleted file mode 100644 index efeb576802f2a..0000000000000 --- a/packages/react-components/react-toolbar/src/components/ToolbarRadio/ToolbarRadio.test.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import * as React from 'react'; -import { render } from '@testing-library/react'; -import { ToolbarRadio } from './ToolbarRadio'; -import { isConformant } from '../../common/isConformant'; - -describe('ToolbarRadio', () => { - isConformant({ - Component: ToolbarRadio, - displayName: 'ToolbarRadio', - primarySlot: 'input', - disabledTests: ['component-has-static-classnames-object'], - }); - - // TODO add more tests here, and create visual regression tests in /apps/vr-tests - - it('renders a default state', () => { - const result = render(); - expect(result.container).toMatchSnapshot(); - }); -}); diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadio/ToolbarRadio.tsx b/packages/react-components/react-toolbar/src/components/ToolbarRadio/ToolbarRadio.tsx deleted file mode 100644 index b19a7d7a5894e..0000000000000 --- a/packages/react-components/react-toolbar/src/components/ToolbarRadio/ToolbarRadio.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import * as React from 'react'; -import type { ToolbarRadioProps } from './ToolbarRadio.types'; -import type { ForwardRefComponent } from '@fluentui/react-utilities'; -import { useRadio_unstable, renderRadio_unstable } from '@fluentui/react-radio'; -import { useToolbarRadioStyles_unstable } from './useToolbarRadioStyles'; -import { useToolbarContext_unstable } from '../Toolbar/ToolbarContext'; - -/** - * ToolbarRadio component is a Radio to be used inside Toolbar - */ -export const ToolbarRadio: ForwardRefComponent = React.forwardRef((props, ref) => { - const size = useToolbarContext_unstable(ctx => ctx.size); - const state = useRadio_unstable(props, ref); - useToolbarRadioStyles_unstable({ size, ...state }); - return renderRadio_unstable(state); -}) as ForwardRefComponent; - -ToolbarRadio.displayName = 'ToolbarRadio'; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadio/ToolbarRadio.types.ts b/packages/react-components/react-toolbar/src/components/ToolbarRadio/ToolbarRadio.types.ts deleted file mode 100644 index 323d5d6fcc0fd..0000000000000 --- a/packages/react-components/react-toolbar/src/components/ToolbarRadio/ToolbarRadio.types.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { RadioState, RadioProps } from '@fluentui/react-radio'; - -/** - * ToolbarRadio Props - */ -export type ToolbarRadioProps = RadioProps & { - size?: 'small' | 'medium'; -}; - -/** - * State used in rendering ToolbarRadio - */ -export type ToolbarRadioState = RadioState & { - size?: 'small' | 'medium'; -}; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadio/__snapshots__/ToolbarRadio.test.tsx.snap b/packages/react-components/react-toolbar/src/components/ToolbarRadio/__snapshots__/ToolbarRadio.test.tsx.snap deleted file mode 100644 index 8738b701c6762..0000000000000 --- a/packages/react-components/react-toolbar/src/components/ToolbarRadio/__snapshots__/ToolbarRadio.test.tsx.snap +++ /dev/null @@ -1,34 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ToolbarRadio renders a default state 1`] = ` -
- - - - -
-`; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadio/index.ts b/packages/react-components/react-toolbar/src/components/ToolbarRadio/index.ts deleted file mode 100644 index 261669c8e5b5f..0000000000000 --- a/packages/react-components/react-toolbar/src/components/ToolbarRadio/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './ToolbarRadio'; -export * from './ToolbarRadio.types'; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadio/useToolbarRadioStyles.ts b/packages/react-components/react-toolbar/src/components/ToolbarRadio/useToolbarRadioStyles.ts deleted file mode 100644 index 963bab584036f..0000000000000 --- a/packages/react-components/react-toolbar/src/components/ToolbarRadio/useToolbarRadioStyles.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; -import { useRadioStyles_unstable } from '@fluentui/react-radio'; -import { ToolbarRadioState } from './ToolbarRadio.types'; - -const useBaseStyles = makeStyles({ - root: { - ...shorthands.padding('0px'), - }, -}); - -const useSmallStyles = makeStyles({ - label: { - fontSize: 'var(--fontSizeBase200)', - }, - root: { - columnGap: '8px', - }, -}); - -/** - * Apply styling to the ToolbarRadio slots based on the state - */ -export const useToolbarRadioStyles_unstable = (state: ToolbarRadioState) => { - useRadioStyles_unstable(state); - const baseToolbarRadioStyles = useBaseStyles(); - const toolbarRadioSmallStyles = useSmallStyles(); - if (state.label) { - state.label.className = mergeClasses( - state.label.className, - state.size === 'small' && toolbarRadioSmallStyles.label, - ); - } - state.root.className = mergeClasses( - state.root.className, - baseToolbarRadioStyles.root, - state.size === 'small' && toolbarRadioSmallStyles.root, - ); -}; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/ToolbarRadioButton.test.tsx b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/ToolbarRadioButton.test.tsx new file mode 100644 index 0000000000000..2d8d20a585023 --- /dev/null +++ b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/ToolbarRadioButton.test.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; +import { ToolbarRadioButton } from './ToolbarRadioButton'; +import { isConformant } from '../../common/isConformant'; +import { ToggleButtonProps } from '@fluentui/react-button'; + +describe('ToolbarRadioButton', () => { + isConformant({ + Component: ToolbarRadioButton as React.FunctionComponent, + displayName: 'ToolbarRadioButton', + disabledTests: ['component-has-static-classnames-object'], + }); + + // TODO add more tests here, and create visual regression tests in /apps/vr-tests + + it('renders a default state', () => { + const result = render( + + Default ToolbarRadio + , + ); + expect(result.container).toMatchSnapshot(); + }); +}); diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/ToolbarRadioButton.tsx b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/ToolbarRadioButton.tsx new file mode 100644 index 0000000000000..92b1ee2952f82 --- /dev/null +++ b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/ToolbarRadioButton.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import type { ToolbarRadioButtonProps } from './ToolbarRadioButton.types'; +import type { ForwardRefComponent } from '@fluentui/react-utilities'; +import { renderToggleButton_unstable } from '@fluentui/react-button'; +import { useToolbarRadioButton_unstable } from './useToolbarRadioButton'; +import { useToolbarRadioButtonStyles_unstable } from './useToolbarRadioButtonStyles'; + +/** + * ToolbarRadioButton component + */ +export const ToolbarRadioButton: ForwardRefComponent = React.forwardRef((props, ref) => { + const state = useToolbarRadioButton_unstable(props, ref); + + useToolbarRadioButtonStyles_unstable(state); + return renderToggleButton_unstable(state); +}) as ForwardRefComponent; + +ToolbarRadioButton.displayName = 'ToolbarRadioButton'; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/ToolbarRadioButton.types.ts b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/ToolbarRadioButton.types.ts new file mode 100644 index 0000000000000..a9e86e9b6e805 --- /dev/null +++ b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/ToolbarRadioButton.types.ts @@ -0,0 +1,20 @@ +import type { ComponentProps, ComponentState } from '@fluentui/react-utilities'; +import { ToggleButtonProps, ButtonSlots, ToggleButtonState } from '@fluentui/react-button'; + +/** + * ToolbarRadioButton Props + */ +export type ToolbarRadioButtonProps = ComponentProps & + Partial> & { + appearance?: 'primary' | 'subtle'; + name: string; + value: string; + }; + +/** + * State used in rendering ToolbarRadioButton + */ +export type ToolbarRadioButtonState = ComponentState> & + ToggleButtonState & + Required> & + Pick; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/__snapshots__/ToolbarRadioButton.test.tsx.snap b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/__snapshots__/ToolbarRadioButton.test.tsx.snap new file mode 100644 index 0000000000000..84fb76d27bc4b --- /dev/null +++ b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/__snapshots__/ToolbarRadioButton.test.tsx.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ToolbarRadioButton renders a default state 1`] = ` +
+ +
+`; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/index.ts b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/index.ts new file mode 100644 index 0000000000000..85b739021a57c --- /dev/null +++ b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/index.ts @@ -0,0 +1,2 @@ +export * from './ToolbarRadioButton'; +export * from './ToolbarRadioButton.types'; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/useToolbarRadioButton.ts b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/useToolbarRadioButton.ts new file mode 100644 index 0000000000000..f907b74bb6c98 --- /dev/null +++ b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/useToolbarRadioButton.ts @@ -0,0 +1,42 @@ +import * as React from 'react'; +import { useEventCallback } from '@fluentui/react-hooks'; +import { useToggleButton_unstable } from '@fluentui/react-button'; +import { useToolbarContext_unstable } from '../Toolbar/ToolbarContext'; +import { ToolbarRadioButtonProps, ToolbarRadioButtonState } from './ToolbarRadioButton.types'; + +/** + * Given user props, defines default props for the RadioButton, calls useButtonState and useChecked, and returns + * processed state. + * @param props - User provided props to the RadioButton component. + * @param ref - User provided ref to be passed to the RadioButton component. + */ +export const useToolbarRadioButton_unstable = ( + props: ToolbarRadioButtonProps, + ref: React.Ref, +): ToolbarRadioButtonState => { + const handleRadio = useToolbarContext_unstable(ctx => ctx.handleRadio); + const checked = useToolbarContext_unstable(ctx => !!ctx.checkedValues[props.name]?.includes(props.value)); + const size = useToolbarContext_unstable(ctx => ctx.size); + + const { onClick: onClickOriginal } = props; + const toggleButtonState = useToggleButton_unstable({ size, checked, ...props }, ref); + const state: ToolbarRadioButtonState = { + ...toggleButtonState, + name: props.name, + value: props.value, + }; + + const handleOnClick = useEventCallback( + (e: React.MouseEvent & React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + return; + + handleRadio?.(e, state.name, state.value, state.checked); + onClickOriginal?.(e); + }, + ); + + state.root.onClick = handleOnClick; + return state; +}; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/useToolbarRadioButtonStyles.ts b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/useToolbarRadioButtonStyles.ts new file mode 100644 index 0000000000000..915158bab51b0 --- /dev/null +++ b/packages/react-components/react-toolbar/src/components/ToolbarRadioButton/useToolbarRadioButtonStyles.ts @@ -0,0 +1,20 @@ +import { tokens } from '@fluentui/react-theme'; +import { makeStyles, mergeClasses } from '@griffel/react'; +import { useToggleButtonStyles_unstable } from '@fluentui/react-button'; +import { ToolbarRadioButtonState } from './ToolbarRadioButton.types'; + +const useBaseStyles = makeStyles({ + selected: { + color: tokens.colorBrandForeground1, + }, +}); + +/** + * Apply styling to the ToolbarRadioButton slots based on the state + */ +export const useToolbarRadioButtonStyles_unstable = (state: ToolbarRadioButtonState) => { + useToggleButtonStyles_unstable(state); + const toggleButtonStyles = useBaseStyles(); + + state.root.className = mergeClasses(state.root.className, state.checked && toggleButtonStyles.selected); +}; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/ToolbarRadioGroup.test.tsx b/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/ToolbarRadioGroup.test.tsx deleted file mode 100644 index 12a76373dc900..0000000000000 --- a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/ToolbarRadioGroup.test.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import * as React from 'react'; -import { render } from '@testing-library/react'; -import { ToolbarRadioGroup } from './ToolbarRadioGroup'; -import { isConformant } from '../../common/isConformant'; - -describe('ToolbarRadioGroup', () => { - isConformant({ - Component: ToolbarRadioGroup, - displayName: 'ToolbarRadioGroup', - disabledTests: ['component-has-static-classnames-object'], - }); - - // TODO add more tests here, and create visual regression tests in /apps/vr-tests - - it('renders a default state', () => { - const result = render(Default ToolbarRadioGroup); - expect(result.container).toMatchSnapshot(); - }); -}); diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/ToolbarRadioGroup.tsx b/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/ToolbarRadioGroup.tsx deleted file mode 100644 index 8af8d9bb52f8a..0000000000000 --- a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/ToolbarRadioGroup.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import * as React from 'react'; -import type { ToolbarRadioGroupProps } from './ToolbarRadioGroup.types'; -import type { ForwardRefComponent } from '@fluentui/react-utilities'; -import { useRadioGroup_unstable, renderRadioGroup_unstable } from '@fluentui/react-radio'; -import { useToolbarRadioGroupStyles_unstable } from './useToolbarRadioGroupStyles'; -import { useRadioGroupContextValues } from './contexts/useRadioGroupContextValues'; - -/** - * ToolbarRadioGroup component is a RadioGroup to be used inside Toolbar - * which will keep always horizontal layout - */ -export const ToolbarRadioGroup: ForwardRefComponent = React.forwardRef((props, ref) => { - const state = useRadioGroup_unstable({ layout: 'horizontal', ...props }, ref); - const contextValues = useRadioGroupContextValues(state); - useToolbarRadioGroupStyles_unstable(state); - return renderRadioGroup_unstable(state, contextValues); -}); - -ToolbarRadioGroup.displayName = 'ToolbarRadioGroup'; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/ToolbarRadioGroup.types.ts b/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/ToolbarRadioGroup.types.ts deleted file mode 100644 index ea37a6e8af080..0000000000000 --- a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/ToolbarRadioGroup.types.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { RadioGroupProps, RadioGroupState } from '@fluentui/react-radio'; - -/** - * ToolbarRadioGroup Props - */ -export type ToolbarRadioGroupProps = RadioGroupProps; - -/** - * State used in rendering ToolbarRadioGroup - */ -export type ToolbarRadioGroupState = RadioGroupState; - -export type RadioGroupContextValue = Pick< - RadioGroupProps, - 'name' | 'value' | 'defaultValue' | 'disabled' | 'layout' | 'required' ->; - -export type RadioGroupContextValues = { - radioGroup: RadioGroupContextValue; -}; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/__snapshots__/ToolbarRadioGroup.test.tsx.snap b/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/__snapshots__/ToolbarRadioGroup.test.tsx.snap deleted file mode 100644 index 8155e6e59b06c..0000000000000 --- a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/__snapshots__/ToolbarRadioGroup.test.tsx.snap +++ /dev/null @@ -1,12 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ToolbarRadioGroup renders a default state 1`] = ` -
-
- Default ToolbarRadioGroup -
-
-`; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/contexts/useRadioGroupContextValues.ts b/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/contexts/useRadioGroupContextValues.ts deleted file mode 100644 index f8bb4cb451032..0000000000000 --- a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/contexts/useRadioGroupContextValues.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { - RadioGroupContextValue, - RadioGroupContextValues, - ToolbarRadioGroupState, -} from '../ToolbarRadioGroup.types'; - -export const useRadioGroupContextValues = (state: ToolbarRadioGroupState): RadioGroupContextValues => { - const { name, value, defaultValue, disabled, layout, required } = state; - - const radioGroup: RadioGroupContextValue = { - name, - value, - defaultValue, - disabled, - layout, - required, - }; - - return { radioGroup }; -}; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/index.ts b/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/index.ts deleted file mode 100644 index fb331a3a89ff3..0000000000000 --- a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './ToolbarRadioGroup'; -export * from './ToolbarRadioGroup.types'; diff --git a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/useToolbarRadioGroupStyles.ts b/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/useToolbarRadioGroupStyles.ts deleted file mode 100644 index 697f893b9799f..0000000000000 --- a/packages/react-components/react-toolbar/src/components/ToolbarRadioGroup/useToolbarRadioGroupStyles.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; -import { useRadioGroupStyles_unstable } from '@fluentui/react-radio'; -import { ToolbarRadioGroupState } from './ToolbarRadioGroup.types'; - -const useBaseStyles = makeStyles({ - root: { - display: 'flex', - alignItems: 'center', - ...shorthands.gap('8px'), - }, -}); - -// const useSmallStyles = makeStyles({ -// label: { -// fontSize: 'var(--fontSizeBase200)', -// }, -// }); - -/** - * Apply styling to the ToolbarRadio slots based on the state - */ -export const useToolbarRadioGroupStyles_unstable = (state: ToolbarRadioGroupState) => { - useRadioGroupStyles_unstable(state); - const baseToolbarRadioStyles = useBaseStyles(); - - state.root.className = mergeClasses(state.root.className, baseToolbarRadioStyles.root); -}; diff --git a/packages/react-components/react-toolbar/src/index.ts b/packages/react-components/react-toolbar/src/index.ts index bf1991f4e5f78..85f4bdd56b274 100644 --- a/packages/react-components/react-toolbar/src/index.ts +++ b/packages/react-components/react-toolbar/src/index.ts @@ -12,12 +12,5 @@ export { ToolbarDivider, useToolbarDividerStyles_unstable } from './ToolbarDivid export type { ToolbarDividerProps, ToolbarDividerState } from './ToolbarDivider'; export { ToolbarToggleButton } from './ToolbarToggleButton'; export type { ToolbarToggleButtonProps, ToolbarToggleButtonState } from './ToolbarToggleButton'; -export { ToolbarRadio } from './ToolbarRadio'; -export type { ToolbarRadioProps, ToolbarRadioState } from './ToolbarRadio'; -export { ToolbarRadioGroup } from './ToolbarRadioGroup'; -export type { - RadioGroupContextValue, - RadioGroupContextValues, - ToolbarRadioGroupProps, - ToolbarRadioGroupState, -} from './ToolbarRadioGroup'; +export { ToolbarRadioButton } from './ToolbarRadioButton'; +export type { ToolbarRadioButtonProps, ToolbarRadioButtonState } from './ToolbarRadioButton'; diff --git a/packages/react-components/react-toolbar/src/stories/Toolbar/ToolbarRadio.stories.tsx b/packages/react-components/react-toolbar/src/stories/Toolbar/ToolbarRadio.stories.tsx new file mode 100644 index 0000000000000..bed44cfc6e074 --- /dev/null +++ b/packages/react-components/react-toolbar/src/stories/Toolbar/ToolbarRadio.stories.tsx @@ -0,0 +1,12 @@ +import * as React from 'react'; +import { TextBold24Regular, TextItalic24Regular, TextUnderline24Regular } from '@fluentui/react-icons'; +import { Toolbar, ToolbarRadioButton } from '@fluentui/react-toolbar'; +import type { ToolbarProps } from '@fluentui/react-toolbar'; + +export const Radio = (props: Partial) => ( + + } /> + } /> + } /> + +); diff --git a/packages/react-components/react-toolbar/src/stories/Toolbar/ToolbarRadioControlled.stories.tsx b/packages/react-components/react-toolbar/src/stories/Toolbar/ToolbarRadioControlled.stories.tsx new file mode 100644 index 0000000000000..61dbfa07e7dbc --- /dev/null +++ b/packages/react-components/react-toolbar/src/stories/Toolbar/ToolbarRadioControlled.stories.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import { TextBold24Regular, TextItalic24Regular, TextUnderline24Regular } from '@fluentui/react-icons'; +import { Toolbar, ToolbarRadioButton, ToolbarDivider } from '@fluentui/react-toolbar'; +import type { ToolbarProps } from '@fluentui/react-toolbar'; + +export const ControlledRadio = (props: Partial) => { + const [checkedValues, setCheckedValues] = React.useState>({ + edit: ['cut', 'paste'], + }); + const onChange: ToolbarProps['onCheckedValueChange'] = (e, { name, checkedItems }) => { + setCheckedValues(s => { + return s ? { ...s, [name]: checkedItems } : { [name]: checkedItems }; + }); + }; + + return ( + + } /> + } /> + } /> + + + ); +}; diff --git a/packages/react-components/react-toolbar/src/stories/Toolbar/index.stories.tsx b/packages/react-components/react-toolbar/src/stories/Toolbar/index.stories.tsx index d913547c93e9d..396038d897565 100644 --- a/packages/react-components/react-toolbar/src/stories/Toolbar/index.stories.tsx +++ b/packages/react-components/react-toolbar/src/stories/Toolbar/index.stories.tsx @@ -10,6 +10,8 @@ export { WithTooltip } from './ToolbarWithTooltip.stories'; export { WithPopover } from './ToolbarWithPopover.stories'; export { Subtle } from './ToolbarSubtle.stories'; export { ControlledToggleButton } from './ToolbarControlledToggleButton.stories'; +export { Radio } from './ToolbarRadio.stories'; +export { ControlledRadio } from './ToolbarRadioControlled.stories'; export default { title: 'Preview Components/Toolbar',