Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Button: Migrate react-button to new DX #18607

Merged
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
55387b7
migrate react-button
TristanWatanabe Jun 17, 2021
60b4d3c
explicitly declare marginTop value to fix babel error
TristanWatanabe Jun 17, 2021
4eb8061
extract buttonBaseProps from Button story into its own file
TristanWatanabe Jun 17, 2021
d0bcf13
update other Button Stories to import from new ButtonBaseProps file
TristanWatanabe Jun 17, 2021
43f9679
Change files
TristanWatanabe Jun 17, 2021
7591bf2
rename buttonBaseProps
TristanWatanabe Jun 18, 2021
a98a9f3
change import paths from index to respective Button folders
TristanWatanabe Jun 18, 2021
68441b7
change import paths from index to exact file
TristanWatanabe Jun 18, 2021
ab753e7
add .stories suffix to Playground files
TristanWatanabe Jun 18, 2021
e96762f
update Playground imports
TristanWatanabe Jun 18, 2021
32389fc
update start script so yarn start works
TristanWatanabe Jun 18, 2021
410bc66
change file extension
TristanWatanabe Jun 18, 2021
b5c6c69
minor
TristanWatanabe Jun 18, 2021
3cc4543
refactor and remove usage of v8 components
TristanWatanabe Jul 2, 2021
e77d235
Merge branch 'master' into migrate-react-button
TristanWatanabe Jul 2, 2021
8fbe1be
Undo file change due to linter
TristanWatanabe Jul 2, 2021
bdf497e
minor
TristanWatanabe Jul 2, 2021
b4272ef
add react-menu as devDep
TristanWatanabe Jul 2, 2021
f53eed8
update version number
TristanWatanabe Jul 2, 2021
010ca9d
Remove usage of react-text
TristanWatanabe Jul 2, 2021
d06f287
Merge branch 'master' into migrate-react-button
TristanWatanabe Jul 14, 2021
9e97b56
remove changes made by linter
TristanWatanabe Jul 14, 2021
f945ced
update buttonBaseProps based on changes made in #18563
TristanWatanabe Jul 14, 2021
bbc4f3d
update buttonBaseProps import path
TristanWatanabe Jul 14, 2021
e0191f8
remove changes made by linter
TristanWatanabe Jul 14, 2021
31b0a49
update react-menu version
TristanWatanabe Jul 14, 2021
9807ce9
update buttonBaseProps import path
TristanWatanabe Jul 14, 2021
30e42f4
Merge branch 'master' into migrate-react-button
TristanWatanabe Jul 16, 2021
c406275
upgrade react-menu devDep to alpha.50
TristanWatanabe Jul 16, 2021
76c4a4b
remove unused disable lint directives
TristanWatanabe Jul 16, 2021
36c2d21
Merge branch 'master' into migrate-react-button
TristanWatanabe Jul 16, 2021
b56cc35
Remove react-menu devDep
TristanWatanabe Jul 16, 2021
980c228
Merge branch 'master' into migrate-react-button
TristanWatanabe Jul 16, 2021
ed0485d
add ts-ignore on react-menu import
TristanWatanabe Jul 19, 2021
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
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Button: Migrate to new dx",
"packageName": "@fluentui/react-button",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Button: Migrate to new dx",
"packageName": "@fluentui/react-examples",
"email": "[email protected]",
"dependentChangeType": "patch"
}
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ module.exports = {
'<rootDir>/packages/react-utilities',
'<rootDir>/packages/react-theme',
'<rootDir>/packages/react-badge',
'<rootDir>/packages/react-button',
'<rootDir>/packages/keyboard-keys',
'<rootDir>/packages/react-slider',
'<rootDir>/packages/make-styles-webpack-loader',
Expand Down
2 changes: 1 addition & 1 deletion nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
"@fluentui/react-accordion": { "tags": ["vNext"], "implicitDependencies": [] },
"@fluentui/react-avatar": { "tags": ["vNext", "platform:web"], "implicitDependencies": [] },
"@fluentui/react-badge": { "tags": ["vNext", "platform:web"], "implicitDependencies": [] },
"@fluentui/react-button": { "implicitDependencies": [] },
"@fluentui/react-button": { "tags": ["vNext", "platform:web"], "implicitDependencies": [] },
"@fluentui/react-card": { "implicitDependencies": [] },
"@fluentui/react-cards": { "implicitDependencies": [] },
"@fluentui/react-charting": { "implicitDependencies": [] },
Expand Down
11 changes: 11 additions & 0 deletions packages/react-button/.storybook/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const rootMain = require('../../../.storybook/main');

module.exports = /** @type {Pick<import('../../../.storybook/main').StorybookConfig,'addons'|'stories'|'webpackFinal'>} */ ({
stories: [...rootMain.stories, '../src/**/*.stories.mdx', '../src/**/*.stories.@(ts|tsx)'],
addons: [...rootMain.addons],
webpackFinal: (config, options) => {
const localConfig = { ...rootMain.webpackFinal(config, options) };

return localConfig;
},
});
3 changes: 3 additions & 0 deletions packages/react-button/.storybook/preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import * as rootPreview from '../../../.storybook/preview';

export const decorators = [...rootPreview.decorators];
9 changes: 9 additions & 0 deletions packages/react-button/.storybook/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true
},
"exclude": ["../**/*.test.ts", "../**/*.test.js", "../**/*.test.tsx", "../**/*.test.jsx"],
"include": ["../src/**/*", "*.js"]
}
5 changes: 5 additions & 0 deletions packages/react-button/config/api-extractor.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"extends": "./api-extractor.json",
"mainEntryPointFilePath": "<projectFolder>/dist/<unscopedPackageName>/src/index.d.ts"
}
26 changes: 19 additions & 7 deletions packages/react-button/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
const { createConfig } = require('@fluentui/scripts/jest/jest-resources');
const path = require('path');
// @ts-check

