Browse Source

Start tab component

main
GreatBearShark 2 years ago
parent
commit
bc8bf7426b
  1. 1
      package.json
  2. 97
      src/components/AutosizeTextArea.tsx
  3. 29
      src/components/Tabs.tsx
  4. 31
      src/components/user.tsx
  5. 6
      src/custom.css
  6. 54
      src/stories/Tabs.stories.tsx
  7. 2
      src/theme.tsx
  8. 36
      yarn.lock

1
package.json

@ -18,6 +18,7 @@
"@pika/react-dom": "^16.13.1",
"@reach/combobox": "^0.10.5",
"@reach/menu-button": "^0.10.5",
"@reach/tabs": "^0.11.2",
"@sentry/react": "^5.22.3",
"@theme-ui/color": "^0.3.1",
"@theme-ui/presets": "^0.3.0",

97
src/components/AutosizeTextArea.tsx

@ -7,36 +7,63 @@ import { Textarea } from 'theme-ui';
const getLineHeight = _getLineHeight as (element: HTMLElement) => number | null;
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace TextareaAutosize {
export type RequiredProps = Pick<
React.HTMLProps<HTMLTextAreaElement>,
Exclude<keyof React.HTMLProps<HTMLTextAreaElement>, 'ref'>
> & {
/** Called whenever the textarea resizes */
onResize?: (e: Event) => void;
/** Minimum number of visible rows */
rows?: React.HTMLProps<HTMLTextAreaElement>['rows'];
/** Maximum number of visible rows */
maxRows?: number;
/** Initialize `autosize` asynchronously.
* Enable it if you are using StyledComponents
* This is forced to true when `maxRows` is set.
*/
async?: boolean;
};
export type DefaultProps = {
rows: number;
async: boolean;
};
export type Props = RequiredProps & Partial<DefaultProps>;
export type State = {
lineHeight: number | null;
};
}
// export const TextareaAutosize {
// export type RequiredProps = Pick<
// React.HTMLProps<HTMLTextAreaElement>,
// Exclude<keyof React.HTMLProps<HTMLTextAreaElement>, 'ref'>
// > & {
// /** Called whenever the textarea resizes */
// onResize?: (e: Event) => void;
// /** Minimum number of visible rows */
// rows?: React.HTMLProps<HTMLTextAreaElement>['rows'];
// /** Maximum number of visible rows */
// maxRows?: number;
// /** Initialize `autosize` asynchronously.
// * Enable it if you are using StyledComponents
// * This is forced to true when `maxRows` is set.
// */
// async?: boolean;
// };
// export type DefaultProps = {
// rows: number;
// async: boolean;
// };
// export type Props = RequiredProps & Partial<DefaultProps>;
// export type State = {
// lineHeight: number | null;
// };
// }
export type RequiredProps = Pick<
React.HTMLProps<HTMLTextAreaElement>,
Exclude<keyof React.HTMLProps<HTMLTextAreaElement>, 'ref'>
> & {
/** Called whenever the textarea resizes */
onResize?: (e: Event) => void;
/** Minimum number of visible rows */
rows?: React.HTMLProps<HTMLTextAreaElement>['rows'];
/** Maximum number of visible rows */
maxRows?: number;
/** Initialize `autosize` asynchronously.
* Enable it if you are using StyledComponents
* This is forced to true when `maxRows` is set.
*/
async?: boolean;
};
export type DefaultProps = {
rows: number;
async: boolean;
};
export type Props = RequiredProps & Partial<DefaultProps>;
export type State = {
lineHeight: number | null;
};
const RESIZED = 'autosize:resized';
type InnerProps = TextareaAutosize.Props & {
type InnerProps = {
innerRef: React.Ref<HTMLTextAreaElement> | null;
};
@ -44,11 +71,8 @@ type InnerProps = TextareaAutosize.Props & {
* A light replacement for built-in textarea component
* which automaticaly adjusts its height to match the content
*/
class TextareaAutosizeClass extends React.Component<
InnerProps,
TextareaAutosize.State
> {
static defaultProps: TextareaAutosize.DefaultProps = {
class TextareaAutosizeClass extends React.Component<InnerProps, State> {
static defaultProps = {
rows: 1,
async: false,
};
@ -63,7 +87,7 @@ class TextareaAutosizeClass extends React.Component<
// async: PropTypes.bool
// };
state: TextareaAutosize.State = {
state: State = {
lineHeight: null,
};
@ -147,7 +171,7 @@ class TextareaAutosizeClass extends React.Component<
if (typeof this.props.innerRef === 'function') {
this.props.innerRef(element);
} else if (this.props.innerRef) {
(this.props.innerRef as any).current = element;
this.props.innerRef.current = element;
}
}}
>
@ -162,10 +186,7 @@ class TextareaAutosizeClass extends React.Component<
}
export const AutosizeTextArea = React.forwardRef(
(
props: TextareaAutosize.Props,
ref: React.Ref<HTMLTextAreaElement> | null
) => {
(props: Props, ref: React.Ref<HTMLTextAreaElement> | null) => {
return <TextareaAutosizeClass {...props} innerRef={ref} />;
}
);

29
src/components/Tabs.tsx

@ -0,0 +1,29 @@
import React from 'react';
import {
Tabs,
TabList as ReachTabList,
Tab as ReachTab,
TabPanels as ReachTabPanels,
TabPanel as ReachTabPanel,
} from '@reach/tabs';
import '@reach/tabs/styles.css';
import Block from './elements/Block';
import { Box } from 'theme-ui';
import styled from 'styled-components';
export const TabList = props => (
<Box as={ReachTabList} bg="background" {...props} />
);
export const Tab = props => (
<Box
as={ReachTab}
css={{ height: '54px', fontSize: '14px', fontWeight: '600' }}
color="text"
{...props}
/>
);
export const TabPanels = props => <Box as={ReachTabPanels} {...props} />;
export const TabPanel = props => <Box as={ReachTabPanel} {...props} />;

31
src/components/user.tsx

@ -53,6 +53,8 @@ import { Box, Checkbox, Heading, Input, Label, Select, Text } from 'theme-ui';
import Block from './elements/Block';
import Card from './elements/Card';
import StyledLink from '../StyledLink';
import { Tabs } from '@reach/tabs';
import { Tab, TabList, TabPanel, TabPanels } from './Tabs';
// import { Button } from 'theme-ui';
// import { changeTheme } from './ThemeSystemProvider';
@ -333,6 +335,25 @@ class BaseUser extends Component<any, UserState> {
viewRadios() {
return (
<div className="btn-group btn-group-toggle">
<Tabs>
<TabList>
<Tab>Overview</Tab>
<Tab>Comments</Tab>
<Tab>Posts</Tab>
<Tab>Saved</Tab>
</TabList>
<TabPanels>
<TabPanel>
<p>one!</p>
</TabPanel>
<TabPanel>
<p>two!</p>
</TabPanel>
<TabPanel>
<p>three!</p>
</TabPanel>
</TabPanels>
</Tabs>
<Button
as="label"
variant={
@ -629,7 +650,6 @@ class BaseUser extends Component<any, UserState> {
<Select
value={this.state.userSettingsForm.lang}
onChange={linkEvent(this, this.handleUserSettingsLangChange)}
ml={2}
>
<option disabled>{i18n.t('language')}</option>
<option value="browser">{i18n.t('browser_default')}</option>
@ -678,7 +698,6 @@ class BaseUser extends Component<any, UserState> {
<Input
type="email"
id="user-email"
className="form-control"
placeholder={i18n.t('optional')}
value={this.state.userSettingsForm.email}
onInput={linkEvent(this, this.handleUserSettingsEmailChange)}
@ -695,7 +714,6 @@ class BaseUser extends Component<any, UserState> {
<div className="col-lg-7">
<Input
type="text"
className="form-control"
placeholder="@user:example.com"
value={this.state.userSettingsForm.matrix_user_id}
onInput={linkEvent(
@ -717,7 +735,6 @@ class BaseUser extends Component<any, UserState> {
<Input
type="password"
id="user-password"
className="form-control"
value={this.state.userSettingsForm.new_password}
autoComplete="new-password"
onInput={linkEvent(
@ -738,7 +755,6 @@ class BaseUser extends Component<any, UserState> {
<Input
type="password"
id="user-verify-password"
className="form-control"
value={this.state.userSettingsForm.new_password_verify}
autoComplete="new-password"
onInput={linkEvent(
@ -759,7 +775,6 @@ class BaseUser extends Component<any, UserState> {
<Input
type="password"
id="user-old-password"
className="form-control"
value={this.state.userSettingsForm.old_password}
autoComplete="new-password"
onInput={linkEvent(
@ -843,7 +858,7 @@ class BaseUser extends Component<any, UserState> {
<div className="my-2 alert alert-danger" role="alert">
{i18n.t('delete_account_confirm')}
</div>
<input
<Input
type="password"
value={this.state.deleteAccountForm.password}
autoComplete="new-password"
@ -851,7 +866,7 @@ class BaseUser extends Component<any, UserState> {
this,
this.handleDeleteAccountPasswordChange
)}
className="form-control my-2"
className="my-2"
/>
<Button
variant="danger"

6
src/custom.css

@ -722,7 +722,7 @@ a.text-body {
@media (max-width: 768px) {
.user-settings-container {
flex-direction: column-reverse;
/* flex-direction: column-reverse; */
}
}
@ -869,4 +869,8 @@ button:hover [type="button"]:hover {
a:hover {
/* text-decoration: none; */
color: inherit;
}
[data-reach-tab][data-selected] {
border-bottom: 4px solid #F471C8;
}

54
src/stories/Tabs.stories.tsx

@ -0,0 +1,54 @@
import React, { useState } from 'react';
import {
Box,
Label,
Input,
Select,
Textarea,
Radio,
Flex,
Checkbox,
Slider,
Text,
} from 'theme-ui';
import { ThemeSystemProvider } from '../components/ThemeSystemProvider';
import { themes } from '../theme';
import { Tabs } from '@reach/tabs';
import { Tab, TabList, TabPanel, TabPanels } from '../components/Tabs';
export default { title: 'Tabs' };
export const Basic = () => {
return (
<div>
{Object.keys(themes).map(theme => {
return (
<ThemeSystemProvider key={theme} initialTheme={theme}>
<Tabs>
<TabList>
<Tab>Overview</Tab>
<Tab>Comments</Tab>
<Tab>Posts</Tab>
<Tab>Saved</Tab>
</TabList>
<TabPanels>
<TabPanel>
<Text>Overview</Text>
</TabPanel>
<TabPanel>
<Text>Comments</Text>
</TabPanel>
<TabPanel>
<Text>Posts</Text>
</TabPanel>
<TabPanel>
<Text>Saved</Text>
</TabPanel>
</TabPanels>
</Tabs>
</ThemeSystemProvider>
);
})}
</div>
);
};

2
src/theme.tsx

@ -165,6 +165,8 @@ export const variants: any = {
const defaultTheme: ThemeProviderProps<Theme> = {
...dark,
useCustomProperties: true,
useBodyStyles: true,
fonts: {
body:
'Lato, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif',

36
yarn.lock

@ -1746,6 +1746,14 @@
"@reach/utils" "0.10.5"
tslib "^2.0.0"
"@reach/[email protected]":
version "0.11.2"
resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.11.2.tgz#c66a905c5401d1ac3da8d26165b8d27d6e778fa6"
integrity sha512-YZ21b0Kb88wJ0t7QjSznWOYskARQMnmXY9Y2XZ5RyYcZ2krT4s3+ghghpfaPs6BKcrZDonZCrU65OFDJPa1jAw==
dependencies:
"@reach/utils" "0.11.2"
tslib "^2.0.0"
"@reach/[email protected]^0.10.5":
version "0.10.5"
resolved "https://registry.yarnpkg.com/@reach/combobox/-/combobox-0.10.5.tgz#60e442ee7d1c63022cc3079e1aa4713aa1d398d4"
@ -1768,6 +1776,14 @@
"@reach/utils" "0.10.5"
tslib "^2.0.0"
"@reach/[email protected]":
version "0.11.2"
resolved "https://registry.yarnpkg.com/@reach/descendants/-/descendants-0.11.2.tgz#49ea1b5eb91aba8ae6dce57f6575c38aff1f9756"
integrity sha512-63Wdx32/RyjGRJc4UZKK7F1sIrb6jeGkDwvQH0hv0lRAhEjsiSQ1t2JTYDml3testFP48J0B2xS7JzNeY0zoQw==
dependencies:
"@reach/utils" "0.11.2"
tslib "^2.0.0"
"@reach/[email protected]^0.10.5":
version "0.10.5"
resolved "https://registry.yarnpkg.com/@reach/menu-button/-/menu-button-0.10.5.tgz#b023044fa199bc256572830740049a50fea1d690"
@ -1824,6 +1840,17 @@
prop-types "^15.6.1"
react-lifecycles-compat "^3.0.4"
"@reach/[email protected]^0.11.2":
version "0.11.2"
resolved "https://registry.yarnpkg.com/@reach/tabs/-/tabs-0.11.2.tgz#75a73d069ff4832259a191e7e321818c9d09a2c8"
integrity sha512-iVDXfmdpJmBavyyiJbm9sUddlelra+x5MaF5Y4QwV7Q+w3t9RLqTePQAOX+2MX0BJgvasX/YItMBO2JumWxGPQ==
dependencies:
"@reach/auto-id" "0.11.2"
"@reach/descendants" "0.11.2"
"@reach/utils" "0.11.2"
prop-types "^15.7.2"
tslib "^2.0.0"
"@reach/[email protected]":
version "0.10.5"
resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.10.5.tgz#fbac944d29565f6dd7abd0e1b13950e99b1e470b"
@ -1833,6 +1860,15 @@
tslib "^2.0.0"
warning "^4.0.3"
"@reach/[email protected]":
version "0.11.2"
resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.11.2.tgz#be1f03650db56fd67a16d3fc70e5262cdb139cec"
integrity sha512-fBTolYj+rKTROXmf0zHO0rCWSvw7J0ALmYj5QxW4DmITMOH5uyRuWDWOfqohIGFbOtF/sum50WTB3tvx76d+Aw==
dependencies:
"@types/warning" "^3.0.0"
tslib "^2.0.0"
warning "^4.0.3"
"@rollup/[email protected]^14.0.0":
version "14.0.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-14.0.0.tgz#4285f9ec2db686a31129e5a2b415c94aa1f836f0"

Loading…
Cancel
Save