Skip to content

Commit

Permalink
AmplifyProvider accepts partial list of primitives as components (#582
Browse files Browse the repository at this point in the history
)
  • Loading branch information
ericclemmons authored Oct 27, 2021
1 parent 3985283 commit 3143def
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 48 deletions.
26 changes: 26 additions & 0 deletions .changeset/wet-candles-warn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
"@aws-amplify/ui-react": patch
---

AmplifyProvider accepts a partial list of primitives as `components`:

```js
const App = () => {
const {
components: { Heading },
} = useAmplify();

return <Heading>Howdy</Heading>;
};


<AmplifyProvider
components={{
Heading({ children }) {
return <h1>{children}</h1>;
},
}}
>
<App />
</AmplifyProvider>
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { render, screen } from '@testing-library/react';
import { useAmplify } from '../../../hooks';

import { AmplifyProvider } from '..';

const App = () => {
const {
components: { Heading },
} = useAmplify();

return <Heading>Howdy</Heading>;
};

describe('AmplifyProvider', () => {
it('does not require props', async () => {
render(
<AmplifyProvider>
<App />
</AmplifyProvider>
);

const heading = await screen.getByText('Howdy');
expect(heading.nodeName).toBe('H6');
});

it('wraps the App in [data-amplify-theme="default-theme"]', () => {
const { container } = render(
<AmplifyProvider>
<App />
</AmplifyProvider>
);

const wrapper = container.querySelector('[data-amplify-theme]');
expect(wrapper).toBeInTheDocument();
expect(wrapper).toHaveAttribute('data-amplify-theme', 'default-theme');
});

it('accepts custom primitives as components', async () => {
render(
<AmplifyProvider
components={{
Heading({ children }) {
return <h1>Custom {children}</h1>;
},
}}
>
<App />
</AmplifyProvider>
);

const heading = await screen.getByText('Custom Howdy');
expect(heading.nodeName).toBe('H1');
});
});
3 changes: 2 additions & 1 deletion packages/react/src/components/AmplifyProvider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { ReactNode } from 'react';

import { AmplifyContext } from './AmplifyContext';
import { defaultTheme, BrowserTheme } from '@aws-amplify/ui';
import * as primitives from '../../primitives';

export type ColorMode = 'system' | 'light' | 'dark';

interface AmplifyProviderProps {
children: ReactNode;
components: Record<string, ReactNode>;
components?: Partial<typeof primitives>;
theme?: BrowserTheme;
colorMode?: ColorMode;
}
Expand Down
57 changes: 10 additions & 47 deletions packages/react/src/hooks/useAmplify.tsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,18 @@
import { useContext } from 'react';
import * as React from 'react';

import { AmplifyContext } from '../components/AmplifyProvider/AmplifyContext';
import * as primitives from '../primitives';

export function useAmplify(namespace) {
const { components = {}, theme } = useContext(AmplifyContext);

const customComponents = Object.entries(components).reduce(
(acc, [namespaced, Component]) => {
// `Authenticator.SignIn.Button` => `Button`
const name = namespaced.split('.').pop();

// TODO `Authenticator.Button` should also override `Authenticator.SignIn.Button`? Maybe not...
// But wait, `Input` should override `Authenticator.Input`!
// if (namespaced === `${namespace}.${name}`) {
// TODO Support decorator pattern (e.g. `acc[name] = Component(InputPrimitive)`)
// TODO Pass in the previous component, not necessarily a primitive (e.g. SignIn?)
acc[name] = Component;
// }

return acc;
},
{}
);

// TODO `theme` should override `style` or `className`?

// const styledComponents = Object.entries(components).reduce(
// (acc, [name, Component]) => {
// // e.g. `Authenticator.Input` || `Input`
// // TODO Is this needed anymore? Maybe so for custom tailwind overrides!
// const className =
// custom.theme?.[`${namespace}.${name}`] || custom.theme?.[name];
// const namespaced = `${namespace}.${name}`;

// acc[name] =
// custom.components?.[namespaced] ||
// custom.components?.[name] ||
// Component;

// return acc;
// },
// {}
// );

return {
components: {
export function useAmplify() {
const context = React.useContext(AmplifyContext);
const { components: customComponents, theme } = context;
const components = React.useMemo(
() => ({
...primitives,
...customComponents,
},
}),
[customComponents]
);

theme,
};
return { components, theme };
}

0 comments on commit 3143def

Please sign in to comment.