diff --git a/UNRELEASED.md b/UNRELEASED.md
index f8257737542..88241f43862 100644
--- a/UNRELEASED.md
+++ b/UNRELEASED.md
@@ -16,6 +16,7 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f
- Converted `Form`, `Frame`, and `Loading` examples to functional components ([#2130](https://github.com/Shopify/polaris-react/pull/2130))
- Replaced Latin abbreviations with English words in Text field content guidelines ([#2192](https://github.com/Shopify/polaris-react/pull/2192))
+- Converted `SettingToggle`, `Sheet`, and `Tabs` examples to functional components ([#2134](https://github.com/Shopify/polaris-react/pull/2134))
### Development workflow
diff --git a/src/components/AccountConnection/README.md b/src/components/AccountConnection/README.md
index e12f21a2457..56e443e8b51 100644
--- a/src/components/AccountConnection/README.md
+++ b/src/components/AccountConnection/README.md
@@ -106,50 +106,38 @@ Connect to app
Use to let merchants connect or disconnect their store to their third-party accounts, like Facebook.
```jsx
-class AccountConnectionExample extends React.Component {
- state = {
- connected: false,
- accountName: '',
- };
-
- render() {
- const {accountName, connected} = this.state;
- const buttonText = connected ? 'Disconnect' : 'Connect';
- const details = connected ? 'Account connected' : 'No account connected';
- const terms = connected ? null : (
-
- By clicking Connect , you agree to accept Sample App’s{' '}
- terms and conditions. You’ll pay a
- commission rate of 15% on sales made through Sample App.
-
- );
-
- return (
-
- );
- }
-
- handleAction = () => {
- this.setState((state) => {
- const connected = !state.connected;
- const accountName = connected ? 'Jane Appleseed' : '';
-
- return {
- connected,
- accountName,
- };
- });
- };
+function AccountConnectionExample() {
+ const [connected, setConnected] = useState(false);
+ const accountName = connected ? 'Jane Appleseed' : '';
+
+ const handleAction = useCallback(() => {
+ const newConnected = !connected;
+ setConnected((connected) => !connected);
+ }, [connected]);
+
+ const buttonText = connected ? 'Disconnect' : 'Connect';
+ const details = connected ? 'Account connected' : 'No account connected';
+ const terms = connected ? null : (
+
+ By clicking Connect , you agree to accept Sample App’s{' '}
+ terms and conditions. You’ll pay a
+ commission rate of 15% on sales made through Sample App.
+
+ );
+
+ return (
+
+ );
}
```
diff --git a/src/components/ActionList/README.md b/src/components/ActionList/README.md
index 91938a99c31..2213f63fb1e 100644
--- a/src/components/ActionList/README.md
+++ b/src/components/ActionList/README.md
@@ -85,51 +85,45 @@ Each item in an action list should be scannable avoiding unnecessary words and a
Use for the least important actions so merchants aren’t distracted by secondary tasks. Can also be used for a set of actions that won’t fit in the available screen space.
```jsx
-class ActionListExample extends React.Component {
- state = {
- active: true,
- };
-
- togglePopover = () => {
- this.setState(({active}) => {
- return {active: !active};
- });
- };
-
- render() {
- const activator = (
-
- More actions
-
- );
-
- return (
-
-
- {
- console.log('File imported');
- },
- },
- {
- content: 'Export file',
- onAction: () => {
- console.log('File exported');
- },
- },
- ]}
- />
-
-
- );
- }
+function ActionListInPopoverExample() {
+ const [active, setActive] = useState(true);
+
+ const toggleActive = useCallback(() => setActive((active) => !active), []);
+
+ const handleImportedAction = useCallback(
+ () => console.log('Imported action'),
+ [],
+ );
+
+ const handleExportedAction = useCallback(
+ () => console.log('Exported action'),
+ [],
+ );
+
+ const activator = (
+
+ More actions
+
+ );
+
+ return (
+
+ );
}
```
@@ -138,41 +132,29 @@ class ActionListExample extends React.Component {
Use when the items benefit from an associated action or image, such as a list of products.
```jsx
-class ActionListExample extends React.Component {
- state = {
- active: true,
- };
-
- togglePopover = () => {
- this.setState(({active}) => {
- return {active: !active};
- });
- };
-
- render() {
- const activator = (
-
- More actions
-
- );
-
- return (
-
- );
- }
+function ActionListWithMediaExample() {
+ const [active, setActive] = useState(true);
+
+ const toggleActive = useCallback(() => setActive((active) => !active), []);
+
+ const activator = (
+
+ More actions
+
+ );
+
+ return (
+
+ );
}
```
@@ -181,46 +163,34 @@ class ActionListExample extends React.Component {
Use when the items benefit from sections to help differentiate actions.
```jsx
-class ActionListExample extends React.Component {
- state = {
- active: true,
- };
-
- togglePopover = () => {
- this.setState(({active}) => {
- return {active: !active};
- });
- };
-
- render() {
- const activator = (
-
- More actions
-
- );
-
- return (
-
- );
- }
+function SectionedActionListExample() {
+ const [active, setActive] = useState(true);
+
+ const toggleActive = useCallback(() => setActive((active) => !active), []);
+
+ const activator = (
+
+ More actions
+
+ );
+
+ return (
+
+ );
}
```
@@ -229,51 +199,39 @@ class ActionListExample extends React.Component {
Use to visually indicate that an action list item is destructive.
```jsx
-class ActionListExample extends React.Component {
- state = {
- active: true,
- };
-
- togglePopover = () => {
- this.setState(({active}) => {
- return {active: !active};
- });
- };
-
- render() {
- const activator = (
-
- More actions
-
- );
-
- return (
-
- );
- }
+function ActionListWithDestructiveItemExample() {
+ const [active, setActive] = useState(true);
+
+ const toggleActive = useCallback(() => setActive((active) => !active), []);
+
+ const activator = (
+
+ More actions
+
+ );
+
+ return (
+
+ );
}
```
@@ -282,51 +240,39 @@ class ActionListExample extends React.Component {
Use help text when the normal Verb noun syntax for the actions does not provide sufficient context for the merchant.
```jsx
-class ActionListExample extends React.Component {
- state = {
- active: true,
- };
-
- togglePopover = () => {
- this.setState(({active}) => {
- return {active: !active};
- });
- };
-
- render() {
- const activator = (
-
- More actions
-
- );
-
- return (
-
- );
- }
+function ActionListWithHelpTextExample() {
+ const [active, setActive] = useState(true);
+
+ const toggleActive = useCallback(() => setActive((active) => !active), []);
+
+ const activator = (
+
+ More actions
+
+ );
+
+ return (
+
+ );
}
```
diff --git a/src/components/AppProvider/README.md b/src/components/AppProvider/README.md
index 0d657cb6761..e04270be89e 100644
--- a/src/components/AppProvider/README.md
+++ b/src/components/AppProvider/README.md
@@ -158,47 +158,45 @@ With an `i18n`, `AppProvider` will provide these translations to polaris compone
With a `linkComponent`, the app provider component will override the links used in other components. For example you may want to use the `Link` component provided by `react-router` throughout your application instead of the default `a` tag.
```jsx
-class ProviderLinkExample extends React.Component {
- render() {
- const CustomLinkComponent = ({children, url, ...rest}) => {
- return (
- console.log('Custom link clicked')}
- {...rest}
- >
- {children}
-
- );
- };
-
+function AppProviderLinkExample() {
+ const CustomLinkComponent = ({children, url, ...rest}) => {
return (
- console.log('Custom link clicked')}
+ {...rest}
+ >
+ {children}
+
+ );
+ };
+
+ return (
+
+
-
- Page content
-
-
- );
- }
+ Page content
+
+
+ );
}
```
@@ -207,114 +205,108 @@ class ProviderLinkExample extends React.Component {
With a `theme`, the app provider component will set light, dark, and text colors for the [top bar](https://polaris.shopify.com/components/structure/top-bar) component when given a `background` color, as well as a logo for the top bar and [contextual save bar](https://polaris.shopify.com/components/forms/contextual-save-bar) components.
```jsx
-class ProviderThemeExample extends React.Component {
- state = {
- isDirty: false,
- searchFieldValue: '',
- };
-
- render() {
- const {isDirty, searchFieldValue} = this.state;
-
- const theme = {
- colors: {
- topBar: {
- background: '#357997',
- },
- },
- logo: {
- width: 124,
- topBarSource:
- 'https://cdn.shopify.com/s/files/1/0446/6937/files/jaded-pixel-logo-color.svg?6215648040070010999',
- url: 'http://jadedpixel.com',
- accessibilityLabel: 'Jaded Pixel',
- contextualSaveBarSource:
- 'https://cdn.shopify.com/s/files/1/0446/6937/files/jaded-pixel-logo-gray.svg?6215648040070010999',
+function AppProviderThemeExample() {
+ const [isDirty, setIsDirty] = useState(false);
+ const [searchFieldValue, setSearchFieldValue] = useState('');
+
+ const handleSearchChange = useCallback(
+ (searchFieldValue) => setSearchFieldValue(searchFieldValue),
+ [],
+ );
+
+ const toggleIsDirty = useCallback(
+ () => setIsDirty((isDirty) => !isDirty),
+ [],
+ );
+
+ const theme = {
+ colors: {
+ topBar: {
+ background: '#357997',
},
- };
-
- const searchFieldMarkup = (
-
- );
-
- const topBarMarkup = ;
-
- const contentStatus = isDirty ? 'Disable' : 'Enable';
- const textStatus = isDirty ? 'enabled' : 'disabled';
-
- const pageMarkup = (
-
-
-
-
- This setting is{' '}
- {textStatus} .
-
-
-
-
- );
+ },
+ logo: {
+ width: 124,
+ topBarSource:
+ 'https://cdn.shopify.com/s/files/1/0446/6937/files/jaded-pixel-logo-color.svg?6215648040070010999',
+ url: 'http://jadedpixel.com',
+ accessibilityLabel: 'Jaded Pixel',
+ contextualSaveBarSource:
+ 'https://cdn.shopify.com/s/files/1/0446/6937/files/jaded-pixel-logo-gray.svg?6215648040070010999',
+ },
+ };
- const contextualSaveBarMarkup = isDirty ? (
-
- ) : null;
+ const searchFieldMarkup = (
+
+ );
+
+ const topBarMarkup = ;
+
+ const contentStatus = isDirty ? 'Disable' : 'Enable';
+ const textStatus = isDirty ? 'enabled' : 'disabled';
+
+ const pageMarkup = (
+
+
+
+
+ This setting is{' '}
+ {textStatus} .
+
+
+
+
+ );
+
+ const contextualSaveBarMarkup = isDirty ? (
+
+ ) : null;
- return (
-
-
+
-
- {contextualSaveBarMarkup}
- {pageMarkup}
-
-
-
- );
- }
-
- handleSearchChange = (searchFieldValue) => {
- this.setState({searchFieldValue});
- };
-
- toggleState = (key) => {
- return () => {
- this.setState((prevState) => ({[key]: !prevState[key]}));
- };
- };
+ },
+ }}
+ >
+
+ {contextualSaveBarMarkup}
+ {pageMarkup}
+
+
+
+ );
}
```
@@ -323,118 +315,112 @@ class ProviderThemeExample extends React.Component {
Provide specific keys and corresponding colors to the [top bar](https://polaris.shopify.com/components/structure/top-bar) component theme for finer control. When giving more than just the `background`, providing all keys is necessary to prevent falling back to default colors.
```jsx
-class ProviderThemeExample extends React.Component {
- state = {
- isDirty: false,
- searchFieldValue: '',
- };
-
- render() {
- const {isDirty, searchFieldValue} = this.state;
-
- const theme = {
- colors: {
- topBar: {
- background: '#357997',
- backgroundLighter: '#6192a9',
- color: '#FFFFFF',
- },
+function AppProviderWithAllThemeKeysExample() {
+ const [isDirty, setIsDirty] = useState(false);
+ const [searchFieldValue, setSearchFieldValue] = useState('');
+
+ const handleSearchChange = useCallback(
+ (searchFieldValue) => setSearchFieldValue(searchFieldValue),
+ [],
+ );
+
+ const toggleIsDirty = useCallback(
+ () => setIsDirty((isDirty) => !isDirty),
+ [],
+ );
+
+ const theme = {
+ colors: {
+ topBar: {
+ background: '#357997',
+ backgroundLighter: '#6192a9',
+ color: '#FFFFFF',
},
- logo: {
- width: 124,
- topBarSource:
- 'https://cdn.shopify.com/s/files/1/0446/6937/files/jaded-pixel-logo-color.svg?6215648040070010999',
- url: 'http://jadedpixel.com',
- accessibilityLabel: 'Jaded Pixel',
- contextualSaveBarSource:
- 'https://cdn.shopify.com/s/files/1/0446/6937/files/jaded-pixel-logo-gray.svg?6215648040070010999',
- },
- };
-
- const searchFieldMarkup = (
-
- );
-
- const topBarMarkup = ;
-
- const contentStatus = isDirty ? 'Disable' : 'Enable';
- const textStatus = isDirty ? 'enabled' : 'disabled';
-
- const pageMarkup = (
-
-
-
-
- This setting is{' '}
- {textStatus} .
-
-
-
-
- );
+ },
+ logo: {
+ width: 124,
+ topBarSource:
+ 'https://cdn.shopify.com/s/files/1/0446/6937/files/jaded-pixel-logo-color.svg?6215648040070010999',
+ url: 'http://jadedpixel.com',
+ accessibilityLabel: 'Jaded Pixel',
+ contextualSaveBarSource:
+ 'https://cdn.shopify.com/s/files/1/0446/6937/files/jaded-pixel-logo-gray.svg?6215648040070010999',
+ },
+ };
- const contextualSaveBarMarkup = isDirty ? (
-
- ) : null;
+ const searchFieldMarkup = (
+
+ );
+
+ const topBarMarkup = ;
+
+ const contentStatus = isDirty ? 'Disable' : 'Enable';
+ const textStatus = isDirty ? 'enabled' : 'disabled';
+
+ const pageMarkup = (
+
+
+
+
+ This setting is{' '}
+ {textStatus} .
+
+
+
+
+ );
+
+ const contextualSaveBarMarkup = isDirty ? (
+
+ ) : null;
- return (
-
-
+
-
- {contextualSaveBarMarkup}
- {pageMarkup}
-
-
-
- );
- }
-
- handleSearchChange = (searchFieldValue) => {
- this.setState({searchFieldValue});
- };
-
- toggleState = (key) => {
- return () => {
- this.setState((prevState) => ({[key]: !prevState[key]}));
- };
- };
+ },
+ }}
+ >
+
+ {contextualSaveBarMarkup}
+ {pageMarkup}
+
+
+
+ );
}
```
@@ -488,14 +474,14 @@ To provide access to your initialized Shopify App Bridge instance, we make it av
```js
import React from 'react';
import {render} from 'react-dom';
-import {AppProvider, AppBridgeContext} from '@shopify/polaris';
+import {AppProvider, _SECRET_INTERNAL_APP_BRIDGE_CONTEXT} from '@shopify/polaris';
import {Redirect} from '@shopify/app-bridge/actions';
-class MyApp extends React.Component {
- static contextType = AppBridgeContext;
+function MyApp() {
+ const appBridge = useContext(_SECRET_INTERNAL_APP_BRIDGE_CONTEXT)
- componentDidMount() {
- const redirect = Redirect.create(this.context);
+ redirectToSettings() {
+ const redirect = Redirect.create(appBridge);
// Go to {appOrigin}/settings
redirect.dispatch(Redirect.Action.APP, '/settings');