@mbao01/ui 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -0
- package/dist/index.d.ts +1 -0
- package/package.json +74 -0
- package/plugin.d.ts +4 -0
- package/plugin.js +10 -0
- package/src/components/Button/Button.stories.ts +77 -0
- package/src/components/Button/Button.tsx +37 -0
- package/src/components/Button/constants.ts +44 -0
- package/src/components/Button/index.ts +1 -0
- package/src/components/Button/types.ts +26 -0
- package/src/index.ts +1 -0
- package/src/tailwind.css +25 -0
- package/src/vite-env.d.ts +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
So here it is, I have gotten really bored creating UI component from scratch for the many projects I work on.
|
|
2
|
+
It is high time I have a unified component library - so here it is.
|
|
3
|
+
I have built this to be highly opinionated on certain libraries I love to use like typescript, tailwind, date-fns, and react.
|
|
4
|
+
|
|
5
|
+
I believe in future this UI component library may extend to meta frameworks like [Next.js](https://nextjs.org/), [Remix](https://remix.run/) and even [Nuxt](https://nuxt.com/) (and naturally [Vue.js](https://vuejs.org/) as well).
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Description
|
|
9
|
+
|
|
10
|
+
The library is written using [React](https://react.dev/), [Tailwind](https://tailwindcss.com/), [Typescript](https://www.typescriptlang.org/) and [Vite](https://vitejs.dev/). The library is uncooked which means there is no build step involved which means you'd have to cater for building the components into your library.
|
|
11
|
+
|
|
12
|
+
# Consuming the library
|
|
13
|
+
|
|
14
|
+
1. Ensure you have react and typescript install and setup in your project.
|
|
15
|
+
Then install the library
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add @mbao01/ui
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
or
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @mbao01/ui
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
2. Install tailwind - do so by following the [installation guide](https://tailwindcss.com/docs/installation)
|
|
28
|
+
|
|
29
|
+
3. Configure tailwind
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
const plugin = require("@mbao01/ui/plugin") // -> import the library plugin
|
|
33
|
+
|
|
34
|
+
export default {
|
|
35
|
+
...plugin.config, // -> add the library plugin config
|
|
36
|
+
content: [
|
|
37
|
+
"./src/**/*.{js,ts,jsx,tsx,mdx}",
|
|
38
|
+
"node_modules/@mbao01/ui/src/**/*.{js,ts,jsx,tsx,mdx}" // -> ensure to add this to allow tailwind to scan the library for classes
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./components/Button";
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mbao01/ui",
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"author": "Ayomide Bakare",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"description": "A fully ready-to-consume component library available in different frontend frameworks",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"react",
|
|
11
|
+
"components",
|
|
12
|
+
"ui",
|
|
13
|
+
"library"
|
|
14
|
+
],
|
|
15
|
+
"main": "./src/index.ts",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"files": [
|
|
18
|
+
"src",
|
|
19
|
+
"plugin.js",
|
|
20
|
+
"plugin.d.ts",
|
|
21
|
+
"dist/index.d.ts"
|
|
22
|
+
],
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"scripts": {
|
|
25
|
+
"dev": "storybook dev -p 6006",
|
|
26
|
+
"build": "tsc && vite build",
|
|
27
|
+
"build-storybook": "storybook build",
|
|
28
|
+
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
|
29
|
+
"preview": "vite preview"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"autoprefixer": "^10.4.16",
|
|
33
|
+
"clsx": "^2.0.0",
|
|
34
|
+
"daisyui": "^4.4.24"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@storybook/addon-essentials": "^7.6.6",
|
|
38
|
+
"@storybook/addon-interactions": "^7.6.6",
|
|
39
|
+
"@storybook/addon-links": "^7.6.6",
|
|
40
|
+
"@storybook/addon-onboarding": "^1.0.10",
|
|
41
|
+
"@storybook/addon-themes": "^7.6.6",
|
|
42
|
+
"@storybook/blocks": "^7.6.6",
|
|
43
|
+
"@storybook/react": "^7.6.6",
|
|
44
|
+
"@storybook/react-vite": "^7.6.6",
|
|
45
|
+
"@storybook/test": "^7.6.6",
|
|
46
|
+
"@types/node": "^20.10.5",
|
|
47
|
+
"@types/react": "^18.2.43",
|
|
48
|
+
"@types/react-dom": "^18.2.17",
|
|
49
|
+
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
|
50
|
+
"@typescript-eslint/parser": "^6.14.0",
|
|
51
|
+
"@vitejs/plugin-react": "^4.2.1",
|
|
52
|
+
"eslint": "^8.55.0",
|
|
53
|
+
"eslint-plugin-react": "^7.33.2",
|
|
54
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
55
|
+
"eslint-plugin-react-refresh": "^0.4.5",
|
|
56
|
+
"eslint-plugin-storybook": "^0.6.15",
|
|
57
|
+
"path": "^0.12.7",
|
|
58
|
+
"postcss": "^8.4.32",
|
|
59
|
+
"react": "^18.2.0",
|
|
60
|
+
"react-dom": "^18.2.0",
|
|
61
|
+
"storybook": "^7.6.6",
|
|
62
|
+
"tailwindcss": "^3.4.0",
|
|
63
|
+
"typescript": "^5.2.2",
|
|
64
|
+
"vite": "^5.0.8",
|
|
65
|
+
"vite-plugin-dts": "^3.7.0"
|
|
66
|
+
},
|
|
67
|
+
"peerDependencies": {
|
|
68
|
+
"postcss": "^8.4.32",
|
|
69
|
+
"react": "^18.2.0",
|
|
70
|
+
"react-dom": "^18.2.0",
|
|
71
|
+
"tailwindcss": "^3.4.0",
|
|
72
|
+
"typescript": "^5.2.2"
|
|
73
|
+
}
|
|
74
|
+
}
|
package/plugin.d.ts
ADDED
package/plugin.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
|
|
3
|
+
import { Button } from './Button';
|
|
4
|
+
|
|
5
|
+
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
|
|
6
|
+
const meta = {
|
|
7
|
+
component: Button,
|
|
8
|
+
parameters: {
|
|
9
|
+
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/react/configure/story-layout
|
|
10
|
+
layout: 'centered',
|
|
11
|
+
},
|
|
12
|
+
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs
|
|
13
|
+
tags: ['autodocs'],
|
|
14
|
+
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes
|
|
15
|
+
argTypes: {},
|
|
16
|
+
} satisfies Meta<typeof Button>;
|
|
17
|
+
|
|
18
|
+
export default meta;
|
|
19
|
+
type Story = StoryObj<typeof meta>;
|
|
20
|
+
|
|
21
|
+
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
|
|
22
|
+
export const Default: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
variant: 'default',
|
|
25
|
+
label: 'Button',
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const PrimaryButton: Story = {
|
|
30
|
+
args: {
|
|
31
|
+
variant: 'primary',
|
|
32
|
+
label: 'Button',
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const WideButton: Story = {
|
|
37
|
+
args: {
|
|
38
|
+
wide: true,
|
|
39
|
+
label: 'Wide Button',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const TinyButton: Story = {
|
|
44
|
+
args: {
|
|
45
|
+
size: 'xs',
|
|
46
|
+
label: 'Tiny',
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const OutlineButton: Story = {
|
|
51
|
+
args: {
|
|
52
|
+
outline: true,
|
|
53
|
+
label: 'Click me!',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const DisabledButton: Story = {
|
|
58
|
+
args: {
|
|
59
|
+
disabled: true,
|
|
60
|
+
label: 'Click me?',
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const LoadingButton: Story = {
|
|
65
|
+
args: {
|
|
66
|
+
loading: true,
|
|
67
|
+
label: 'Loading',
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const BlockButton: Story = {
|
|
72
|
+
args: {
|
|
73
|
+
disabled: true,
|
|
74
|
+
className: 'btn-block',
|
|
75
|
+
label: 'Block Button',
|
|
76
|
+
},
|
|
77
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import c from "clsx";
|
|
2
|
+
import { getButtonClasses } from "./constants";
|
|
3
|
+
import { type ButtonProps } from "./types";
|
|
4
|
+
|
|
5
|
+
export const Button = (props: ButtonProps) => {
|
|
6
|
+
const {
|
|
7
|
+
className,
|
|
8
|
+
outline,
|
|
9
|
+
label,
|
|
10
|
+
disabled,
|
|
11
|
+
onClick,
|
|
12
|
+
loading,
|
|
13
|
+
variant,
|
|
14
|
+
size,
|
|
15
|
+
wide,
|
|
16
|
+
...rest
|
|
17
|
+
} = props;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<button
|
|
21
|
+
{...rest}
|
|
22
|
+
onClick={onClick}
|
|
23
|
+
disabled={disabled}
|
|
24
|
+
className={c(
|
|
25
|
+
getButtonClasses({ size, wide, outline, variant, loading }),
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
>
|
|
29
|
+
{label}
|
|
30
|
+
{loading ? (
|
|
31
|
+
<span className="absolute left-0 top-0 flex h-full w-full items-center justify-center bg-[inherit]">
|
|
32
|
+
<span className="loading loading-spinner" />
|
|
33
|
+
</span>
|
|
34
|
+
) : null}
|
|
35
|
+
</button>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import c from 'clsx';
|
|
2
|
+
import type { ButtonSize, ButtonVariant } from './types';
|
|
3
|
+
|
|
4
|
+
const BUTTON_SIZE = {
|
|
5
|
+
xs: c('btn-xs'),
|
|
6
|
+
sm: c('btn-sm'),
|
|
7
|
+
md: c('btn-md'),
|
|
8
|
+
lg: c('btn-lg'),
|
|
9
|
+
} satisfies Record<ButtonSize, string>;
|
|
10
|
+
|
|
11
|
+
const BUTTON_VARIANTS = {
|
|
12
|
+
accent: c('btn-accent'),
|
|
13
|
+
default: c('btn-default'),
|
|
14
|
+
error: c('btn-error'),
|
|
15
|
+
ghost: c('btn-ghost'),
|
|
16
|
+
info: c('btn-info'),
|
|
17
|
+
link: c('btn-link'),
|
|
18
|
+
neutral: c('btn-neutral'),
|
|
19
|
+
primary: c('btn-primary'),
|
|
20
|
+
secondary: c('btn-secondary'),
|
|
21
|
+
success: c('btn-success'),
|
|
22
|
+
warning: c('btn-warning'),
|
|
23
|
+
} satisfies Record<ButtonVariant, string>;
|
|
24
|
+
|
|
25
|
+
export const getButtonClasses = ({
|
|
26
|
+
size,
|
|
27
|
+
wide,
|
|
28
|
+
loading,
|
|
29
|
+
outline,
|
|
30
|
+
variant,
|
|
31
|
+
}: {
|
|
32
|
+
size?: ButtonSize;
|
|
33
|
+
wide?: boolean;
|
|
34
|
+
loading?: boolean;
|
|
35
|
+
outline?: boolean;
|
|
36
|
+
variant?: ButtonVariant;
|
|
37
|
+
}) => {
|
|
38
|
+
return c('btn', BUTTON_VARIANTS[variant!], BUTTON_SIZE[size!], {
|
|
39
|
+
'btn-outline': outline,
|
|
40
|
+
'btn-wide': wide,
|
|
41
|
+
'relative overflow-hidden': loading,
|
|
42
|
+
'min-h-fit h-10': !size,
|
|
43
|
+
});
|
|
44
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Button } from "./Button";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';
|
|
4
|
+
|
|
5
|
+
export type ButtonVariant =
|
|
6
|
+
| 'default'
|
|
7
|
+
| 'neutral'
|
|
8
|
+
| 'primary'
|
|
9
|
+
| 'secondary'
|
|
10
|
+
| 'accent'
|
|
11
|
+
| 'ghost'
|
|
12
|
+
| 'link'
|
|
13
|
+
| 'info'
|
|
14
|
+
| 'success'
|
|
15
|
+
| 'warning'
|
|
16
|
+
| 'error';
|
|
17
|
+
|
|
18
|
+
export type ButtonProps = {
|
|
19
|
+
size?: ButtonSize;
|
|
20
|
+
wide?: boolean;
|
|
21
|
+
label: ReactNode;
|
|
22
|
+
loading?: boolean;
|
|
23
|
+
outline?: boolean;
|
|
24
|
+
variant?: ButtonVariant;
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
} & ButtonHTMLAttributes<HTMLButtonElement>;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./components/Button";
|
package/src/tailwind.css
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
.scroll-shadow {
|
|
6
|
+
background-image: linear-gradient(to top, white, white),
|
|
7
|
+
linear-gradient(to top, white, white),
|
|
8
|
+
linear-gradient(to top, rgba(100, 100, 100, 0.25), rgba(255, 255, 255, 0)),
|
|
9
|
+
linear-gradient(to bottom, rgba(100, 100, 100, 0.25), rgba(255, 255, 255, 0));
|
|
10
|
+
background-position: bottom center, top center, bottom center, top center;
|
|
11
|
+
background-color: white;
|
|
12
|
+
background-repeat: no-repeat;
|
|
13
|
+
background-size: 100% 12px, 100% 12px, 100% 10px, 100% 10px;
|
|
14
|
+
background-attachment: local, local, scroll, scroll;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
input[type=number]::-webkit-outer-spin-button,
|
|
18
|
+
input[type=number]::-webkit-inner-spin-button {
|
|
19
|
+
-webkit-appearance: none;
|
|
20
|
+
margin: 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
input[type=number] {
|
|
24
|
+
-moz-appearance: textfield;
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|