Skip to content

Commit

Permalink
feat: fix theming, make it easier, add docs
Browse files Browse the repository at this point in the history
  • Loading branch information
jrea committed Apr 11, 2022
1 parent 7ee002d commit 7953e55
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 24 deletions.
31 changes: 28 additions & 3 deletions packages/react/src/components/LoginForm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ A basic email and password login form.
Assumes a `<NileProvider />` in a higher order component

```javascript
function SignIn() {
function LoginForm() {
return (
<>
<h1>🤩 My Great App🤩</h1>
Expand All @@ -20,10 +20,35 @@ function SignIn() {
</>
);
}

React.render('root', <MyApp />);
```

## Theming

### General theming (recommended)

[theming](../../theme/README.md)

### Advanced theming

The labels and inputs of this form are customizable via props. You can pass any `React.Node` to it, but at a minimum you must use the passed `id` prop to ensure submission works properly. For completeness, spread all provided props input `<input />` or `<label />`and override as necessary.

```typescript
import { LoginForm, LabelOverride, InputOverride } from '@theniledev/react';

const EmailLabel = (props: LabelOverride) => {
return (
<label {...props} htmlFor="fancyName">
Not an email
</label>
);
};

const EmailInput = (props: InputOverride) => (
<>
<img src="/fancy-name.svg" alt="fancy name" />
<input {...props} type="email" name="fancyName" placeholder="Email" />
</>
);

<LoginForm emailLabel={EmailLabel} emailInput={EmailInput} />;
```
2 changes: 1 addition & 1 deletion packages/react/src/components/LoginForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function LoginForm(props: Props) {
alert('things went bad');
});
if (success) {
handleSuccess && handleSuccess();
handleSuccess && handleSuccess(payload);
}
}

Expand Down
13 changes: 8 additions & 5 deletions packages/react/src/components/LoginForm/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
type LoginSuccess = (LoginInfo: { email: string; password: string }) => void;
import { LabelOverride, InputOverride } from '../../theme';

export interface Props {
handleSuccess: () => void;
emailLabel?: React.ReactNode;
handleSuccess: LoginSuccess;
emailLabel?: React.ReactNode | LabelOverride;
button?: React.ReactNode;
emailInput?: React.ReactNode;
passwordLabel?: React.ReactNode;
passwordInput?: React.ReactNode;
emailInput?: React.ReactNode | InputOverride;
passwordLabel?: React.ReactNode | LabelOverride;
passwordInput?: React.ReactNode | InputOverride;
}
38 changes: 32 additions & 6 deletions packages/react/src/components/SignUpForm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,50 @@ A basic email and password signup form.

Assumes a `<NileProvider />` in a higher order component

```javascript
function SignIn() {
```typescript
import { SignUpForm } from '@theniledev/react';
function SignUp() {
return (
<>
<h1>🤩 My Great App🤩</h1>
<h2>Sign in</h2>
<LoginForm
<SignUpForm
handleSuccess={() => {
// redirect to user profile
// redirect to log in page
}}
/>
</>
);
}

React.render('root', <MyApp />);
```

## Theming

### General theming (recommended)

[theming](../../theme/README.md)

### Advanced theming

The labels and inputs of this form are customizable via props. You can pass any `React.Node` to it, but at a minimum you must use the passed `id` prop to ensure submission works properly. For completeness, spread all provided props input `<input />` or `<label />`and override as necessary.

```typescript
import { SignUpForm, LabelOverride, InputOverride } from '@theniledev/react';

const EmailLabel = (props: LabelOverride) => {
return (
<label {...props} htmlFor="fancyName">
Not an email
</label>
);
};

const EmailInput = (props: InputOverride) => (
<>
<img src="/fancy-name.svg" alt="fancy name" />
<input {...props} type="email" name="fancyName" placeholder="Email" />
</>
);

<SignUpForm emailLabel={EmailLabel} emailInput={EmailInput} />;
```
2 changes: 1 addition & 1 deletion packages/react/src/components/SignUpForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default function SignUpForm(props: Props) {
};

await nile.createUser(payload).catch(() => alert('things went bad'));
handleSuccess && handleSuccess();
handleSuccess && handleSuccess(payload);
}

return (
Expand Down
13 changes: 8 additions & 5 deletions packages/react/src/components/SignUpForm/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
type SignInSuccess = (loginInfo: { email: string; password: string }) => void;
import { LabelOverride, InputOverride } from '../../theme';

export interface Props {
handleSuccess: () => void;
emailLabel?: React.ReactNode;
handleSuccess: SignInSuccess;
emailLabel?: React.ReactNode | LabelOverride;
button?: React.ReactNode;
emailInput?: React.ReactNode;
passwordLabel?: React.ReactNode;
passwordInput?: React.ReactNode;
emailInput?: React.ReactNode | InputOverride;
passwordLabel?: React.ReactNode | LabelOverride;
passwordInput?: React.ReactNode | InputOverride;
}
22 changes: 20 additions & 2 deletions packages/react/src/components/_Themeable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,17 @@ export function Input({
node: React.ReactNode;
}) {
const theme = useTheme(name);
if (node === null) {
return null;
}

const props = { id: name };

if (typeof node === 'function') {
return node(props);
}

if (React.isValidElement(node)) {
const props = { id: name };
return React.cloneElement(node, props);
}

Expand All @@ -30,8 +39,17 @@ export function Label({
node: React.ReactNode;
}) {
const theme = useTheme(htmlFor);
if (node === null) {
return null;
}

const props = { htmlFor };

if (typeof node === 'function') {
return node(props);
}

if (React.isValidElement(node)) {
const props = { htmlFor };
return React.cloneElement(node, props);
}

Expand Down
1 change: 1 addition & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { default as LoginForm } from './components/LoginForm';
export { default as SignUpForm } from './components/SignUpForm';

export { NileProvider, useNile } from './context';
export { LabelOverride, InputOverride } from './theme';
4 changes: 3 additions & 1 deletion packages/react/src/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ const ThemeConfig = {
email: 'email',
password: 'password',
signupButton: 'signupButton',
loginButton: 'loginButon',
loginButton: 'loginButton',
};

export type InputThemeName = 'email' | 'password';
export type ButtonThemeName = 'signupButton' | 'loginButton';
export type LabelOverride = (props: { htmlFor: string }) => React.ReactNode;
export type InputOverride = (props: { id: string }) => React.ReactNode;

export const useTheme = (name: InputThemeName | ButtonThemeName) => {
const contextTheme = useNileContextTheme();
Expand Down

0 comments on commit 7953e55

Please sign in to comment.