style(dashboard-v2): prettify

This commit is contained in:
Michał Leszczyk 2022-02-18 09:20:47 +01:00
parent 02b3b814f0
commit d385f9e689
No known key found for this signature in database
GPG Key ID: FA123CA8BAA2FBF4
71 changed files with 576 additions and 576 deletions

View File

@ -2,5 +2,5 @@ module.exports = {
globals: { globals: {
__PATH_PREFIX__: true, __PATH_PREFIX__: true,
}, },
extends: ['react-app', 'plugin:storybook/recommended'], extends: ["react-app", "plugin:storybook/recommended"],
} };

View File

@ -1,18 +1,18 @@
module.exports = { module.exports = {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], stories: ["../src/**/*.stories.@(js|jsx|ts|tsx)"],
addons: [ addons: [
'@storybook/addon-links', "@storybook/addon-links",
'@storybook/addon-essentials', "@storybook/addon-essentials",
{ {
name: '@storybook/addon-postcss', name: "@storybook/addon-postcss",
options: { options: {
postcssLoaderOptions: { postcssLoaderOptions: {
implementation: require('postcss'), implementation: require("postcss"),
}, },
}, },
}, },
], ],
core: { core: {
builder: 'webpack5', builder: "webpack5",
}, },
} };

View File

@ -1,20 +1,20 @@
import 'tailwindcss/tailwind.css' import "tailwindcss/tailwind.css";
import '@fontsource/sora/300.css' // light import "@fontsource/sora/300.css"; // light
import '@fontsource/sora/400.css' // normal import "@fontsource/sora/400.css"; // normal
import '@fontsource/sora/500.css' // medium import "@fontsource/sora/500.css"; // medium
import '@fontsource/sora/600.css' // semibold import "@fontsource/sora/600.css"; // semibold
import '@fontsource/source-sans-pro/400.css' // normal import "@fontsource/source-sans-pro/400.css"; // normal
import '@fontsource/source-sans-pro/600.css' // semibold import "@fontsource/source-sans-pro/600.css"; // semibold
import '../src/styles/global.css' import "../src/styles/global.css";
export const parameters = { export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' }, actions: { argTypesRegex: "^on[A-Z].*" },
controls: { controls: {
matchers: { matchers: {
color: /(background|color)$/i, color: /(background|color)$/i,
date: /Date$/, date: /Date$/,
}, },
}, },
layout: 'fullscreen', layout: "fullscreen",
} };

View File

@ -1,3 +1,3 @@
module.exports = { module.exports = {
plugins: [require('tailwindcss/nesting'), require('tailwindcss'), require('autoprefixer')], plugins: [require("tailwindcss/nesting"), require("tailwindcss"), require("autoprefixer")],
} };

View File

@ -1,4 +1,4 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
/** /**
* Primary UI component for user interaction * Primary UI component for user interaction
@ -8,13 +8,13 @@ export const Button = ({ primary, label, ...props }) => {
<button <button
type="button" type="button"
className={`min-w-button min-h-button rounded-full font-sans uppercase tracking-wide text-button className={`min-w-button min-h-button rounded-full font-sans uppercase tracking-wide text-button
${primary ? 'bg-primary' : 'bg-white border-2 border-black'}`} ${primary ? "bg-primary" : "bg-white border-2 border-black"}`}
{...props} {...props}
> >
{label} {label}
</button> </button>
) );
} };
Button.propTypes = { Button.propTypes = {
/** /**
@ -33,9 +33,9 @@ Button.propTypes = {
* Optional click handler * Optional click handler
*/ */
onClick: PropTypes.func, onClick: PropTypes.func,
} };
Button.defaultProps = { Button.defaultProps = {
primary: false, primary: false,
onClick: undefined, onClick: undefined,
} };

View File

@ -1,38 +1,38 @@
import { Button } from './Button' import { Button } from "./Button";
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default { export default {
title: 'SkynetLibrary/Button', title: "SkynetLibrary/Button",
component: Button, component: Button,
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
argTypes: { argTypes: {
backgroundColor: { control: 'color' }, backgroundColor: { control: "color" },
}, },
} };
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Template = (args) => <Button {...args} /> const Template = (args) => <Button {...args} />;
export const Primary = Template.bind({}) export const Primary = Template.bind({});
// More on args: https://storybook.js.org/docs/react/writing-stories/args // More on args: https://storybook.js.org/docs/react/writing-stories/args
Primary.args = { Primary.args = {
primary: true, primary: true,
label: 'Button', label: "Button",
} };
export const Secondary = Template.bind({}) export const Secondary = Template.bind({});
Secondary.args = { Secondary.args = {
label: 'Button', label: "Button",
} };
export const Large = Template.bind({}) export const Large = Template.bind({});
Large.args = { Large.args = {
size: 'large', size: "large",
label: 'Button', label: "Button",
} };
export const Small = Template.bind({}) export const Small = Template.bind({});
Small.args = { Small.args = {
size: 'small', size: "small",
label: 'Button', label: "Button",
} };

View File

@ -1 +1 @@
export * from './Button' export * from "./Button";

View File