const config = createConfig({
setupFiles: [path.resolve(path.join(__dirname, 'config', 'tests.js'))],
/**
* @type {jest.InitialOptions}
*/
module.exports = {
displayName: 'react-button',
preset: '../../jest.preset.js',
globals: {
'ts-jest': {
tsConfig: '<rootDir>/tsconfig.json',
diagnostics: false,
},
},
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
coverageDirectory: './coverage',
setupFilesAfterEnv: ['./config/tests.js'],
snapshotSerializers: ['@fluentui/jest-serializer-make-styles'],
});

module.exports = config;
};
9 changes: 5 additions & 4 deletions packages/react-button/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
"code-style": "just-scripts code-style",
"just": "just-scripts",
"lint": "just-scripts lint",
"start": "just-scripts dev:storybook",
"start-test": "just-scripts jest-watch",
"test": "just-scripts test",
"update-snapshots": "just-scripts jest -u"
"start": "yarn storybook",
"test": "jest",
"docs": "api-extractor run --config=config/api-extractor.local.json --local",
"build:local": "tsc -p . --module esnext --emitDeclarationOnly && node ../../scripts/typescript/normalize-import --output dist/packages/react-button/src && yarn docs",
"storybook": "start-storybook"
},
"devDependencies": {
"@fluentui/a11y-testing": "^0.1.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as React from 'react';
import { Button, ButtonProps } from '@fluentui/react-button';
import { Playground } from '../Playground';
import { PlaygroundProps, PropDefinition } from '../Playground.types';
import { Button, ButtonProps } from './Button';
import { Playground } from './Playground.stories';
import { PlaygroundProps } from './Playground.types.stories';
import { buttonBaseProps } from './buttonBaseProps.stories';

// TODO: this is here while waiting for react-icons to merge
const SVGIcon = () => (
Expand Down Expand Up @@ -101,29 +102,6 @@ export const Disabled = () => (
</>
);

type ExampleProps = { iconOnly?: string };

export const buttonBaseProps: PropDefinition<ButtonProps & ExampleProps>[] = [
{ propName: 'block', propType: 'boolean' },
{ propName: 'circular', propType: 'boolean' },
{ propName: 'content', propType: 'string', defaultValue: 'This is a button', dependsOnProps: ['~iconOnly'] },
{ propName: 'disabled', propType: 'boolean', dependsOnProps: ['~disabledFocusable'] },
{ propName: 'disabledFocusable', propType: 'boolean', dependsOnProps: ['~disabled'] },
{ propName: 'icon', propType: 'boolean' },
{ propName: 'iconOnly', propType: 'boolean', dependsOnProps: ['icon'] },
{
propName: 'iconPosition',
propType: ['before', 'after'],
defaultValue: 'before',
dependsOnProps: ['icon', '~iconOnly'],
},
{ propName: 'outline', propType: 'boolean', dependsOnProps: ['~primary', '~subtle', '~transparent'] },
{ propName: 'primary', propType: 'boolean', dependsOnProps: ['~outline', '~subtle', '~transparent'] },
{ propName: 'size', propType: ['small', 'medium', 'large'], defaultValue: 'medium' },
{ propName: 'subtle', propType: 'boolean', dependsOnProps: ['~outline', '~primary', '~transparent'] },
{ propName: 'transparent', propType: 'boolean', dependsOnProps: ['~outline', '~primary', '~subtle'] },
];

const buttonProps: PlaygroundProps<ButtonProps>['sections'] = [
{ sectionName: 'Button props', propList: buttonBaseProps },
];
Expand All @@ -133,3 +111,8 @@ export const ButtonPlayground = () => (
<Button />
</Playground>
);

export default {
title: 'Components/Button',
component: Button,
};
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as React from 'react';
import { CompoundButton, CompoundButtonProps } from '@fluentui/react-button';
import { buttonBaseProps } from '../Button/Button.stories';
import { Playground } from '../Playground';
import { PlaygroundProps, PropDefinition } from '../Playground.types';
import { CompoundButton, CompoundButtonProps } from './CompoundButton';
import { Playground } from './Playground.stories';
import { PlaygroundProps, PropDefinition } from './Playground.types.stories';
import { buttonBaseProps } from './buttonBaseProps.stories';

type ExampleProps = { iconOnly?: string };

Expand All @@ -25,3 +25,8 @@ export const CompoundButtonPlayground = () => (
<CompoundButton />
</Playground>
);

export default {
title: 'Components/CompoundButton',
component: CompoundButton,
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as React from 'react';
import { MenuButton, MenuButtonProps } from '@fluentui/react-button';
import { Menu, MenuItem, MenuList, MenuProps, MenuTrigger } from '@fluentui/react-menu';
import { buttonBaseProps } from '../Button/Button.stories';
import { Playground } from '../Playground';
import { PlaygroundProps } from '../Playground.types';
import { MenuButton, MenuButtonProps } from './MenuButton';
import { Playground } from './Playground.stories';
import { PlaygroundProps } from './Playground.types.stories';
import { buttonBaseProps } from './buttonBaseProps.stories';

const ExampleMenu = (props: MenuButtonProps): JSX.Element => (
<Menu>
Expand All @@ -29,3 +29,8 @@ export const MenuButtonPlayground = () => {
</Playground>
);
};

export default {
title: 'Components/MenuButton',
component: MenuButton,
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import { Checkbox, Dropdown, IDropdownOption, Stack, Text, TextField } from '@fluentui/react';
import { PlaygroundProps } from './Playground.types';
import { Checkbox, Dropdown, IDropdownOption, TextField } from './tmp-components.stories';
import { PlaygroundProps } from './Playground.types.stories';
import { makeStyles } from '@fluentui/react-make-styles';

const tableStyle: React.CSSProperties = {
border: '1px solid black',
Expand All @@ -10,8 +11,39 @@ const cellStyle: React.CSSProperties = {
padding: '5px',
};

const useStyles = makeStyles({
stack: {
display: 'flex',
flexDirection: 'row',
flexWrap: 'nowrap',
width: 'auto',
height: 'auto',
boxSizing: 'border-box',
justifyContent: 'center',
},

checkbox: {
position: 'relative',
display: 'flex',
flexShrink: 0,
alignItems: 'center',
justifyContent: 'center',
height: '20px',
width: '20px',
border: `1px solid rgb(50, 49, 48)`,
borderRadius: '2px',
boxSizing: 'border-box',
transitionProperty: 'background, border, border-color',
transitionDuration: '200ms',
transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.23, 1)',
overflow: 'hidden',
marginRight: '4px',
},
});

export const Playground = function <TType>(props: PlaygroundProps<TType>): JSX.Element {
const { children, sections } = props;
const styles = useStyles();

const [componentProps, setComponentProps] = React.useState<{ [key in string]: boolean | string } | null>(null);
const newProps: { [key in string]: boolean | string } = {};
Expand Down Expand Up @@ -54,7 +86,9 @@ export const Playground = function <TType>(props: PlaygroundProps<TType>): JSX.E
}

const onBooleanPropChange = (ev?: React.FormEvent<HTMLElement | HTMLInputElement>, checked?: boolean) => {
const newComponentProps: { [key in string]: boolean | string } = { ...componentProps };
const newComponentProps: { [key in string]: boolean | string } = {
...componentProps,
};
newComponentProps[propName] = checked || false;
setComponentProps(newComponentProps);
prop.setDefaultValue?.(checked || false);
Expand All @@ -71,8 +105,8 @@ export const Playground = function <TType>(props: PlaygroundProps<TType>): JSX.E
: (prop.defaultValue as boolean)
}
disabled={!isPropEnabled}
// eslint-disable-next-line react/jsx-no-bind
onChange={onBooleanPropChange}
styles={styles.checkbox}
/>
</td>
</tr>,
Expand All @@ -84,7 +118,9 @@ export const Playground = function <TType>(props: PlaygroundProps<TType>): JSX.E
ev?: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>,
newValue?: string,
) => {
const newComponentProps: { [key in string]: boolean | string } = { ...componentProps };
const newComponentProps: { [key in string]: boolean | string } = {
...componentProps,
};
newComponentProps[propName] = newValue || '';
setComponentProps(newComponentProps);
};
Expand All @@ -100,7 +136,6 @@ export const Playground = function <TType>(props: PlaygroundProps<TType>): JSX.E
: (prop.defaultValue as string)
}
disabled={!isPropEnabled}
// eslint-disable-next-line react/jsx-no-bind
onChange={onStringPropChange}
/>
</td>
Expand All @@ -111,11 +146,13 @@ export const Playground = function <TType>(props: PlaygroundProps<TType>): JSX.E
newProps[propName] = (componentProps && componentProps[propName]) || prop.defaultValue || propType[0];

const onOptionsPropChange = (
ev?: React.FormEvent<HTMLDivElement>,
option?: IDropdownOption<any>,
ev?: React.FormEvent<HTMLSelectElement>,
option?: IDropdownOption,
index?: number,
) => {
const newComponentProps: { [key in string]: boolean | string } = { ...componentProps };
const newComponentProps: { [key in string]: boolean | string } = {
...componentProps,
};
if (option) {
newComponentProps[propName] = (option.key as string) || '';
setComponentProps(newComponentProps);
Expand All @@ -134,7 +171,6 @@ export const Playground = function <TType>(props: PlaygroundProps<TType>): JSX.E
: (defaultSelectedKey as string)
}
options={propType.map(value => ({ key: value, text: value }))}
// eslint-disable-next-line react/jsx-no-bind
onChange={onOptionsPropChange}
/>
</td>
Expand All @@ -146,7 +182,7 @@ export const Playground = function <TType>(props: PlaygroundProps<TType>): JSX.E
<React.Fragment key={section.sectionName}>
<tr>
<td style={cellStyle} colSpan={2}>
<Text variant="medium">{section.sectionName}</Text>
<text>{section.sectionName}</text>
</td>
</tr>
{sectionList}
Expand All @@ -166,7 +202,7 @@ export const Playground = function <TType>(props: PlaygroundProps<TType>): JSX.E

return (
<>
<Stack horizontalAlign="center">{React.cloneElement(children, elementProps || {})}</Stack>
<div className={styles.stack}>{React.cloneElement(children, elementProps || {})}</div>
<table style={tableStyle} cellSpacing={0}>
<tbody>{playgroundSections}</tbody>
</table>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import * as React from 'react';

/* eslint-disable @typescript-eslint/naming-convention */

/** Type to get only the string keys of T. */
type StringKeyOf<T> = { [K in keyof T]: K extends string ? K : never }[keyof T];

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as React from 'react';
import { ToggleButton, ToggleButtonProps } from '@fluentui/react-button';
import { useBoolean } from '@fluentui/react-utilities';
import { buttonBaseProps } from '../Button/Button.stories';
import { Playground } from '../Playground';
import { PlaygroundProps, PropDefinition } from '../Playground.types';
import { ToggleButton, ToggleButtonProps } from './ToggleButton';
import { Playground } from './Playground.stories';
import { PlaygroundProps, PropDefinition } from './Playground.types.stories';
import { buttonBaseProps } from './buttonBaseProps.stories';

export const ToggleButtonPlayground = () => {
const [checked, { setTrue: setTrueChecked, setFalse: setFalseChecked, toggle: toggleChecked }] = useBoolean(false);
Expand Down Expand Up @@ -43,3 +43,8 @@ export const ToggleButtonPlayground = () => {
</Playground>
);
};

export default {
title: 'Components/ToggleButton',
component: ToggleButton,
};
25 changes: 25 additions & 0 deletions packages/react-button/src/buttonBaseProps.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ButtonProps } from './Button';
import { PropDefinition } from './Playground.types.stories';

type ExampleProps = { iconOnly?: string };

export const buttonBaseProps: PropDefinition<ButtonProps & ExampleProps>[] = [
{ propName: 'block', propType: 'boolean' },
{ propName: 'circular', propType: 'boolean' },
{ propName: 'content', propType: 'string', defaultValue: 'This is a button', dependsOnProps: ['~iconOnly'] },
{ propName: 'disabled', propType: 'boolean', dependsOnProps: ['~disabledFocusable'] },
{ propName: 'disabledFocusable', propType: 'boolean', dependsOnProps: ['~disabled'] },
{ propName: 'icon', propType: 'boolean' },
{ propName: 'iconOnly', propType: 'boolean', dependsOnProps: ['icon'] },
{
propName: 'iconPosition',
propType: ['before', 'after'],
defaultValue: 'before',
dependsOnProps: ['icon', '~iconOnly'],
},
{ propName: 'outline', propType: 'boolean', dependsOnProps: ['~primary', '~subtle', '~transparent'] },
{ propName: 'primary', propType: 'boolean', dependsOnProps: ['~outline', '~subtle', '~transparent'] },
{ propName: 'size', propType: ['small', 'medium', 'large'], defaultValue: 'medium' },
{ propName: 'subtle', propType: 'boolean', dependsOnProps: ['~outline', '~primary', '~transparent'] },
{ propName: 'transparent', propType: 'boolean', dependsOnProps: ['~outline', '~primary', '~subtle'] },
];
Loading