= (args) => ;
+export const Basic = {
+ args: {
+ label: 'Click Me',
+ size: 'md',
+ variant: 'primary',
+ },
+};
-export const PrimaryButton = Template.bind({});
+export function Variant() {
+ return (
+
+ {buttonVariants.map((variant) => (
+
+ ))}
+
+ );
+}
-PrimaryButton.args = {
- label: 'Button text',
- size: 'md',
- variant: 'primary',
-};
+export function Size() {
+ return (
+
+ {buttonSizes.map((size) => (
+
+ ))}
+
+ );
+}
-export const SecondaryButton = Template.bind({});
+export function Display() {
+ return (
+
+ {buttonSizes.map((size) => (
+
+ ))}
+
+ );
+}
-SecondaryButton.args = {
- label: 'Button text',
- size: 'md',
- variant: 'secondary',
-};
+export function Disabled() {
+ return (
+
+ {buttonVariants.map((variant) => (
+
+ ))}
+
+ );
+}
+
+export function Loading() {
+ return (
+
+
+ {buttonVariants.map((variant) => (
+
+ ))}
+
+
+ {buttonVariants.map((variant) => (
+
+ ))}
+
+
+ );
+}
+
+export function Icons() {
+ return (
+
+
+ {buttonSizes.map((size) => (
+
+ ))}
+
+
+
+ {buttonSizes.map((size) => (
+
+ ))}
+
+
+
+ {buttonSizes.map((size) => (
+
+ ))}
+
+
+
+ );
+}
+
+export function HiddenLabel() {
+ return (
+
+ {buttonSizes.map((size) => (
+
+ ))}
+
+
+ );
+}
diff --git a/apps/storybook/stories/counterbutton.stories.mdx b/apps/storybook/stories/counterbutton.stories.mdx
deleted file mode 100644
index af87316a..00000000
--- a/apps/storybook/stories/counterbutton.stories.mdx
+++ /dev/null
@@ -1,20 +0,0 @@
-import { CounterButton } from '@tih/ui';
-import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs';
-
-
-
-# Button
-
-Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec euismod, nisl eget consectetur tempor, nisl nunc egestas nisi, euismod aliquam nisl nunc euismod.
-
-## Props
-
-
-
-## Examples
-
-
diff --git a/apps/storybook/stories/spinner.stories.tsx b/apps/storybook/stories/spinner.stories.tsx
new file mode 100644
index 00000000..609aefa6
--- /dev/null
+++ b/apps/storybook/stories/spinner.stories.tsx
@@ -0,0 +1,57 @@
+import { ComponentMeta } from '@storybook/react';
+
+import { Spinner, SpinnerColor, SpinnerSize, SpinnerDisplay } from '@tih/ui';
+import React from 'react';
+
+const spinnerColors: ReadonlyArray = ['default', 'inherit'];
+const spinnerDisplays: ReadonlyArray = ['block', 'inline'];
+const spinnerSizes: ReadonlyArray = ['xs', 'sm', 'md', 'lg'];
+
+export default {
+ title: 'Spinner',
+ component: Spinner,
+ argTypes: {
+ color: {
+ options: spinnerColors,
+ control: { type: 'select' },
+ },
+ display: {
+ options: spinnerDisplays,
+ control: { type: 'select' },
+ },
+ label: {
+ control: 'string',
+ },
+ size: {
+ options: spinnerSizes,
+ control: { type: 'select' },
+ },
+ },
+} as ComponentMeta;
+
+export const Basic = {
+ args: {
+ label: 'Loading data',
+ size: 'md',
+ },
+};
+
+export function Size() {
+ return (
+
+ {spinnerSizes.map((size) => (
+
+ ))}
+
+ );
+}
+
+export function Display() {
+ return (
+
+ {spinnerSizes.map((size) => (
+
+ ))}
+
+ );
+}
diff --git a/apps/storybook/tailwind.config.js b/apps/storybook/tailwind.config.js
new file mode 100644
index 00000000..f023466b
--- /dev/null
+++ b/apps/storybook/tailwind.config.js
@@ -0,0 +1,7 @@
+const config = require('@tih/tailwind-config/tailwind.config.js');
+
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ ...config,
+ content: [...config.content, './stories/**/*.{js,jsx,ts,tsx,md,mdx}'],
+};
diff --git a/packages/ui/package.json b/packages/ui/package.json
index e9aeb9fd..5e92810e 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -30,6 +30,7 @@
"@tih/tsconfig": "*",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
+ "autoprefixer": "^10.4.12",
"concurrently": "^7.4.0",
"eslint": "^8.24.0",
"eslint-config-tih": "*",
diff --git a/packages/ui/src/Button/Button.tsx b/packages/ui/src/Button/Button.tsx
index edb7f00b..d95906a7 100644
--- a/packages/ui/src/Button/Button.tsx
+++ b/packages/ui/src/Button/Button.tsx
@@ -4,8 +4,10 @@ import type { UrlObject } from 'url';
import Spinner from '../Spinner';
+export type ButtonAddOnPosition = 'end' | 'start';
export type ButtonDisplay = 'block' | 'inline';
export type ButtonSize = 'lg' | 'md' | 'sm';
+export type ButtonType = 'button' | 'reset' | 'submit';
export type ButtonVariant =
| 'primary'
| 'secondary'
@@ -14,7 +16,7 @@ export type ButtonVariant =
| 'tertiary';
type Props = Readonly<{
- addonPosition?: 'end' | 'start';
+ addonPosition?: ButtonAddOnPosition;
'aria-controls'?: string;
className?: string;
display?: ButtonDisplay;
@@ -26,7 +28,7 @@ type Props = Readonly<{
label: string;
onClick?: (event: React.MouseEvent) => void;
size?: ButtonSize;
- type?: 'button' | 'submit';
+ type?: ButtonType;
variant: ButtonVariant;
}>;
diff --git a/packages/ui/src/CounterButton.tsx b/packages/ui/src/CounterButton.tsx
deleted file mode 100644
index 6a9017c7..00000000
--- a/packages/ui/src/CounterButton.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import * as React from 'react';
-
-export function CounterButton() {
- const [count, setCount] = React.useState(0);
- return (
-
-
- This component is from{' '}
-
- @tih/ui
-
-
-
-
-
-
- );
-}
diff --git a/packages/ui/src/NewTabLink.tsx b/packages/ui/src/NewTabLink.tsx
deleted file mode 100644
index 86c240e8..00000000
--- a/packages/ui/src/NewTabLink.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import * as React from 'react';
-export function NewTabLink({
- children,
- href,
- ...other
-}: {
- children: React.ReactNode;
- href: string;
-}) {
- return (
-
- {children}
-
- );
-}
diff --git a/packages/ui/src/index.tsx b/packages/ui/src/index.tsx
index 00b92547..215b15fe 100644
--- a/packages/ui/src/index.tsx
+++ b/packages/ui/src/index.tsx
@@ -1,4 +1,4 @@
export { default as Button } from './Button';
export * from './Button';
-export { CounterButton } from './CounterButton';
-export { NewTabLink } from './NewTabLink';
+export { default as Spinner } from './Spinner';
+export * from './Spinner';
diff --git a/yarn.lock b/yarn.lock
index c33d6b77..999d5e87 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2372,6 +2372,17 @@
regenerator-runtime "^0.13.7"
ts-dedent "^2.0.0"
+"@storybook/addon-postcss@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@storybook/addon-postcss/-/addon-postcss-2.0.0.tgz#ec61cb9bb2662f408072b35c466c7df801c28498"
+ integrity sha512-Nt82A7e9zJH4+A+VzLKKswUfru+T6FJTakj4dccP0i8DSn7a0CkzRPrLuZBq8tg4voV6gD74bcDf3gViCVBGtA==
+ dependencies:
+ "@storybook/node-logger" "^6.1.14"
+ css-loader "^3.6.0"
+ postcss "^7.0.35"
+ postcss-loader "^4.2.0"
+ style-loader "^1.3.0"
+
"@storybook/addon-toolbars@6.5.12":
version "6.5.12"
resolved "https://registry.yarnpkg.com/@storybook/addon-toolbars/-/addon-toolbars-6.5.12.tgz#ea81c63ae56eae8bc1d3b5a358cff66ae5a2d66e"
@@ -2858,7 +2869,7 @@
prettier ">=2.2.1 <=2.3.0"
ts-dedent "^2.0.0"
-"@storybook/node-logger@6.5.12":
+"@storybook/node-logger@6.5.12", "@storybook/node-logger@^6.1.14":
version "6.5.12"
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-6.5.12.tgz#0f9efcd1a37c7aae493b22fe33cacca87c135b9b"
integrity sha512-jdLtT3mX5GQKa+0LuX0q0sprKxtCGf6HdXlKZGD5FEuz4MgJUGaaiN0Hgi+U7Z4tVNOtSoIbYBYXHqfUgJrVZw==
@@ -11442,7 +11453,7 @@ postcss@8.4.14:
picocolors "^1.0.0"
source-map-js "^1.0.2"
-postcss@^7.0.14, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.36, postcss@^7.0.5, postcss@^7.0.6:
+postcss@^7.0.14, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.35, postcss@^7.0.36, postcss@^7.0.5, postcss@^7.0.6:
version "7.0.39"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309"
integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==