@ -1,9 +1,9 @@
import { useRef, useState } from 'react' import { useRef, useState } from "react";
import { useClickAway } from 'react-use' import { useClickAway } from "react-use";
import PropTypes from 'prop-types' import PropTypes from "prop-types";
import styled, { css, keyframes } from 'styled-components' import styled, { css, keyframes } from "styled-components";
import { ChevronDownIcon } from '../Icons' import { ChevronDownIcon } from "../Icons";
const dropDown = keyframes` const dropDown = keyframes`
0% { 0% {
@ -15,39 +15,39 @@ const dropDown = keyframes`
100% { 100% {
transform: scaleY(1); transform: scaleY(1);
} }
` `;
const Container = styled.div.attrs({ className: `relative inline-flex` })`` const Container = styled.div.attrs({ className: `relative inline-flex` })``;
const Trigger = styled.button.attrs({ const Trigger = styled.button.attrs({
className: 'flex items-center', className: "flex items-center",
})`` })``;
const TriggerIcon = styled(ChevronDownIcon).attrs({ const TriggerIcon = styled(ChevronDownIcon).attrs({
className: 'transition-transform text-primary', className: "transition-transform text-primary",
})` })`
transform: ${({ open }) => (open ? 'rotateX(180deg)' : 'none')}; transform: ${({ open }) => (open ? "rotateX(180deg)" : "none")};
` `;
const Flyout = styled.div.attrs(({ open }) => ({ const Flyout = styled.div.attrs(({ open }) => ({
className: `absolute top-full right-0 p-0 className: `absolute top-full right-0 p-0
border rounded border-palette-100 border rounded border-palette-100
bg-white shadow-md shadow-palette-200/50 bg-white shadow-md shadow-palette-200/50
${open ? 'visible' : 'invisible'}`, ${open ? "visible" : "invisible"}`,
}))` }))`
animation: ${({ open }) => animation: ${({ open }) =>
open open
? css` ? css`
${dropDown} 0.1s ease-in-out ${dropDown} 0.1s ease-in-out
` `
: 'none'}; : "none"};
` `;
export const DropdownMenu = ({ title, children }) => { export const DropdownMenu = ({ title, children }) => {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false);
const menuRef = useRef() const menuRef = useRef();
useClickAway(menuRef, () => setOpen(false)) useClickAway(menuRef, () => setOpen(false));
return ( return (
<Container ref={menuRef}> <Container ref={menuRef}>
@ -56,10 +56,10 @@ export const DropdownMenu = ({ title, children }) => {
</Trigger> </Trigger>
<Flyout open={open}>{children}</Flyout> <Flyout open={open}>{children}</Flyout>
</Container> </Container>
) );
} };
DropdownMenu.propTypes = { DropdownMenu.propTypes = {
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
children: PropTypes.node.isRequired, children: PropTypes.node.isRequired,
} };

View File

@ -1,25 +1,25 @@
import { Panel } from '../Panel' import { Panel } from "../Panel";
import { DropdownMenu, DropdownMenuLink } from '.' import { DropdownMenu, DropdownMenuLink } from ".";
import { CogIcon, LockClosedIcon } from '../Icons' import { CogIcon, LockClosedIcon } from "../Icons";
export default { export default {
title: 'SkynetLibrary/DropdownMenu', title: "SkynetLibrary/DropdownMenu",
component: DropdownMenu, component: DropdownMenu,
subcomponents: { subcomponents: {
DropdownMenuLink, DropdownMenuLink,
}, },
decorators: [ decorators: [
(Story) => ( (Story) => (
<Panel style={{ margin: 50, textAlign: 'center' }}> <Panel style={{ margin: 50, textAlign: "center" }}>
<Story /> <Story />
</Panel> </Panel>
), ),
], ],
} };
export const NavigationDropdown = () => ( export const NavigationDropdown = () => (
<DropdownMenu title="My account"> <DropdownMenu title="My account">
<DropdownMenuLink href="/settings" icon={CogIcon} label="Settings" active /> <DropdownMenuLink href="/settings" icon={CogIcon} label="Settings" active />
<DropdownMenuLink href="/logout" icon={LockClosedIcon} label="Log out" /> <DropdownMenuLink href="/logout" icon={LockClosedIcon} label="Log out" />
</DropdownMenu> </DropdownMenu>
) );

View File

@ -1,25 +1,25 @@
import styled from 'styled-components' import styled from "styled-components";
import PropTypes from 'prop-types' import PropTypes from "prop-types";
const DropdownLink = styled.a.attrs({ const DropdownLink = styled.a.attrs({
className: `m-0 border-t border-palette-200/50 h-[60px] className: `m-0 border-t border-palette-200/50 h-[60px]
whitespace-nowrap transition-colors text-current whitespace-nowrap transition-colors text-current
hover:bg-palette-100/50 flex items-center hover:bg-palette-100/50 flex items-center
pr-8 pl-6 py-4 gap-4 first:border-0`, pr-8 pl-6 py-4 gap-4 first:border-0`,
})`` })``;
export const DropdownMenuLink = ({ active, icon: Icon, label, ...props }) => ( export const DropdownMenuLink = ({ active, icon: Icon, label, ...props }) => (
<> <>
<DropdownLink {...props}> <DropdownLink {...props}>
{Icon ? <Icon className={active ? 'text-primary' : 'text-current'} /> : null} {Icon ? <Icon className={active ? "text-primary" : "text-current"} /> : null}
{label} {label}
</DropdownLink> </DropdownLink>
</> </>
) );
DropdownMenuLink.propTypes = { DropdownMenuLink.propTypes = {
label: PropTypes.oneOfType([PropTypes.node, PropTypes.string]).isRequired, label: PropTypes.oneOfType([PropTypes.node, PropTypes.string]).isRequired,
active: PropTypes.bool, active: PropTypes.bool,
icon: PropTypes.func, icon: PropTypes.func,
children: PropTypes.node.isRequired, children: PropTypes.node.isRequired,
} };

View File

@ -1,2 +1,2 @@
export * from './DropdownMenu' export * from "./DropdownMenu";
export * from './DropdownMenuLink' export * from "./DropdownMenuLink";

View File

@ -1,4 +1,4 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
/** /**
* Primary UI component for user interaction * Primary UI component for user interaction
@ -8,30 +8,30 @@ export const IconButton = ({ primary, size, icon, ...props }) => {
<button <button
type="button" type="button"
className={`${ className={`${
size === 'small' size === "small"
? 'h-iconButtonSm w-buttonIconSm' ? "h-iconButtonSm w-buttonIconSm"
: size === 'large' : size === "large"
? 'h-iconButtonLg w-iconButtonLg' ? "h-iconButtonLg w-iconButtonLg"
: 'w-iconButton h-iconButton' : "w-iconButton h-iconButton"
} rounded-full } rounded-full
inline-flex justify-center items-center inline-flex justify-center items-center
${primary ? 'bg-primary' : null}`} ${primary ? "bg-primary" : null}`}
{...props} {...props}
> >
<div <div
className={ className={
size === 'small' size === "small"
? 'h-buttonIconSm w-buttonIconSm' ? "h-buttonIconSm w-buttonIconSm"
: size === 'large' : size === "large"
? 'h-buttonIconLg w-buttonIconLg' ? "h-buttonIconLg w-buttonIconLg"
: 'h-buttonIcon w-buttonIcon' : "h-buttonIcon w-buttonIcon"
} }
> >
{icon} {icon}
</div> </div>
</button> </button>
) );
} };
IconButton.propTypes = { IconButton.propTypes = {
/** /**
@ -41,7 +41,7 @@ IconButton.propTypes = {
/** /**
* How large should the button be? * How large should the button be?
*/ */
size: PropTypes.oneOf(['small', 'medium', 'large']), size: PropTypes.oneOf(["small", "medium", "large"]),
/** /**
* Icon component * Icon component
*/ */
@ -50,11 +50,11 @@ IconButton.propTypes = {
* Optional click handler * Optional click handler
*/ */
onClick: PropTypes.func, onClick: PropTypes.func,
} };
IconButton.defaultProps = { IconButton.defaultProps = {
backgroundColor: null, backgroundColor: null,
primary: false, primary: false,
size: 'medium', size: "medium",
onClick: undefined, onClick: undefined,
} };

View File

@ -1,39 +1,39 @@
import { IconButton } from './IconButton' import { IconButton } from "./IconButton";
import { ArrowRightIcon } from '../Icons' import { ArrowRightIcon } from "../Icons";
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default { export default {
title: 'SkynetLibrary/IconButton', title: "SkynetLibrary/IconButton",
component: IconButton, component: IconButton,
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
argTypes: { argTypes: {
backgroundColor: { control: 'color' }, backgroundColor: { control: "color" },
}, },
} };
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Template = (args) => <IconButton {...args} /> const Template = (args) => <IconButton {...args} />;
export const Primary = Template.bind({}) export const Primary = Template.bind({});
// More on args: https://storybook.js.org/docs/react/writing-stories/args // More on args: https://storybook.js.org/docs/react/writing-stories/args
Primary.args = { Primary.args = {
primary: true, primary: true,
icon: <ArrowRightIcon />, icon: <ArrowRightIcon />,
} };
export const Secondary = Template.bind({}) export const Secondary = Template.bind({});
Secondary.args = { Secondary.args = {
icon: <ArrowRightIcon />, icon: <ArrowRightIcon />,
} };
export const Large = Template.bind({}) export const Large = Template.bind({});
Large.args = { Large.args = {
size: 'large', size: "large",
icon: <ArrowRightIcon />, icon: <ArrowRightIcon />,
} };
export const Small = Template.bind({}) export const Small = Template.bind({});
Small.args = { Small.args = {
size: 'small', size: "small",
icon: <ArrowRightIcon />, icon: <ArrowRightIcon />,
} };

View File

@ -1 +1 @@
export * from './IconButton' export * from "./IconButton";

View File

@ -1,4 +1,4 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
/** /**
* Primary UI component for user interaction * Primary UI component for user interaction
@ -10,15 +10,15 @@ export const IconButtonText = ({ primary, label, icon, ...props }) => {
className={`flex justify-center items-center w-iconButtonTextWidth py-iconButtonTextY`} className={`flex justify-center items-center w-iconButtonTextWidth py-iconButtonTextY`}
{...props} {...props}
> >
<div className={`h-buttonTextIcon w-buttonTextIcon ${primary ? 'text-primary' : 'text-palette-600'}`}>{icon}</div> <div className={`h-buttonTextIcon w-buttonTextIcon ${primary ? "text-primary" : "text-palette-600"}`}>{icon}</div>
<p <p
className={'ml-iconButtonTextTextLeft tracking-wide text-iconButtonText font-sans font-light text-palette-600'} className={"ml-iconButtonTextTextLeft tracking-wide text-iconButtonText font-sans font-light text-palette-600"}
> >
{label} {label}
</p> </p>
</button> </button>
) );
} };
IconButtonText.propTypes = { IconButtonText.propTypes = {
/** /**
@ -37,10 +37,10 @@ IconButtonText.propTypes = {
* Optional click handler * Optional click handler
*/ */
onClick: PropTypes.func, onClick: PropTypes.func,
} };
IconButtonText.defaultProps = { IconButtonText.defaultProps = {
primary: false, primary: false,
label: '', label: "",
onClick: undefined, onClick: undefined,
} };

View File

@ -1,29 +1,29 @@
import { IconButtonText } from './IconButtonText' import { IconButtonText } from "./IconButtonText";
import { CogIcon } from '../Icons' import { CogIcon } from "../Icons";
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default { export default {
title: 'SkynetLibrary/IconButtonText', title: "SkynetLibrary/IconButtonText",
component: IconButtonText, component: IconButtonText,
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
argTypes: { argTypes: {
backgroundColor: { control: 'color' }, backgroundColor: { control: "color" },
}, },
} };
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Template = (args) => <IconButtonText {...args} /> const Template = (args) => <IconButtonText {...args} />;
export const Primary = Template.bind({}) export const Primary = Template.bind({});
// More on args: https://storybook.js.org/docs/react/writing-stories/args // More on args: https://storybook.js.org/docs/react/writing-stories/args
Primary.args = { Primary.args = {
primary: true, primary: true,
label: 'Settings', label: "Settings",
icon: <CogIcon />, icon: <CogIcon />,
} };
export const Secondary = Template.bind({}) export const Secondary = Template.bind({});
Secondary.args = { Secondary.args = {
label: 'Settings', label: "Settings",
icon: <CogIcon />, icon: <CogIcon />,
} };

View File

@ -1 +1 @@
export * from './IconButtonText' export * from "./IconButtonText";

View File

@ -1,8 +1,8 @@
import { Panel } from '../Panel' import { Panel } from "../Panel";
import * as icons from '.' import * as icons from ".";
export default { export default {
title: 'SkynetLibrary/Icons', title: "SkynetLibrary/Icons",
decorators: [ decorators: [
(Story) => ( (Story) => (
<div style={{ margin: 50 }}> <div style={{ margin: 50 }}>
@ -10,14 +10,14 @@ export default {
</div> </div>
), ),
], ],
} };
export const DefaultSizeIcon = () => <icons.SkynetLogoIcon /> export const DefaultSizeIcon = () => <icons.SkynetLogoIcon />;
export const LargeIcon = () => <icons.SkynetLogoIcon size={60} /> export const LargeIcon = () => <icons.SkynetLogoIcon size={60} />;
export const AllIcons = () => { export const AllIcons = () => {
const sizes = [24, 32, 60] const sizes = [24, 32, 60];
return ( return (
<> <>
@ -25,7 +25,7 @@ export const AllIcons = () => {
<Panel key={`panel-${iconName}`}> <Panel key={`panel-${iconName}`}>
<pre>{iconName}</pre> <pre>{iconName}</pre>
<div style={{ padding: 10, border: '1px dashed #fafafa', display: 'flex', alignItems: 'center', gap: 50 }}> <div style={{ padding: 10, border: "1px dashed #fafafa", display: "flex", alignItems: "center", gap: 50 }}>
{sizes.map((size) => ( {sizes.map((size) => (
<IconComponent key={`${iconName}-${size}`} size={size} /> <IconComponent key={`${iconName}-${size}`} size={size} />
))} ))}
@ -33,5 +33,5 @@ export const AllIcons = () => {
</Panel> </Panel>
))} ))}
</> </>
) );
} };

View File

@ -1,4 +1,4 @@
import { withIconProps } from '../withIconProps' import { withIconProps } from "../withIconProps";
export const ArrowRightIcon = withIconProps(({ size, ...props }) => ( export const ArrowRightIcon = withIconProps(({ size, ...props }) => (
<svg width={size} height={size} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" {...props}> <svg width={size} height={size} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" {...props}>
@ -8,4 +8,4 @@ export const ArrowRightIcon = withIconProps(({ size, ...props }) => (
fillRule="nonzero" fillRule="nonzero"
/> />
</svg> </svg>
)) ));

View File

@ -1,4 +1,4 @@
import { withIconProps } from '../withIconProps' import { withIconProps } from "../withIconProps";
export const ChevronDownIcon = withIconProps(({ size, ...props }) => ( export const ChevronDownIcon = withIconProps(({ size, ...props }) => (
<svg width={size} height={size} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" {...props}> <svg width={size} height={size} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" {...props}>
@ -11,4 +11,4 @@ export const ChevronDownIcon = withIconProps(({ size, ...props }) => (
strokeLinejoin="round" strokeLinejoin="round"
/> />
</svg> </svg>
)) ));

View File

@ -1,4 +1,4 @@
import { withIconProps } from '../withIconProps' import { withIconProps } from "../withIconProps";
export const CogIcon = withIconProps(({ size, ...props }) => ( export const CogIcon = withIconProps(({ size, ...props }) => (
<svg width={size} height={size} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" {...props}> <svg width={size} height={size} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" {...props}>
@ -8,4 +8,4 @@ export const CogIcon = withIconProps(({ size, ...props }) => (
fillRule="nonzero" fillRule="nonzero"
/> />
</svg> </svg>
)) ));

View File

@ -1,4 +1,4 @@
import { withIconProps } from '../withIconProps' import { withIconProps } from "../withIconProps";
export const InfoIcon = withIconProps(({ size, ...props }) => ( export const InfoIcon = withIconProps(({ size, ...props }) => (
<svg width={size} height={size} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" {...props}> <svg width={size} height={size} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" {...props}>
@ -8,4 +8,4 @@ export const InfoIcon = withIconProps(({ size, ...props }) => (
fillRule="nonzero" fillRule="nonzero"
/> />
</svg> </svg>
)) ));

View File

@ -1,4 +1,4 @@
import { withIconProps } from '../withIconProps' import { withIconProps } from "../withIconProps";
export const LockClosedIcon = withIconProps(({ size, ...props }) => ( export const LockClosedIcon = withIconProps(({ size, ...props }) => (
<svg width={size} height={size} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" {...props}> <svg width={size} height={size} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" {...props}>
@ -8,4 +8,4 @@ export const LockClosedIcon = withIconProps(({ size, ...props }) => (
fillRule="nonzero" fillRule="nonzero"
/> />
</svg> </svg>
)) ));

View File

@ -1,8 +1,8 @@
import { withIconProps } from '../withIconProps' import { withIconProps } from "../withIconProps";
export const SkynetLogoIcon = withIconProps(({ size, ...props }) => ( export const SkynetLogoIcon = withIconProps(({ size, ...props }) => (
<svg role="img" width={size} fill="#00C65E" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" {...props}> <svg role="img" width={size} fill="#00C65E" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" {...props}>
<title>Skynet</title> <title>Skynet</title>
<path d="m-.0004 6.4602 21.3893 11.297c.561.2935.6633 1.0532.1999 1.4846h-.011a10.0399 10.0399 0 0 1-2.2335 1.5307c-6.912 3.4734-14.9917-1.838-14.5438-9.5605l2.8601 1.9752c.856 4.508 5.6187 7.1094 9.8742 5.3932zm8.6477 3.1509 14.3661 5.6785a.8704.8704 0 0 1 .5197 1.0466v.0182c-.1537.5377-.7668.7938-1.2575.5252zm5.2896-7.4375c2.7093-.2325 6.0946.7869 8.1116 3.3871 1.699 2.1951 2.0497 4.8772 1.9298 7.6465v-.007c-.0478.5874-.6494.9616-1.1975.745l-9.7652-3.8596 9.0656 2.4313a7.296 7.296 0 0 0-1.0677-4.5631c-2.9683-4.7678-9.9847-4.5344-12.6297.4201a7.5048 7.5048 0 0 0-.398.8831L5.5546 7.9614c.069-.1017.1417-.198.2144-.2962.1163-.2416.2417-.487.3798-.7268 1.6118-2.7911 4.3102-4.4338 7.1558-4.6973.2108-.0182.4215-.049.6323-.0672z"></path> <path d="m-.0004 6.4602 21.3893 11.297c.561.2935.6633 1.0532.1999 1.4846h-.011a10.0399 10.0399 0 0 1-2.2335 1.5307c-6.912 3.4734-14.9917-1.838-14.5438-9.5605l2.8601 1.9752c.856 4.508 5.6187 7.1094 9.8742 5.3932zm8.6477 3.1509 14.3661 5.6785a.8704.8704 0 0 1 .5197 1.0466v.0182c-.1537.5377-.7668.7938-1.2575.5252zm5.2896-7.4375c2.7093-.2325 6.0946.7869 8.1116 3.3871 1.699 2.1951 2.0497 4.8772 1.9298 7.6465v-.007c-.0478.5874-.6494.9616-1.1975.745l-9.7652-3.8596 9.0656 2.4313a7.296 7.296 0 0 0-1.0677-4.5631c-2.9683-4.7678-9.9847-4.5344-12.6297.4201a7.5048 7.5048 0 0 0-.398.8831L5.5546 7.9614c.069-.1017.1417-.198.2144-.2962.1163-.2416.2417-.487.3798-.7268 1.6118-2.7911 4.3102-4.4338 7.1558-4.6973.2108-.0182.4215-.049.6323-.0672z"></path>
</svg> </svg>
)) ));

View File

@ -1,6 +1,6 @@
export * from './icons/ChevronDownIcon' export * from "./icons/ChevronDownIcon";
export * from './icons/CogIcon' export * from "./icons/CogIcon";
export * from './icons/LockClosedIcon' export * from "./icons/LockClosedIcon";
export * from './icons/SkynetLogoIcon' export * from "./icons/SkynetLogoIcon";
export * from './icons/ArrowRightIcon' export * from "./icons/ArrowRightIcon";
export * from './icons/InfoIcon' export * from "./icons/InfoIcon";

View File

@ -1,19 +1,19 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
const propTypes = { const propTypes = {
/** /**
* Size of the icon's bounding box. * Size of the icon's bounding box.
*/ */
size: PropTypes.number, size: PropTypes.number,
} };
const defaultProps = { const defaultProps = {
size: 32, size: 32,
} };
export const withIconProps = (IconComponent) => { export const withIconProps = (IconComponent) => {
IconComponent.propTypes = propTypes IconComponent.propTypes = propTypes;
IconComponent.defaultProps = defaultProps IconComponent.defaultProps = defaultProps;
return IconComponent return IconComponent;
} };

View File

@ -1,16 +1,16 @@
import styled from 'styled-components' import styled from "styled-components";
import { PageContainer } from '../PageContainer' import { PageContainer } from "../PageContainer";
const NavBarContainer = styled.div.attrs({ const NavBarContainer = styled.div.attrs({
className: `grid sticky top-0 bg-white`, className: `grid sticky top-0 bg-white`,
})`` })``;
const NavBarBody = styled.nav.attrs({ const NavBarBody = styled.nav.attrs({
className: 'grid h-[80px] font-sans font-light text-sm', className: "grid h-[80px] font-sans font-light text-sm",
})` })`
grid-template-columns: auto max-content 1fr; grid-template-columns: auto max-content 1fr;
` `;
export const NavBar = (props) => ( export const NavBar = (props) => (
<NavBarContainer> <NavBarContainer>
@ -18,4 +18,4 @@ export const NavBar = (props) => (
<NavBarBody {...props} /> <NavBarBody {...props} />
</PageContainer> </PageContainer>
</NavBarContainer> </NavBarContainer>
) );

View File

@ -1,13 +1,13 @@
import { NavBar, NavBarLink, NavBarSection } from '.' import { NavBar, NavBarLink, NavBarSection } from ".";
export default { export default {
title: 'SkynetLibrary/NavBar', title: "SkynetLibrary/NavBar",
component: NavBar, component: NavBar,
subcomponents: { subcomponents: {
NavBarSection, NavBarSection,
NavBarLink, NavBarLink,
}, },
} };
const Template = (props) => ( const Template = (props) => (
<NavBar {...props}> <NavBar {...props}>
@ -19,7 +19,7 @@ const Template = (props) => (
<NavBarLink href="/payments">Payments</NavBarLink> <NavBarLink href="/payments">Payments</NavBarLink>
</NavBarSection> </NavBarSection>
</NavBar> </NavBar>
) );
export const DashboardTopNavigation = Template.bind({}) export const DashboardTopNavigation = Template.bind({});
DashboardTopNavigation.args = {} DashboardTopNavigation.args = {};

View File

@ -1,5 +1,5 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
import styled from 'styled-components' import styled from "styled-components";
export const NavBarLink = styled.a.attrs(({ active }) => ({ export const NavBarLink = styled.a.attrs(({ active }) => ({
className: ` className: `
@ -7,13 +7,13 @@ export const NavBarLink = styled.a.attrs(({ active }) => ({
flex h-full items-center justify-center flex h-full items-center justify-center
border-x border-x-palette-100 border-b-2 border-x border-x-palette-100 border-b-2
text-palette-600 transition-colors hover:bg-palette-100/50 text-palette-600 transition-colors hover:bg-palette-100/50
${active ? 'border-b-primary' : 'border-b-palette-200/50'} ${active ? "border-b-primary" : "border-b-palette-200/50"}
`, `,
}))`` }))``;
NavBarLink.propTypes = { NavBarLink.propTypes = {
/** /**
* When set to true, an additional indicator will be rendered showing the item as active. * When set to true, an additional indicator will be rendered showing the item as active.
*/ */
active: PropTypes.bool, active: PropTypes.bool,
} };

View File

@ -1,3 +1,3 @@
import styled from 'styled-components' import styled from "styled-components";
export const NavBarSection = styled.div.attrs({ className: 'flex items-center' })`` export const NavBarSection = styled.div.attrs({ className: "flex items-center" })``;

View File

@ -1,3 +1,3 @@
export * from './NavBar' export * from "./NavBar";
export * from './NavBarSection' export * from "./NavBarSection";
export * from './NavBarLink' export * from "./NavBarLink";

View File

@ -1,13 +1,13 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
import styled from 'styled-components' import styled from "styled-components";
export const PageContainer = styled.div.attrs({ export const PageContainer = styled.div.attrs({
className: `mx-auto w-page md:w-page-md lg:w-page-lg xl:w-page-xl`, className: `mx-auto w-page md:w-page-md lg:w-page-lg xl:w-page-xl`,
})`` })``;
PageContainer.propTypes = { PageContainer.propTypes = {
/** /**
* Optional `class` attribute. * Optional `class` attribute.
*/ */
className: PropTypes.string, className: PropTypes.string,
} };

View File

@ -1 +1 @@
export * from './PageContainer' export * from "./PageContainer";

View File

@ -1,13 +1,13 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
import styled from 'styled-components' import styled from "styled-components";
const PanelBody = styled.div.attrs({ const PanelBody = styled.div.attrs({
className: 'p-6 bg-white rounded', className: "p-6 bg-white rounded",
})`` })``;
const PanelTitle = styled.h6.attrs({ const PanelTitle = styled.h6.attrs({
className: 'uppercase text-xs text-palette-400 h-8 flex items-center', className: "uppercase text-xs text-palette-400 h-8 flex items-center",
})`` })``;
/** /**
* Besides documented props, it accepts all HMTL attributes a `<div>` element does. * Besides documented props, it accepts all HMTL attributes a `<div>` element does.
@ -19,15 +19,15 @@ export const Panel = ({ title, ...props }) => (
{title && <PanelTitle>{title}</PanelTitle>} {title && <PanelTitle>{title}</PanelTitle>}
<PanelBody {...props} /> <PanelBody {...props} />
</div> </div>
) );
Panel.propTypes = { Panel.propTypes = {
/** /**
* Label of the panel * Label of the panel
*/ */
title: PropTypes.string, title: PropTypes.string,
} };
Panel.defaultProps = { Panel.defaultProps = {
title: '', title: "",
} };

View File

@ -1,7 +1,7 @@
import { Panel } from './Panel' import { Panel } from "./Panel";
export default { export default {
title: 'SkynetLibrary/Panel', title: "SkynetLibrary/Panel",
component: Panel, component: Panel,
decorators: [ decorators: [
(Story) => ( (Story) => (
@ -12,7 +12,7 @@ export default {
</div> </div>
), ),
], ],
} };
const SampleContent = () => ( const SampleContent = () => (
<> <>
@ -20,21 +20,21 @@ const SampleContent = () => (
<p>This is the second paragraph</p> <p>This is the second paragraph</p>
<p>This is the third paragraph</p> <p>This is the third paragraph</p>
</> </>
) );
const Template = (args) => ( const Template = (args) => (
<Panel {...args}> <Panel {...args}>
<SampleContent /> <SampleContent />
</Panel> </Panel>
) );
export const RawPanel = Template.bind({}) export const RawPanel = Template.bind({});
RawPanel.args = {} RawPanel.args = {};
export const TitledPanel = Template.bind({}) export const TitledPanel = Template.bind({});
TitledPanel.args = { TitledPanel.args = {
title: 'Latest activity', title: "Latest activity",
} };
export const InlinePanelsExample = () => ( export const InlinePanelsExample = () => (
<div className="grid gap-4 grid-flow-col auto-cols-fr"> <div className="grid gap-4 grid-flow-col auto-cols-fr">
@ -45,7 +45,7 @@ export const InlinePanelsExample = () => (
<SampleContent /> <SampleContent />
</Panel> </Panel>
</div> </div>
) );
export const FullWidthPanelsExample = () => ( export const FullWidthPanelsExample = () => (
<> <>
@ -56,10 +56,10 @@ export const FullWidthPanelsExample = () => (
<SampleContent /> <SampleContent />
</Panel> </Panel>
</> </>
) );
export const CustomPanelBackground = Template.bind({}) export const CustomPanelBackground = Template.bind({});
CustomPanelBackground.args = { CustomPanelBackground.args = {
className: 'bg-red-500', className: "bg-red-500",
title: 'Background below should be red', title: "Background below should be red",
} };

View File

@ -1 +1 @@
export * from './Panel' export * from "./Panel";

View File

@ -1 +1 @@
export * from './PopoverMenu' export * from "./PopoverMenu";

View File

@ -1,11 +1,11 @@
import { Children, cloneElement, useEffect, useMemo, useRef } from 'react' import { Children, cloneElement, useEffect, useMemo, useRef } from "react";
import PropTypes from 'prop-types' import PropTypes from "prop-types";
import { useClickAway } from 'react-use' import { useClickAway } from "react-use";
import styled, { css, keyframes } from 'styled-components' import styled, { css, keyframes } from "styled-components";
import { ChevronDownIcon } from '../Icons' import { ChevronDownIcon } from "../Icons";
import { useCallbacks, useSelectReducer } from './hooks' import { useCallbacks, useSelectReducer } from "./hooks";
import { SelectOption } from './SelectOption' import { SelectOption } from "./SelectOption";
const dropDown = keyframes` const dropDown = keyframes`
0% { 0% {
@ -17,52 +17,52 @@ const dropDown = keyframes`
100% { 100% {
transform: scaleY(1); transform: scaleY(1);
} }
` `;
const Container = styled.div.attrs({ className: 'relative inline-flex' })`` const Container = styled.div.attrs({ className: "relative inline-flex" })``;
const Trigger = styled.button.attrs(({ placeholder }) => ({ const Trigger = styled.button.attrs(({ placeholder }) => ({
className: `flex items-center cursor-pointer ${placeholder ? 'text-palette-300' : ''}`, className: `flex items-center cursor-pointer ${placeholder ? "text-palette-300" : ""}`,
}))`` }))``;
const TriggerIcon = styled(ChevronDownIcon).attrs({ const TriggerIcon = styled(ChevronDownIcon).attrs({
className: 'transition-transform text-primary', className: "transition-transform text-primary",
})` })`
transform: ${({ open }) => (open ? 'rotateX(180deg)' : 'none')}; transform: ${({ open }) => (open ? "rotateX(180deg)" : "none")};
` `;
const Flyout = styled.ul.attrs(({ open }) => ({ const Flyout = styled.ul.attrs(({ open }) => ({
className: `absolute top-[20px] right-0 className: `absolute top-[20px] right-0
p-0 h-0 border rounded bg-white p-0 h-0 border rounded bg-white
overflow-hidden pointer-events-none overflow-hidden pointer-events-none
shadow-md shadow-palette-200/50 shadow-md shadow-palette-200/50
${open ? 'pointer-events-auto h-auto overflow-visible border-primary' : ''} ${open ? "pointer-events-auto h-auto overflow-visible border-primary" : ""}
${open ? 'visible' : 'invisible'}`, ${open ? "visible" : "invisible"}`,
}))` }))`
animation: ${({ open }) => animation: ${({ open }) =>
open open
? css` ? css`
${dropDown} 0.1s ease-in-out ${dropDown} 0.1s ease-in-out
` `
: 'none'}; : "none"};
` `;
export const Select = ({ defaultValue, children, onChange, placeholder }) => { export const Select = ({ defaultValue, children, onChange, placeholder }) => {
const selectRef = useRef() const selectRef = useRef();
const options = useMemo(() => Children.toArray(children).filter(({ type }) => type === SelectOption), [children]) const options = useMemo(() => Children.toArray(children).filter(({ type }) => type === SelectOption), [children]);
const [state, dispatch] = useSelectReducer({ defaultValue, placeholder, options }) const [state, dispatch] = useSelectReducer({ defaultValue, placeholder, options });
const { close, toggle, selectOption } = useCallbacks(state, dispatch) const { close, toggle, selectOption } = useCallbacks(state, dispatch);
useClickAway(selectRef, close) useClickAway(selectRef, close);
useEffect(() => { useEffect(() => {
if (state.selectedOptionIndex > -1) { if (state.selectedOptionIndex > -1) {
onChange(options[state.selectedOptionIndex].props.value) onChange(options[state.selectedOptionIndex].props.value);
} }
}, [onChange, options, state.selectedOptionIndex]) }, [onChange, options, state.selectedOptionIndex]);
const activeOption = options[state.selectedOptionIndex] const activeOption = options[state.selectedOptionIndex];
const activeLabel = activeOption?.props?.label ?? null const activeLabel = activeOption?.props?.label ?? null;
return ( return (
<Container ref={selectRef}> <Container ref={selectRef}>
@ -79,8 +79,8 @@ export const Select = ({ defaultValue, children, onChange, placeholder }) => {
)} )}
</Flyout> </Flyout>
</Container> </Container>
) );
} };
Select.propTypes = { Select.propTypes = {
/** /**
@ -99,4 +99,4 @@ Select.propTypes = {
* Placeholder to be displayed when no option is selected. * Placeholder to be displayed when no option is selected.
*/ */
placeholder: PropTypes.string, placeholder: PropTypes.string,
} };

View File

@ -1,20 +1,20 @@
import { Panel } from '../Panel' import { Panel } from "../Panel";
import { Select, SelectOption } from '.' import { Select, SelectOption } from ".";
export default { export default {
title: 'SkynetLibrary/Select', title: "SkynetLibrary/Select",
component: Select, component: Select,
subcomponents: { subcomponents: {
SelectOption, SelectOption,
}, },
decorators: [ decorators: [
(Story) => ( (Story) => (
<Panel style={{ margin: 50, textAlign: 'center' }}> <Panel style={{ margin: 50, textAlign: "center" }}>
<Story /> <Story />
</Panel> </Panel>
), ),
], ],
} };
const Template = (props) => ( const Template = (props) => (
<Select {...props}> <Select {...props}>
@ -25,23 +25,23 @@ const Template = (props) => (
<SelectOption value="date-desc" label="Latest" /> <SelectOption value="date-desc" label="Latest" />
<SelectOption value="date-asc" label="Oldest" /> <SelectOption value="date-asc" label="Oldest" />
</Select> </Select>
) );
Template.args = {} Template.args = {};
export const NoDefaultNoPlaceholder = Template.bind({}) export const NoDefaultNoPlaceholder = Template.bind({});
NoDefaultNoPlaceholder.args = { NoDefaultNoPlaceholder.args = {
onChange: console.info.bind(console, 'onChange'), onChange: console.info.bind(console, "onChange"),
} };
export const WithPlaceholder = Template.bind({}) export const WithPlaceholder = Template.bind({});
WithPlaceholder.args = { WithPlaceholder.args = {
placeholder: 'Select...', placeholder: "Select...",
onChange: console.info.bind(console, 'onChange'), onChange: console.info.bind(console, "onChange"),
} };
export const WithDefautValue = Template.bind({}) export const WithDefautValue = Template.bind({});
WithDefautValue.args = { WithDefautValue.args = {
defaultValue: 'size-desc', defaultValue: "size-desc",
placeholder: 'Select...', placeholder: "Select...",
onChange: console.info.bind(console, 'onChange'), onChange: console.info.bind(console, "onChange"),
} };

View File

@ -1,17 +1,17 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
import styled from 'styled-components' import styled from "styled-components";
const Option = styled.li.attrs(({ selected }) => ({ const Option = styled.li.attrs(({ selected }) => ({
className: `m-0 px-4 whitespace-nowrap py-1 px-4 cursor-pointer className: `m-0 px-4 whitespace-nowrap py-1 px-4 cursor-pointer
transition-colors hover:bg-palette-100/50 transition-colors hover:bg-palette-100/50
${selected ? 'pl-3.5 border-l-2 border-l-primary' : ''}`, ${selected ? "pl-3.5 border-l-2 border-l-primary" : ""}`,
}))`` }))``;
export const SelectOption = ({ selected, label, ...props }) => ( export const SelectOption = ({ selected, label, ...props }) => (
<Option selected={selected} role="option" {...props}> <Option selected={selected} role="option" {...props}>
{label} {label}
</Option> </Option>
) );
SelectOption.propTypes = { SelectOption.propTypes = {
/** /**
@ -26,4 +26,4 @@ SelectOption.propTypes = {
* Indicates an option is currently selected. **Controlled by parent `<Select>` component**. * Indicates an option is currently selected. **Controlled by parent `<Select>` component**.
*/ */
selected: PropTypes.bool, selected: PropTypes.bool,
} };

View File

@ -1,86 +1,86 @@
import { useCallback, useReducer } from 'react' import { useCallback, useReducer } from "react";
const initialState = { const initialState = {
open: false, open: false,
selectedOptionIndex: -1, selectedOptionIndex: -1,
} };
const withDefaultValue = (state, { defaultValue, options, placeholder }) => { const withDefaultValue = (state, { defaultValue, options, placeholder }) => {
let index = -1 let index = -1;
if (!defaultValue) { if (!defaultValue) {
if (!placeholder) { if (!placeholder) {
// If no default value and no placeholder are provided, select first option. // If no default value and no placeholder are provided, select first option.
// TODO: might need to look for the first *available* option. // TODO: might need to look for the first *available* option.
index = 0 index = 0;
} }
} else { } else {
index = options.findIndex((option) => { index = options.findIndex((option) => {
if (!option || !option.props) { if (!option || !option.props) {
return false return false;
} }
return option.props.value === defaultValue return option.props.value === defaultValue;
}) });
} }
return { return {
...state, ...state,
selectedOptionIndex: index, selectedOptionIndex: index,
} };
} };
const stateReducer = (state, action) => { const stateReducer = (state, action) => {
switch (action.type) { switch (action.type) {
case 'close': case "close":
return { return {
...state, ...state,
open: false, open: false,
} };
case 'open': case "open":
return { return {
...state, ...state,
open: true, open: true,
} };
case 'selectOption': case "selectOption":
return { return {
...state, ...state,
open: false, open: false,
selectedOptionIndex: action.index, selectedOptionIndex: action.index,
} };
default: default:
return { return {
...state, ...state,
} };
} }
} };
export const useSelectReducer = ({ defaultValue, options, placeholder }) => export const useSelectReducer = ({ defaultValue, options, placeholder }) =>
useReducer(stateReducer, withDefaultValue(initialState, { defaultValue, options, placeholder })) useReducer(stateReducer, withDefaultValue(initialState, { defaultValue, options, placeholder }));
export const useCallbacks = (state, dispatch) => { export const useCallbacks = (state, dispatch) => {
const close = useCallback(() => { const close = useCallback(() => {
if (state.open) { if (state.open) {
dispatch({ type: 'close' }) dispatch({ type: "close" });
} }
}, [dispatch, state.open]) }, [dispatch, state.open]);
const toggle = useCallback(() => { const toggle = useCallback(() => {
dispatch({ type: state.open ? 'close' : 'open' }) dispatch({ type: state.open ? "close" : "open" });
}, [dispatch, state.open]) }, [dispatch, state.open]);
const selectOption = useCallback( const selectOption = useCallback(
(optionIndex) => { (optionIndex) => {
if (optionIndex !== state.selectedOptionIndex) { if (optionIndex !== state.selectedOptionIndex) {
dispatch({ type: 'selectOption', index: optionIndex }) dispatch({ type: "selectOption", index: optionIndex });
} }
}, },
[dispatch, state.selectedOptionIndex] [dispatch, state.selectedOptionIndex]
) );
return { return {
close, close,
selectOption, selectOption,
toggle, toggle,
} };
} };

View File

@ -1,2 +1,2 @@
export * from './Select' export * from "./Select";
export * from './SelectOption' export * from "./SelectOption";

View File

@ -20,7 +20,7 @@
} }
.react-switch-label .react-switch-button { .react-switch-label .react-switch-button {
content: ''; content: "";
position: absolute; position: absolute;
top: 2px; top: 2px;
left: 2px; left: 2px;

View File

@ -1,5 +1,5 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
import './Switch.css' import "./Switch.css";
/** /**
* Primary UI component for user interaction * Primary UI component for user interaction
@ -14,12 +14,12 @@ export const Switch = ({ isOn, handleToggle }) => {
id={`react-switch-new`} id={`react-switch-new`}
type="checkbox" type="checkbox"
/> />
<label className={'react-switch-label'} htmlFor={`react-switch-new`}> <label className={"react-switch-label"} htmlFor={`react-switch-new`}>
<span className={`react-switch-button ${isOn ? 'bg-primary' : 'bg-palette-200'}`} /> <span className={`react-switch-button ${isOn ? "bg-primary" : "bg-palette-200"}`} />
</label> </label>
</> </>
) );
} };
Switch.propTypes = { Switch.propTypes = {
/** /**
@ -30,8 +30,8 @@ Switch.propTypes = {
* Function to execute on change * Function to execute on change
*/ */
handleToggle: PropTypes.func, handleToggle: PropTypes.func,
} };
Switch.defaultProps = { Switch.defaultProps = {
isOn: false, isOn: false,
} };

View File

@ -1,22 +1,22 @@
import { Switch } from './Switch' import { Switch } from "./Switch";
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default { export default {
title: 'SkynetLibrary/Switch', title: "SkynetLibrary/Switch",
component: Switch, component: Switch,
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
} };
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Template = (args) => <Switch {...args} /> const Template = (args) => <Switch {...args} />;
export const SwitchTrue = Template.bind({}) export const SwitchTrue = Template.bind({});
// More on args: https://storybook.js.org/docs/react/writing-stories/args // More on args: https://storybook.js.org/docs/react/writing-stories/args
SwitchTrue.args = { SwitchTrue.args = {
isOn: true, isOn: true,
} };
export const SwitchFalse = Template.bind({}) export const SwitchFalse = Template.bind({});
// More on args: https://storybook.js.org/docs/react/writing-stories/args // More on args: https://storybook.js.org/docs/react/writing-stories/args
SwitchFalse.args = { SwitchFalse.args = {
isOn: false, isOn: false,
} };

View File

@ -1 +1 @@
export * from './Switch' export * from "./Switch";

View File

@ -1,14 +1,14 @@
import styled from 'styled-components' import styled from "styled-components";
const Container = styled.div.attrs({ const Container = styled.div.attrs({
className: 'p-1 max-w-full overflow-x-auto', className: "p-1 max-w-full overflow-x-auto",
})`` })``;
const StyledTable = styled.table.attrs({ const StyledTable = styled.table.attrs({
className: 'table-auto w-full border-separate', className: "table-auto w-full border-separate",
})` })`
border-spacing: 0; border-spacing: 0;
` `;
/** /**
* Accepts all HMTL attributes a `<table>` element does. * Accepts all HMTL attributes a `<table>` element does.
@ -17,4 +17,4 @@ export const Table = (props) => (
<Container> <Container>
<StyledTable {...props} /> <StyledTable {...props} />
</Container> </Container>
) );

View File

@ -1,10 +1,10 @@
import { CogIcon } from '../Icons' import { CogIcon } from "../Icons";
import { IconButton } from '../IconButton' import { IconButton } from "../IconButton";
import { Table, TableBody, TableHead, TableCell, TableRow, TableHeadCell } from './' import { Table, TableBody, TableHead, TableCell, TableRow, TableHeadCell } from "./";
export default { export default {
title: 'SkynetLibrary/Table', title: "SkynetLibrary/Table",
component: Table, component: Table,
subcomponents: { subcomponents: {
TableBody, TableBody,
@ -13,52 +13,52 @@ export default {
TableRow, TableRow,
TableHeadCell, TableHeadCell,
}, },
} };
const DATA = [ const DATA = [
{ {
name: 'At_vereo_eos_censes', name: "At_vereo_eos_censes",
type: '.mp4', type: ".mp4",
size: '2.45 MB', size: "2.45 MB",
uploaded: 'a few seconds ago', uploaded: "a few seconds ago",
skylink: '_HyFqH632Rmy99c93idTtBVXeRDgaDAAWg6Bmm5P1izriu', skylink: "_HyFqH632Rmy99c93idTtBVXeRDgaDAAWg6Bmm5P1izriu",
}, },
{ {
name: 'Miriam Klein IV', name: "Miriam Klein IV",
type: '.pdf', type: ".pdf",
size: '7.52 MB', size: "7.52 MB",
uploaded: '01/04/2021; 17:11', uploaded: "01/04/2021; 17:11",
skylink: '_izriuHyFqH632Rmy99c93idTtBVXeRDgaDAAWg6Bmm5P1', skylink: "_izriuHyFqH632Rmy99c93idTtBVXeRDgaDAAWg6Bmm5P1",
}, },
{ {
name: 'tmp/QmWR6eVDVkwhAYq7X99w4xT9KNKBzwK39Fj1PDmr4ZnzMm/QmWR6eVDVkwhAYq7X99w4xT9KNKBzwK39Fj1PDmr4ZnzMm', name: "tmp/QmWR6eVDVkwhAYq7X99w4xT9KNKBzwK39Fj1PDmr4ZnzMm/QmWR6eVDVkwhAYq7X99w4xT9KNKBzwK39Fj1PDmr4ZnzMm",
type: '.doc', type: ".doc",
size: '8.15 MB', size: "8.15 MB",
uploaded: '10/26/2020; 7:21', uploaded: "10/26/2020; 7:21",
skylink: '_VXeRDgaDAAWg6Bmm5P1izriuHyFqH632Rmy99c93idTtB', skylink: "_VXeRDgaDAAWg6Bmm5P1izriuHyFqH632Rmy99c93idTtB",
}, },
{ {
name: 'Perm_London', name: "Perm_London",
type: '.avi', type: ".avi",
size: '225.6 MB', size: "225.6 MB",
uploaded: '09/12/2020; 19:28', uploaded: "09/12/2020; 19:28",
skylink: '_eRDgaDAAWg6Bmm5P1izriuHyFqH632Rmy99c93idTtBVX', skylink: "_eRDgaDAAWg6Bmm5P1izriuHyFqH632Rmy99c93idTtBVX",
}, },
{ {
name: 'Santa_Clara', name: "Santa_Clara",
type: '.pdf', type: ".pdf",
size: '7.52 MB', size: "7.52 MB",
uploaded: '09/12/2020; 19:23', uploaded: "09/12/2020; 19:23",
skylink: '_AWg6Bmm5P1izriuHyFqH632Rmy99c93idTtBVXeRDgaDA', skylink: "_AWg6Bmm5P1izriuHyFqH632Rmy99c93idTtBVXeRDgaDA",
}, },
{ {
name: 'Marysa_Labrone', name: "Marysa_Labrone",
type: '.doc', type: ".doc",
size: '8.15 MB', size: "8.15 MB",
uploaded: '09/12/2020; 19:21', uploaded: "09/12/2020; 19:21",
skylink: '_P1izriuHyFqH632Rmy99c93idTtBVXeRDgaDAAWg6Bmm5', skylink: "_P1izriuHyFqH632Rmy99c93idTtBVXeRDgaDAAWg6Bmm5",
}, },
] ];
const Template = (args) => ( const Template = (args) => (
<Table {...args}> <Table {...args}>
@ -87,7 +87,7 @@ const Template = (args) => (
))} ))}
</TableBody> </TableBody>
</Table> </Table>
) );
export const RegularTable = Template.bind({}) export const RegularTable = Template.bind({});
RegularTable.args = {} RegularTable.args = {};

View File

@ -1,6 +1,6 @@
import styled from 'styled-components' import styled from "styled-components";
/** /**
* Accepts all HMTL attributes a `<tbody>` element does. * Accepts all HMTL attributes a `<tbody>` element does.
*/ */
export const TableBody = styled.tbody`` export const TableBody = styled.tbody``;

View File

@ -1,4 +1,4 @@
import styled from 'styled-components' import styled from "styled-components";
/** /**
* Accepts all HMTL attributes a `<td>` element does. * Accepts all HMTL attributes a `<td>` element does.
@ -8,6 +8,6 @@ export const TableCell = styled.td.attrs({
text-palette-600 even:text-palette-400 text-palette-600 even:text-palette-400
first:rounded-l-sm last:rounded-r-sm`, first:rounded-l-sm last:rounded-r-sm`,
})` })`
text-align: ${({ align }) => align ?? 'left'}; text-align: ${({ align }) => align ?? "left"};
max-width: ${({ maxWidth }) => maxWidth ?? 'none'}; max-width: ${({ maxWidth }) => maxWidth ?? "none"};
` `;

View File

@ -1,6 +1,6 @@
import styled from 'styled-components' import styled from "styled-components";
/** /**
* Accepts all HMTL attributes a `<thead>` element does. * Accepts all HMTL attributes a `<thead>` element does.
*/ */
export const TableHead = styled.thead`` export const TableHead = styled.thead``;

View File

@ -1,4 +1,4 @@
import styled from 'styled-components' import styled from "styled-components";
/** /**
* Accepts all HMTL attributes a `<th>` element does. * Accepts all HMTL attributes a `<th>` element does.
@ -8,6 +8,6 @@ export const TableHeadCell = styled.th.attrs({
text-palette-600 font-sans font-light text-xs text-palette-600 font-sans font-light text-xs
first:rounded-l-sm last:rounded-r-sm`, first:rounded-l-sm last:rounded-r-sm`,
})` })`
text-align: ${({ align }) => align ?? 'left'}; text-align: ${({ align }) => align ?? "left"};
max-width: ${({ maxWidth }) => maxWidth ?? 'none'}; max-width: ${({ maxWidth }) => maxWidth ?? "none"};
` `;

View File

@ -1,20 +1,20 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
import styled from 'styled-components' import styled from "styled-components";
/** /**
* Besides documented props, it accepts all HMTL attributes a `<tr>` element does. * Besides documented props, it accepts all HMTL attributes a `<tr>` element does.
*/ */
export const TableRow = styled.tr.attrs(({ noHoverEffect }) => ({ export const TableRow = styled.tr.attrs(({ noHoverEffect }) => ({
className: `bg-palette-100/50 odd:bg-white ${noHoverEffect ? '' : 'hover:bg-palette-200/20'}`, className: `bg-palette-100/50 odd:bg-white ${noHoverEffect ? "" : "hover:bg-palette-200/20"}`,
}))`` }))``;
/** /**
* Allows disabling `hover` effect on a row. Useful for `<thead>` row. * Allows disabling `hover` effect on a row. Useful for `<thead>` row.
*/ */
TableRow.propTypes = { TableRow.propTypes = {
noHoverEffect: PropTypes.bool, noHoverEffect: PropTypes.bool,
} };
TableRow.defaultProps = { TableRow.defaultProps = {
noHoverEffect: false, noHoverEffect: false,
} };

View File

@ -1,6 +1,6 @@
export * from './Table' export * from "./Table";
export * from './TableHead' export * from "./TableHead";
export * from './TableHeadCell' export * from "./TableHeadCell";
export * from './TableBody' export * from "./TableBody";
export * from './TableRow' export * from "./TableRow";
export * from './TableCell' export * from "./TableCell";

View File

@ -1,38 +1,38 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from "react";
import PropTypes from 'prop-types' import PropTypes from "prop-types";
import styled from 'styled-components' import styled from "styled-components";
const Wrapper = styled.div.attrs({ const Wrapper = styled.div.attrs({
className: 'absolute left-0 bottom-0 w-full h-0.5 bg-palette-200', className: "absolute left-0 bottom-0 w-full h-0.5 bg-palette-200",
})`` })``;
const Indicator = styled.div.attrs({ const Indicator = styled.div.attrs({
className: 'absolute h-0.5 bottom-0 bg-primary duration-200 ease-in-out', className: "absolute h-0.5 bottom-0 bg-primary duration-200 ease-in-out",
})` })`
will-change: left, width; will-change: left, width;
` `;
export const ActiveTabIndicator = ({ tabRef }) => { export const ActiveTabIndicator = ({ tabRef }) => {
const [position, setPosition] = useState(0) const [position, setPosition] = useState(0);
const [width, setWidth] = useState(0) const [width, setWidth] = useState(0);
useEffect(() => { useEffect(() => {
if (!tabRef?.current) { if (!tabRef?.current) {
return return;
} }
const { offsetLeft, offsetWidth } = tabRef.current const { offsetLeft, offsetWidth } = tabRef.current;
setPosition(offsetLeft) setPosition(offsetLeft);
setWidth(offsetWidth) setWidth(offsetWidth);
}, [tabRef]) }, [tabRef]);
return ( return (
<Wrapper> <Wrapper>
<Indicator style={{ left: position, width: `${width}px` }} /> <Indicator style={{ left: position, width: `${width}px` }} />
</Wrapper> </Wrapper>
) );
} };
ActiveTabIndicator.propTypes = { ActiveTabIndicator.propTypes = {
tabRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.instanceOf(Element) })]), tabRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.instanceOf(Element) })]),
} };

