Skip to content

Commit

Permalink
feat: replace ToolbarRadio implementation by usage of toggle button a…
Browse files Browse the repository at this point in the history
…s Radio (microsoft#25343)

* feat: replace ToolbarRadio implementation by usage of toggle button as radio

* chore: add changes

* chore: remove and update api

* chore: update handler types

* chore: delete line

* chore: update checked items type

* chore: rename

* chore: update api and remove disable flag from handle radio

* chore: update snapshot
  • Loading branch information
chpalac authored and NotWoods committed Nov 18, 2022
1 parent 016a37d commit 419d012
Show file tree
Hide file tree
Showing 34 changed files with 223 additions and 289 deletions.
Original file line number Diff line number Diff line change
@@ -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"
}
35 changes: 8 additions & 27 deletions packages/react-components/react-toolbar/etc/react-toolbar.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<RadioGroupProps, 'name' | 'value' | 'defaultValue' | 'disabled' | 'layout' | 'required'>;

// @public (undocumented)
export type RadioGroupContextValues = {
radioGroup: RadioGroupContextValue;
};

// @public
export const renderToolbar_unstable: (state: ToolbarState, contextValues: ToolbarContextValues) => JSX.Element;

Expand All @@ -55,6 +43,7 @@ export const toolbarClassNames: SlotClassNames<ToolbarSlots>;
// @public (undocumented)
export type ToolbarContextValue = Pick<ToolbarState, 'size' | 'vertical' | 'checkedValues'> & {
handleToggleButton?: ToggableHandler;
handleRadio?: ToggableHandler;
};

// @public (undocumented)
Expand Down Expand Up @@ -83,26 +72,17 @@ export type ToolbarProps = ComponentProps<ToolbarSlots> & {
};

// @public
export const ToolbarRadio: ForwardRefComponent<ToolbarRadioProps>;

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

// @public
export type ToolbarRadioGroupProps = RadioGroupProps;
export const ToolbarRadioButton: ForwardRefComponent<ToolbarRadioButtonProps>;

// @public
export type ToolbarRadioGroupState = RadioGroupState;

// @public
export type ToolbarRadioProps = RadioProps & {
size?: 'small' | 'medium';
export type ToolbarRadioButtonProps = ComponentProps<ButtonSlots> & Partial<Pick<ToggleButtonProps, 'disabled' | 'disabledFocusable' | 'size'>> & {
appearance?: 'primary' | 'subtle';
name: string;
value: string;
};

// @public
export type ToolbarRadioState = RadioState & {
size?: 'small' | 'medium';
};
export type ToolbarRadioButtonState = ComponentState<Partial<ButtonSlots>> & ToggleButtonState & Required<Pick<ToggleButtonProps, 'checked'>> & Pick<ToolbarRadioButtonProps, 'name' | 'value'>;

// @public (undocumented)
export type ToolbarSlots = {
Expand All @@ -112,6 +92,7 @@ export type ToolbarSlots = {
// @public
export type ToolbarState = ComponentState<ToolbarSlots> & Required<Pick<ToolbarProps, 'size' | 'checkedValues' | 'vertical'>> & Pick<ToolbarProps, 'defaultCheckedValues' | 'onCheckedValueChange'> & {
handleToggleButton: ToggableHandler;
handleRadio: ToggableHandler;
};

// @public
Expand Down
1 change: 1 addition & 0 deletions packages/react-components/react-toolbar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components/ToolbarRadioButton/index';

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,27 @@ export type ToolbarState = ComponentState<ToolbarSlots> &
* Toggles the state of a ToggleButton item
*/
handleToggleButton: ToggableHandler;
/*
* Toggles the state of a ToggleButton item
*/
handleRadio: ToggableHandler;
};

export type ToolbarContextValue = Pick<ToolbarState, 'size' | 'vertical' | 'checkedValues'> & {
handleToggleButton?: ToggableHandler;
handleRadio?: ToggableHandler;
};

export type ToolbarContextValues = {
toolbar: ToolbarContextValue;
};

export type UninitializedToolbarState = Omit<ToolbarState, 'checkedValues' | 'handleToggleButton'> &
export type UninitializedToolbarState = Omit<ToolbarState, 'checkedValues' | 'handleToggleButton' | 'handleRadio'> &
Partial<Pick<ToolbarState, 'checkedValues'>>;

export type ToggableHandler = (
e: React.MouseEvent | React.KeyboardEvent,
name?: string,
value?: string,
name: string,
value: string,
checked?: boolean,
) => void;
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const ToolbarContext = createContext<ToolbarContextValue | undefined>(und
const toolbarContextDefaultValue: ToolbarContextValue = {
size: 'medium' as 'medium',
handleToggleButton: () => null,
handleRadio: () => null,
vertical: false,
checkedValues: {},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const useToolbar_unstable = (props: ToolbarProps, ref: React.Ref<HTMLElem
const { onCheckedValueChange } = initialState;

const handleToggleButton: ToggableHandler = useEventCallback(
(e: React.MouseEvent | React.KeyboardEvent, name?: string, value?: string, checked?: boolean) => {
(e: React.MouseEvent | React.KeyboardEvent, name: string, value: string, checked?: boolean) => {
if (name && value) {
const checkedItems = checkedValues?.[name] || [];
const newCheckedItems = [...checkedItems];
Expand All @@ -64,9 +64,22 @@ export const useToolbar_unstable = (props: ToolbarProps, ref: React.Ref<HTMLElem
},
);

const handleRadio: ToggableHandler = useEventCallback(
(e: React.MouseEvent | React.KeyboardEvent, name: string, value: string, checked?: boolean) => {
if (name && value) {
onCheckedValueChange?.(e, {
name,
checkedItems: checkedValues?.[name],
});
setCheckedValues(s => ({ ...s, [name]: [value] }));
}
},
);

return {
...initialState,
handleToggleButton,
handleRadio,
checkedValues: checkedValues ?? {},
};
};
Original file line number Diff line number Diff line change
@@ -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,
};

Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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<ToggleButtonProps>,
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(
<ToolbarRadioButton name="name" value="value">
Default ToolbarRadio
</ToolbarRadioButton>,
);
expect(result.container).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -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<ToolbarRadioButtonProps> = React.forwardRef((props, ref) => {
const state = useToolbarRadioButton_unstable(props, ref);

useToolbarRadioButtonStyles_unstable(state);
return renderToggleButton_unstable(state);
}) as ForwardRefComponent<ToolbarRadioButtonProps>;

ToolbarRadioButton.displayName = 'ToolbarRadioButton';
Original file line number Diff line number Diff line change
@@ -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<ButtonSlots> &
Partial<Pick<ToggleButtonProps, 'disabled' | 'disabledFocusable' | 'size'>> & {
appearance?: 'primary' | 'subtle';
name: string;
value: string;
};

/**
* State used in rendering ToolbarRadioButton
*/
export type ToolbarRadioButtonState = ComponentState<Partial<ButtonSlots>> &
ToggleButtonState &
Required<Pick<ToggleButtonProps, 'checked'>> &
Pick<ToolbarRadioButtonProps, 'name' | 'value'>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ToolbarRadioButton renders a default state 1`] = `
<div>
<button
aria-pressed="false"
class="fui-Button fui-ToggleButton"
name="name"
type="button"
value="value"
>
Default ToolbarRadio
</button>
</div>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './ToolbarRadioButton';
export * from './ToolbarRadioButton.types';
Loading

0 comments on commit 419d012

Please sign in to comment.