Skip to content

Commit

Permalink
Merge pull request #1424 from Shopify/appprovider-new-context
Browse files Browse the repository at this point in the history
[AppProvider] Update context
  • Loading branch information
AndrewMusgrave authored May 15, 2019
2 parents 862a709 + a176047 commit f8ade61
Show file tree
Hide file tree
Showing 128 changed files with 1,255 additions and 1,325 deletions.
1 change: 1 addition & 0 deletions UNRELEASED-V4.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f

### Code quality

- Updated all our context files to export react context rather than a provider and consumer ([#1459](https://github.com/Shopify/polaris-react/pull/1459))
- Upgraded the `Autocomplete` component from legacy context API to use createContext ([#1403](https://github.com/Shopify/polaris-react/pull/1403))
- Updated `ThemeProvider` to use the new context api ([#1396](https://github.com/Shopify/polaris-react/pull/1396))
- Updated `AppProvider` to no longer use `componentWillReceiveProps`([#1255](https://github.com/Shopify/polaris-react/pull/1255))
Expand Down
47 changes: 13 additions & 34 deletions src/components/AppProvider/AppProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@ import {
ScrollLockManager,
createAppProviderContext,
} from './utilities';
import {
AppProviderProps,
Context,
polarisAppProviderContextTypes,
} from './types';
import AppProviderContext, {AppProviderContextType} from './context';
import {AppProviderProps} from './types';

interface State {
polaris: Context;
context: AppProviderContextType;
}

// The script in the styleguide that generates the Props Explorer data expects
Expand All @@ -22,10 +19,8 @@ interface State {
interface Props extends AppProviderProps {}

export default class AppProvider extends React.Component<Props, State> {
static childContextTypes = polarisAppProviderContextTypes;
private stickyManager: StickyManager;
private scrollLockManager: ScrollLockManager;
private subscriptions: {(): void}[] = [];

constructor(props: Props) {
super(props);
Expand All @@ -34,12 +29,10 @@ export default class AppProvider extends React.Component<Props, State> {
const {theme, children, ...rest} = this.props;

this.state = {
polaris: createAppProviderContext({
context: createAppProviderContext({
...rest,
stickyManager: this.stickyManager,
scrollLockManager: this.scrollLockManager,
subscribe: this.subscribe,
unsubscribe: this.unsubscribe,
}),
};
}
Expand Down Expand Up @@ -71,41 +64,27 @@ export default class AppProvider extends React.Component<Props, State> {

// eslint-disable-next-line react/no-did-update-set-state
this.setState({
polaris: createAppProviderContext({
context: createAppProviderContext({
i18n,
linkComponent,
apiKey,
shopOrigin,
forceRedirect,
stickyManager: this.stickyManager,
subscribe: this.subscribe,
unsubscribe: this.unsubscribe,
}),
});

this.subscriptions.forEach((subscriberCallback) => subscriberCallback());
}

getChildContext(): Context {
return this.state.polaris;
}

render() {
const {theme = {logo: null}} = this.props;
const {theme = {logo: null}, children} = this.props;
const {context} = this.state;

return (
<ThemeProvider theme={theme}>
{React.Children.only(this.props.children)}
</ThemeProvider>
<AppProviderContext.Provider value={context}>
<ThemeProvider theme={theme}>
{React.Children.only(children)}
</ThemeProvider>
</AppProviderContext.Provider>
);
}

subscribe = (callback: () => void) => {
this.subscriptions.push(callback);
};

unsubscribe = (callback: () => void) => {
this.subscriptions = this.subscriptions.filter(
(subscription) => subscription !== callback,
);
};
}
18 changes: 18 additions & 0 deletions src/components/AppProvider/context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from 'react';
import {ClientApplication} from '@shopify/app-bridge';
import createPolarisContext from './utilities/createPolarisContext';
import {Intl, Link, StickyManager, ScrollLockManager} from './utilities';

export interface AppProviderContextType {
intl: Intl;
link: Link;
stickyManager: StickyManager;
scrollLockManager: ScrollLockManager;
appBridge?: ClientApplication<{}>;
}

const AppProviderContext = React.createContext<AppProviderContextType>(
createPolarisContext(),
);

export default AppProviderContext;
8 changes: 2 additions & 6 deletions src/components/AppProvider/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,12 @@ export {
withAppProvider,
createAppProviderContext,
createPolarisContext,
withSticky,
WithAppProviderProps,
TranslationDictionary,
PrimitiveReplacementDictionary,
ComplexReplacementDictionary,
CreateAppProviderContext,
} from './utilities';
export {
AppProviderProps as Props,
Context,
polarisAppProviderContextTypes,
} from './types';
export {AppProviderProps as Props} from './types';
export {default as AppProviderContext, AppProviderContextType} from './context';
export {default} from './AppProvider';
35 changes: 15 additions & 20 deletions src/components/AppProvider/tests/AppProvider.test.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,28 @@
import * as React from 'react';
import {mount} from 'enzyme';
import {polarisAppProviderContextTypes} from '../types';
import AppProviderContext from '../context';
import AppProvider from '../AppProvider';
import {mountWithAppProvider} from '../../../test-utilities';

describe('<AppProvider />', () => {
it('updates polaris context when props change', () => {
const CustomLinkComponent = () => {
return <a href="test">Custom Link Component</a>;
};

// eslint-disable-next-line react/prefer-stateless-function
class Child extends React.Component {
static contextTypes = polarisAppProviderContextTypes;

render() {
return <div />;
}
}
const Child: React.SFC<{}> = (_props) => (
<AppProviderContext.Consumer>
{({link: {linkComponent}}) =>
linkComponent ? <div id="child" /> : null
}
</AppProviderContext.Consumer>
);
const LinkComponent = () => <div />;

const wrapper = mount(
const wrapper = mountWithAppProvider(
<AppProvider>
<Child />
</AppProvider>,
);

wrapper.setProps({linkComponent: CustomLinkComponent});

expect(
wrapper.find(Child).instance().context.polaris.link.linkComponent,
).toBe(CustomLinkComponent);
expect(wrapper.find('#child')).toHaveLength(0);
wrapper.setProps({linkComponent: LinkComponent});
wrapper.update();
expect(wrapper.find('#child')).toHaveLength(1);
});
});
30 changes: 2 additions & 28 deletions src/components/AppProvider/types.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
import {ClientApplication} from '@shopify/app-bridge';
import {ValidationMap} from 'react';
import * as PropTypes from 'prop-types';
import {LinkLikeComponent} from '../UnstyledLink';
import {Theme, THEME_CONTEXT_TYPES as polarisTheme} from '../ThemeProvider';
import {
Intl,
Link,
StickyManager,
ScrollLockManager,
TranslationDictionary,
} from './utilities';
import {Theme} from '../ThemeProvider';
import {TranslationDictionary} from './utilities';

export interface AppProviderProps {
/** A locale object or array of locale objects that overrides default translations */
Expand All @@ -29,20 +20,3 @@ export interface AppProviderProps {
/** Custom logos and colors provided to select components */
theme?: Theme;
}

export interface Context {
polaris: {
intl: Intl;
link: Link;
stickyManager: StickyManager;
scrollLockManager: ScrollLockManager;
subscribe?(callback: () => void): void;
unsubscribe?(callback: () => void): void;
appBridge?: ClientApplication<{}>;
};
}

export const polarisAppProviderContextTypes: ValidationMap<any> = {
polaris: PropTypes.any,
...polarisTheme,
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface StickyItem {
/** Placeholder element */
placeHolderNode: HTMLElement;
/** Element outlining the fixed position boundaries */
boundingElement: HTMLElement | null;
boundingElement?: HTMLElement | null;
/** Offset vertical spacing from the top of the scrollable container */
offset: boolean;
/** Should the element remain in a fixed position when the layout is stacked (smaller screens) */
Expand Down
3 changes: 3 additions & 0 deletions src/components/AppProvider/utilities/StickyManager/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import StickyManager from './StickyManager';

export default StickyManager;
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {noop} from '@shopify/javascript-utilities/other';
import createApp, {
getShopOrigin,
LifecycleHook,
DispatchActionHook,
} from '@shopify/app-bridge';
import {AppProviderProps, Context} from '../../types';
import {StickyManager} from '../withSticky';
import {AppProviderContextType} from '../../context';
import {AppProviderProps} from '../../types';
import StickyManager from '../StickyManager';
import ScrollLockManager from '../ScrollLockManager';
import Intl from '../Intl';
import Link from '../Link';
Expand All @@ -14,8 +14,6 @@ import {polarisVersion} from '../../../../configure';
export interface CreateAppProviderContext extends AppProviderProps {
stickyManager?: StickyManager;
scrollLockManager?: ScrollLockManager;
subscribe?(callback: () => void): void;
unsubscribe?(callback: () => void): void;
}

export default function createAppProviderContext({
Expand All @@ -26,9 +24,7 @@ export default function createAppProviderContext({
forceRedirect,
stickyManager,
scrollLockManager,
subscribe = noop,
unsubscribe = noop,
}: CreateAppProviderContext = {}): Context {
}: CreateAppProviderContext = {}): AppProviderContextType {
const intl = new Intl(i18n);
const link = new Link(linkComponent);
const appBridge = apiKey
Expand All @@ -44,15 +40,11 @@ export default function createAppProviderContext({
}

return {
polaris: {
intl,
link,
stickyManager: stickyManager || new StickyManager(),
scrollLockManager: scrollLockManager || new ScrollLockManager(),
subscribe,
unsubscribe,
appBridge,
},
intl,
link,
stickyManager: stickyManager || new StickyManager(),
scrollLockManager: scrollLockManager || new ScrollLockManager(),
appBridge,
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import * as React from 'react';
import * as appBridge from '@shopify/app-bridge';
import {noop} from '@shopify/javascript-utilities/other';
import * as targets from '@shopify/react-utilities/target';
import createAppProviderContext, {
setClientInterfaceHook,
} from '../createAppProviderContext';
import {StickyManager} from '../../withSticky';
import StickyManager from '../../StickyManager';
import ScrollLockManager from '../../ScrollLockManager';

jest.mock('../../Intl', () => ({
Expand Down Expand Up @@ -41,15 +40,11 @@ describe('createAppProviderContext()', () => {
const context = createAppProviderContext();

expect(context).toMatchObject({
polaris: {
intl: expect.any(Intl),
link: expect.any(Link),
stickyManager: expect.any(StickyManager),
scrollLockManager: expect.any(ScrollLockManager),
subscribe: noop,
unsubscribe: noop,
appBridge: undefined,
},
intl: expect.any(Intl),
link: expect.any(Link),
stickyManager: expect.any(StickyManager),
scrollLockManager: expect.any(ScrollLockManager),
appBridge: undefined,
});
});

Expand Down Expand Up @@ -86,24 +81,20 @@ describe('createAppProviderContext()', () => {
});

expect(context).toMatchObject({
polaris: {
intl: expect.any(Intl),
link: expect.any(Link),
stickyManager: expect.any(StickyManager),
scrollLockManager: expect.any(ScrollLockManager),
subscribe: noop,
unsubscribe: noop,
appBridge: {
apiKey,
forceRedirect: undefined,
shopOrigin: undefined,
dispatch: expect.any(Function),
localOrigin: '',
featuresAvailable: expect.any(Function),
getState: expect.any(Function),
subscribe: expect.any(Function),
error: expect.any(Function),
},
intl: expect.any(Intl),
link: expect.any(Link),
stickyManager: expect.any(StickyManager),
scrollLockManager: expect.any(ScrollLockManager),
appBridge: {
apiKey,
forceRedirect: undefined,
shopOrigin: undefined,
dispatch: expect.any(Function),
localOrigin: '',
featuresAvailable: expect.any(Function),
getState: expect.any(Function),
subscribe: expect.any(Function),
error: expect.any(Function),
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {PolarisContext} from '../../../types';
import {
createThemeContext,
ThemeContext as CreateThemeContext,
ThemeProviderContextType as CreateThemeContext,
} from '../../../ThemeProvider';
import {AppProviderProps} from '../../types';
import {StickyManager} from '../withSticky';
import StickyManager from '../StickyManager';
import createAppProviderContext, {
CreateAppProviderContext,
} from '../createAppProviderContext';
Expand Down Expand Up @@ -42,5 +42,5 @@ export default function createPolarisContext(
? createThemeContext(themeContext)
: createThemeContext();

return {...appProvider, ...theme};
return {...appProvider, theme};
}
Loading

0 comments on commit f8ade61

Please sign in to comment.