View File

@ -1,21 +1,21 @@
import { forwardRef } from 'react' import { forwardRef } from "react";
import PropTypes from 'prop-types' import PropTypes from "prop-types";
import styled from 'styled-components' import styled from "styled-components";
export const StyledTab = styled.button.attrs(({ active, variant }) => ({ export const StyledTab = styled.button.attrs(({ active, variant }) => ({
className: `m-0 px-2 pb-2 className: `m-0 px-2 pb-2
text-tab text-left font-sans text-tab text-left font-sans
transition-colors hover:text-palette-500 transition-colors hover:text-palette-500
${active ? 'font-semibold text-palette-600' : 'font-light text-palette-300'} ${active ? "font-semibold text-palette-600" : "font-light text-palette-300"}
${variant === 'regular' ? 'sm:min-w-[180px]' : ''}`, ${variant === "regular" ? "sm:min-w-[180px]" : ""}`,
}))`` }))``;
export const Tab = forwardRef(({ active, title, id, variant, ...props }, ref) => ( export const Tab = forwardRef(({ active, title, id, variant, ...props }, ref) => (
<StyledTab <StyledTab
ref={ref} ref={ref}
role="tab" role="tab"
type="button" type="button"
ariaSelected={`${active ? 'true' : 'false'}`} ariaSelected={`${active ? "true" : "false"}`}
ariaControls={`tabpanel-${id}`} ariaControls={`tabpanel-${id}`}
id={`tab-${id}`} id={`tab-${id}`}
active={active} active={active}
@ -24,9 +24,9 @@ export const Tab = forwardRef(({ active, title, id, variant, ...props }, ref) =>
> >
{title} {title}
</StyledTab> </StyledTab>
)) ));
Tab.displayName = 'Tab' Tab.displayName = "Tab";
Tab.propTypes = { Tab.propTypes = {
/** /**
@ -48,8 +48,8 @@ Tab.propTypes = {
* Controlled by `Tabs` component. * Controlled by `Tabs` component.
*/ */
variant: PropTypes.string, variant: PropTypes.string,
} };
Tab.defaultProps = { Tab.defaultProps = {
variant: 'regular', variant: "regular",
} };

View File

@ -1,19 +1,19 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
/** /**
* Besides documented props, it accepts all HMTL attributes a `<div>` element does. * Besides documented props, it accepts all HMTL attributes a `<div>` element does.
*/ */
export const TabPanel = ({ children, active, tabId, ...props }) => { export const TabPanel = ({ children, active, tabId, ...props }) => {
if (!active) { if (!active) {
return null return null;
} }
return ( return (
<div role="tabpanel" id={`tabpanel-${tabId}`} aria-labelledby={`tab-${tabId}`} {...props}> <div role="tabpanel" id={`tabpanel-${tabId}`} aria-labelledby={`tab-${tabId}`} {...props}>
{children} {children}
</div> </div>
) );
} };
TabPanel.propTypes = { TabPanel.propTypes = {
/** /**
@ -28,4 +28,4 @@ TabPanel.propTypes = {
* Controlled by `Tabs` component. * Controlled by `Tabs` component.
*/ */
active: PropTypes.bool, active: PropTypes.bool,
} };

View File

@ -1,61 +1,61 @@
import { cloneElement, useCallback, useEffect, useMemo, useState } from 'react' import { cloneElement, useCallback, useEffect, useMemo, useState } from "react";
import PropTypes from 'prop-types' import PropTypes from "prop-types";
import styled from 'styled-components' import styled from "styled-components";
import { ActiveTabIndicator } from './ActiveTabIndicator' import { ActiveTabIndicator } from "./ActiveTabIndicator";
import { usePrefixedTabIds, useTabsChildren } from './hooks' import { usePrefixedTabIds, useTabsChildren } from "./hooks";
const Container = styled.div.attrs({ const Container = styled.div.attrs({
className: 'tabs-container', className: "tabs-container",
})`` })``;
const Header = styled.div.attrs({ const Header = styled.div.attrs({
className: 'relative flex justify-start overflow-hidden', className: "relative flex justify-start overflow-hidden",
})`` })``;
const TabList = styled.div.attrs(({ variant }) => ({ const TabList = styled.div.attrs(({ variant }) => ({
role: 'tablist', role: "tablist",
className: `relative inline-grid grid-flow-col auto-cols-fr className: `relative inline-grid grid-flow-col auto-cols-fr
${variant === 'regular' ? 'w-full sm:w-auto' : 'w-full'}`, ${variant === "regular" ? "w-full sm:w-auto" : "w-full"}`,
}))`` }))``;
const Divider = styled.div.attrs({ const Divider = styled.div.attrs({
'aria-hidden': 'true', "aria-hidden": "true",
className: 'absolute bottom-0 w-screen border-b border-b-palette-200', className: "absolute bottom-0 w-screen border-b border-b-palette-200",
})` })`
right: calc(-100vw - 2px); right: calc(-100vw - 2px);
` `;
const Body = styled.div`` const Body = styled.div``;
/** /**
* Besides documented props, it accepts all HMTL attributes a `<div>` element does. * Besides documented props, it accepts all HMTL attributes a `<div>` element does.
*/ */
export const Tabs = ({ defaultTab, children, variant }) => { export const Tabs = ({ defaultTab, children, variant }) => {
const getTabId = usePrefixedTabIds() const getTabId = usePrefixedTabIds();
const { tabs, panels, tabsRefs } = useTabsChildren(children, getTabId) const { tabs, panels, tabsRefs } = useTabsChildren(children, getTabId);
const defaultTabId = useMemo(() => getTabId(defaultTab || tabs[0].props.id), [getTabId, defaultTab, tabs]) const defaultTabId = useMemo(() => getTabId(defaultTab || tabs[0].props.id), [getTabId, defaultTab, tabs]);
const [activeTabId, setActiveTabId] = useState(defaultTabId) const [activeTabId, setActiveTabId] = useState(defaultTabId);
const [activeTabRef, setActiveTabRef] = useState(tabsRefs[activeTabId]) const [activeTabRef, setActiveTabRef] = useState(tabsRefs[activeTabId]);
const isActive = (id) => id === activeTabId const isActive = (id) => id === activeTabId;
const onTabChange = useCallback( const onTabChange = useCallback(
(id) => { (id) => {
setActiveTabId(id) setActiveTabId(id);
}, },
[setActiveTabId] [setActiveTabId]
) );
useEffect(() => { useEffect(() => {
// Refresh active tab indicator whenever active tab changes. // Refresh active tab indicator whenever active tab changes.
setActiveTabRef(tabsRefs[activeTabId]) setActiveTabRef(tabsRefs[activeTabId]);
}, [setActiveTabRef, tabsRefs, activeTabId]) }, [setActiveTabRef, tabsRefs, activeTabId]);
return ( return (
<Container> <Container>
<Header> <Header>
<TabList variant={variant}> <TabList variant={variant}>
{tabs.map((tab) => { {tabs.map((tab) => {
const tabId = getTabId(tab.props.id) const tabId = getTabId(tab.props.id);
return cloneElement(tab, { return cloneElement(tab, {
ref: tabsRefs[tabId], ref: tabsRefs[tabId],
@ -63,7 +63,7 @@ export const Tabs = ({ defaultTab, children, variant }) => {
variant, variant,
active: isActive(tabId), active: isActive(tabId),
onClick: () => onTabChange(tabId), onClick: () => onTabChange(tabId),
}) });
})} })}
<Divider /> <Divider />
<ActiveTabIndicator tabRef={activeTabRef} /> <ActiveTabIndicator tabRef={activeTabRef} />
@ -71,18 +71,18 @@ export const Tabs = ({ defaultTab, children, variant }) => {
</Header> </Header>
<Body> <Body>
{panels.map((panel) => { {panels.map((panel) => {
const tabId = getTabId(panel.props.tabId) const tabId = getTabId(panel.props.tabId);
return cloneElement(panel, { return cloneElement(panel, {
...panel.props, ...panel.props,
tabId, tabId,
active: isActive(tabId), active: isActive(tabId),
}) });
})} })}
</Body> </Body>
</Container> </Container>
) );
} };
Tabs.propTypes = { Tabs.propTypes = {
/** /**
@ -98,9 +98,9 @@ Tabs.propTypes = {
* *
* `fill` will make the tabs spread throughout the available width * `fill` will make the tabs spread throughout the available width
*/ */
variant: PropTypes.oneOf(['regular', 'fill']), variant: PropTypes.oneOf(["regular", "fill"]),
} };
Tabs.defaultProps = { Tabs.defaultProps = {
variant: 'regular', variant: "regular",
} };

View File

@ -1,10 +1,10 @@
import { Tab, TabPanel, Tabs } from './' import { Tab, TabPanel, Tabs } from "./";
export default { export default {
title: 'SkynetLibrary/Tabs', title: "SkynetLibrary/Tabs",
component: Tabs, component: Tabs,
subcomponents: { Tab, TabPanel }, subcomponents: { Tab, TabPanel },
} };
const Template = (props) => ( const Template = (props) => (
<> <>
@ -29,39 +29,39 @@ const Template = (props) => (
</TabPanel> </TabPanel>
</Tabs> </Tabs>
</> </>
) );
const RegularTabs = Template.bind({}) const RegularTabs = Template.bind({});
const FillingTabs = Template.bind({}) const FillingTabs = Template.bind({});
FillingTabs.args = { FillingTabs.args = {
variant: 'fill', variant: "fill",
} };
const FillingTabsInNarrowContainer = Template.bind({}) const FillingTabsInNarrowContainer = Template.bind({});
FillingTabsInNarrowContainer.args = { FillingTabsInNarrowContainer.args = {
variant: 'fill', variant: "fill",
defaultTab: 'downloads', defaultTab: "downloads",
} };
FillingTabsInNarrowContainer.decorators = [ FillingTabsInNarrowContainer.decorators = [
(Story) => ( (Story) => (
<div style={{ width: 360, background: '#fafafa', padding: 10, border: '1px solid #eee' }}> <div style={{ width: 360, background: "#fafafa", padding: 10, border: "1px solid #eee" }}>
<Story /> <Story />
</div> </div>
), ),
] ];
const MultipleTabsComponents = Template.bind({}) const MultipleTabsComponents = Template.bind({});
MultipleTabsComponents.args = { MultipleTabsComponents.args = {
variant: 'fill', variant: "fill",
} };
MultipleTabsComponents.decorators = [ MultipleTabsComponents.decorators = [
(Story) => ( (Story) => (
<div style={{ width: 360, background: '#fafafa', padding: 10, border: '1px solid #eee' }}> <div style={{ width: 360, background: "#fafafa", padding: 10, border: "1px solid #eee" }}>
<Story /> <Story />
<Story /> <Story />
</div> </div>
), ),
] ];
export { RegularTabs, FillingTabs, FillingTabsInNarrowContainer, MultipleTabsComponents } export { RegularTabs, FillingTabs, FillingTabsInNarrowContainer, MultipleTabsComponents };

View File

@ -1,18 +1,18 @@
import { Children, createRef, useCallback, useMemo } from 'react' import { Children, createRef, useCallback, useMemo } from "react";
import { Tab } from './Tab' import { Tab } from "./Tab";
import { TabPanel } from './TabPanel' import { TabPanel } from "./TabPanel";
export const usePrefixedTabIds = () => { export const usePrefixedTabIds = () => {
const seed = useMemo(() => Math.random().toString().split('.')[1], []) const seed = useMemo(() => Math.random().toString().split(".")[1], []);
return useCallback((id) => `${seed}-${id}`, [seed]) return useCallback((id) => `${seed}-${id}`, [seed]);
} };
export const useTabsChildren = (children, prefixId) => { export const useTabsChildren = (children, prefixId) => {
const childrenArray = useMemo(() => Children.toArray(children), [children]) const childrenArray = useMemo(() => Children.toArray(children), [children]);
const tabs = useMemo(() => childrenArray.filter(({ type }) => type === Tab), [childrenArray]) const tabs = useMemo(() => childrenArray.filter(({ type }) => type === Tab), [childrenArray]);
const panels = useMemo(() => childrenArray.filter(({ type }) => type === TabPanel), [childrenArray]) const panels = useMemo(() => childrenArray.filter(({ type }) => type === TabPanel), [childrenArray]);
const tabsRefs = useMemo( const tabsRefs = useMemo(
() => () =>
tabs.reduce( tabs.reduce(
@ -23,11 +23,11 @@ export const useTabsChildren = (children, prefixId) => {
{} {}
), ),
[tabs, prefixId] [tabs, prefixId]
) );
return { return {
tabs, tabs,
panels, panels,
tabsRefs, tabsRefs,
} };
} };

View File

@ -1,3 +1,3 @@
export * from './Tab' export * from "./Tab";
export * from './Tabs' export * from "./Tabs";
export * from './TabPanel' export * from "./TabPanel";

View File

@ -1,4 +1,4 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
/** /**
* Primary UI component for user interaction * Primary UI component for user interaction
@ -7,25 +7,25 @@ export const TextIndicator = ({ variant }) => {
return ( return (
<div <div
className={`flex justify-center items-center w-textIndicator h-textIndicator text-textIndicator font-sans uppercase tracking-wide text-button bg-opacity-10 ${ className={`flex justify-center items-center w-textIndicator h-textIndicator text-textIndicator font-sans uppercase tracking-wide text-button bg-opacity-10 ${
variant === 'success' variant === "success"
? 'text-primary bg-primary' ? "text-primary bg-primary"
: variant === 'next' : variant === "next"
? 'text-next bg-next' ? "text-next bg-next"
: 'text-error bg-error' : "text-error bg-error"
}`} }`}
> >
{variant === 'success' ? 'success' : variant === 'next' ? 'next' : 'error'} {variant === "success" ? "success" : variant === "next" ? "next" : "error"}
</div> </div>
) );
} };
TextIndicator.propTypes = { TextIndicator.propTypes = {
/** /**
* Variant of text indicator * Variant of text indicator
*/ */
variant: PropTypes.oneOf(['success', 'next', 'error']), variant: PropTypes.oneOf(["success", "next", "error"]),
} };
TextIndicator.defaultProps = { TextIndicator.defaultProps = {
variant: 'success', variant: "success",
} };

View File

@ -1,27 +1,27 @@
import { TextIndicator } from './TextIndicator' import { TextIndicator } from "./TextIndicator";
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default { export default {
title: 'SkynetLibrary/TextIndicator', title: "SkynetLibrary/TextIndicator",
component: TextIndicator, component: TextIndicator,
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
} };
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Template = (args) => <TextIndicator {...args} /> const Template = (args) => <TextIndicator {...args} />;
export const Success = Template.bind({}) export const Success = Template.bind({});
// More on args: https://storybook.js.org/docs/react/writing-stories/args // More on args: https://storybook.js.org/docs/react/writing-stories/args
Success.args = { Success.args = {
variant: 'success', variant: "success",
} };
export const Next = Template.bind({}) export const Next = Template.bind({});
Next.args = { Next.args = {
variant: 'next', variant: "next",
} };
export const Error = Template.bind({}) export const Error = Template.bind({});
Error.args = { Error.args = {
variant: 'error', variant: "error",
} };

View File

@ -1 +1 @@
export * from './TextIndicator' export * from "./TextIndicator";

View File

@ -1,22 +1,22 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
/** /**
* Primary UI component for user interaction * Primary UI component for user interaction
*/ */
export const TextInputBasic = ({ label, placeholder }) => { export const TextInputBasic = ({ label, placeholder }) => {
return ( return (
<div className={''}> <div className={""}>
<p className={'font-sans uppercase text-palette-300 text-inputLabel mb-textInputLabelBottom'}>{label}</p> <p className={"font-sans uppercase text-palette-300 text-inputLabel mb-textInputLabelBottom"}>{label}</p>
<input <input
placeholder={placeholder} placeholder={placeholder}
className={ className={
'w-full bg-palette-100 h-textInput px-textInputBasicX focus:outline-none bg-transparent ' + "w-full bg-palette-100 h-textInput px-textInputBasicX focus:outline-none bg-transparent " +
'placeholder-palette-400 text-content tracking-inputPlaceholder text-textInput' "placeholder-palette-400 text-content tracking-inputPlaceholder text-textInput"
} }
/> />
</div> </div>
) );
} };
TextInputBasic.propTypes = { TextInputBasic.propTypes = {
/** /**
@ -27,4 +27,4 @@ TextInputBasic.propTypes = {
* Input placeholder * Input placeholder
*/ */
placeholder: PropTypes.string, placeholder: PropTypes.string,
} };

View File

@ -1,18 +1,18 @@
import { TextInputBasic } from './TextInputBasic' import { TextInputBasic } from "./TextInputBasic";
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default { export default {
title: 'SkynetLibrary/TextInputBasic', title: "SkynetLibrary/TextInputBasic",
component: TextInputBasic, component: TextInputBasic,
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
} };
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Template = (args) => <TextInputBasic {...args} /> const Template = (args) => <TextInputBasic {...args} />;
export const Input = Template.bind({}) export const Input = Template.bind({});
// More on args: https://storybook.js.org/docs/react/writing-stories/args // More on args: https://storybook.js.org/docs/react/writing-stories/args
Input.args = { Input.args = {
label: 'Display Name', label: "Display Name",
placeholder: 'Your Name', placeholder: "Your Name",
} };

View File

@ -1 +1 @@
export * from './TextInputBasic' export * from "./TextInputBasic";

View File

@ -1,23 +1,23 @@
import PropTypes from 'prop-types' import PropTypes from "prop-types";
/** /**
* Primary UI component for user interaction * Primary UI component for user interaction
*/ */
export const TextInputIcon = ({ icon, position, placeholder }) => { export const TextInputIcon = ({ icon, position, placeholder }) => {
return ( return (
<div className={'flex flex-row items-center px-textInputIcon h-textInput rounded-full bg-palette-100'}> <div className={"flex flex-row items-center px-textInputIcon h-textInput rounded-full bg-palette-100"}>
{position === 'left' ? <div className={'w-buttonIconLg h-buttonIconLg'}>{icon}</div> : null} {position === "left" ? <div className={"w-buttonIconLg h-buttonIconLg"}>{icon}</div> : null}
<input <input
placeholder={placeholder} placeholder={placeholder}
className={ className={
'w-full focus:outline-none mx-textInputHorizontal rounded-full bg-transparent ' + "w-full focus:outline-none mx-textInputHorizontal rounded-full bg-transparent " +
'placeholder-palette-400 text-content tracking-inputPlaceholder text-textInput' "placeholder-palette-400 text-content tracking-inputPlaceholder text-textInput"
} }
/> />
{position === 'right' ? <div className={'w-buttonIconLg h-buttonIconLg'}>{icon}</div> : null} {position === "right" ? <div className={"w-buttonIconLg h-buttonIconLg"}>{icon}</div> : null}
</div> </div>
) );
} };
TextInputIcon.propTypes = { TextInputIcon.propTypes = {
/** /**
@ -27,9 +27,9 @@ TextInputIcon.propTypes = {
/** /**
* Side to place icon * Side to place icon
*/ */
position: PropTypes.oneOf(['left', 'right']), position: PropTypes.oneOf(["left", "right"]),
/** /**
* Input placeholder * Input placeholder
*/ */
placeholder: PropTypes.string, placeholder: PropTypes.string,
} };

View File

@ -1,27 +1,27 @@
import { TextInputIcon } from './TextInputIcon' import { TextInputIcon } from "./TextInputIcon";
import { CogIcon } from '../Icons' import { CogIcon } from "../Icons";
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default { export default {
title: 'SkynetLibrary/TextInputIcon', title: "SkynetLibrary/TextInputIcon",
component: TextInputIcon, component: TextInputIcon,
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
} };
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Template = (args) => <TextInputIcon {...args} /> const Template = (args) => <TextInputIcon {...args} />;
export const IconLeft = Template.bind({}) export const IconLeft = Template.bind({});
// More on args: https://storybook.js.org/docs/react/writing-stories/args // More on args: https://storybook.js.org/docs/react/writing-stories/args
IconLeft.args = { IconLeft.args = {
icon: <CogIcon />, icon: <CogIcon />,
position: 'left', position: "left",
placeholder: 'Search', placeholder: "Search",
} };
export const IconRight = Template.bind({}) export const IconRight = Template.bind({});
IconRight.args = { IconRight.args = {
icon: <CogIcon />, icon: <CogIcon />,
position: 'right', position: "right",
placeholder: 'Search', placeholder: "Search",
} };

View File

@ -1 +1 @@
export * from './TextInputIcon' export * from "./TextInputIcon";

View File

@ -34,8 +34,8 @@ module.exports = {
content: ["Source\\ Sans\\ Pro", ...defaultTheme.fontFamily.sans], content: ["Source\\ Sans\\ Pro", ...defaultTheme.fontFamily.sans],
}, },
fontSize: { fontSize: {
body: ['21px', { lineHeight: '1.58' }], body: ["21px", { lineHeight: "1.58" }],
tab: ['18px', '28px'], tab: ["18px", "28px"],
}, },
backgroundColor: ["disabled"], backgroundColor: ["disabled"],
textColor: ["disabled"], textColor: ["disabled"],
@ -55,7 +55,7 @@ module.exports = {
"page-xl": "1312px", "page-xl": "1312px",
}, },
minWidth: { minWidth: {
button: '112px', button: "112px",
}, },
}, },
}, },