gox-design-system 0.0.6 → 0.0.8
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/.storybook/main.js +9 -0
- package/package.json +8 -6
- package/src/App.tsx +4 -16
- package/src/components/Avatar.tsx +23 -0
- package/src/components/Badge.tsx +21 -0
- package/src/components/BreadCrumb.tsx +27 -0
- package/src/components/Button.tsx +22 -0
- package/src/components/Card.tsx +20 -0
- package/src/components/Checkbox.tsx +26 -0
- package/src/components/Input.tsx +24 -0
- package/src/components/Label.tsx +15 -0
- package/src/components/Link.tsx +15 -0
- package/src/components/Modal.tsx +38 -0
- package/src/components/Tabs.tsx +36 -0
- package/src/components/index.ts +8 -0
- package/src/index.tsx +1 -4
- package/src/styles/global.css +19 -0
- package/src/theme/ThemeProvider.tsx +22 -0
- package/src/components/input/index.tsx +0 -49
package/package.json
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "gox-design-system",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.8",
|
4
4
|
"private": false,
|
5
|
-
"main": "./index.js",
|
6
|
-
"module": "./index.js",
|
7
5
|
"dependencies": {
|
8
6
|
"@testing-library/dom": "^10.4.0",
|
9
7
|
"@testing-library/jest-dom": "^6.6.3",
|
@@ -17,15 +15,19 @@
|
|
17
15
|
"react-dom": "^19.0.0",
|
18
16
|
"react-scripts": "^5.0.1",
|
19
17
|
"tsc": "^2.0.4",
|
20
|
-
"typescript": "^4.
|
21
|
-
"web-vitals": "^2.1.4"
|
18
|
+
"typescript": "^5.4.5 ",
|
19
|
+
"web-vitals": "^2.1.4",
|
20
|
+
"styled-components": "^5.3.10",
|
21
|
+
"polished": "^4.2.2"
|
22
22
|
},
|
23
23
|
"scripts": {
|
24
24
|
"start": "react-scripts start",
|
25
25
|
"build": "react-scripts build",
|
26
26
|
"test": "react-scripts test",
|
27
27
|
"eject": "react-scripts eject",
|
28
|
-
"compile": "npx tsc"
|
28
|
+
"compile": "npx tsc",
|
29
|
+
"storybook": "start-storybook -p 6006",
|
30
|
+
"build-storybook": "build-storybook"
|
29
31
|
},
|
30
32
|
"eslintConfig": {
|
31
33
|
"extends": [
|
package/src/App.tsx
CHANGED
@@ -1,24 +1,12 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import
|
3
|
-
import './App.css';
|
2
|
+
import { Input } from './components'; // Assuming Input is defined in a file named Input.tsx
|
4
3
|
|
5
4
|
function App() {
|
6
5
|
return (
|
7
6
|
<div className="App">
|
8
|
-
<
|
9
|
-
|
10
|
-
|
11
|
-
Edit <code>src/App.tsx</code> and save to reload.
|
12
|
-
</p>
|
13
|
-
<a
|
14
|
-
className="App-link"
|
15
|
-
href="https://reactjs.org"
|
16
|
-
target="_blank"
|
17
|
-
rel="noopener noreferrer"
|
18
|
-
>
|
19
|
-
Learn React
|
20
|
-
</a>
|
21
|
-
</header>
|
7
|
+
<Input placeholder={''} value={''} onChange={function (e: React.ChangeEvent<HTMLInputElement>): void {
|
8
|
+
throw new Error('Function not implemented.');
|
9
|
+
} }/>
|
22
10
|
</div>
|
23
11
|
);
|
24
12
|
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
interface AvatarProps {
|
4
|
+
src: string;
|
5
|
+
alt: string;
|
6
|
+
size?: 'small' | 'medium' | 'large';
|
7
|
+
}
|
8
|
+
|
9
|
+
export const Avatar = ({ src, alt, size = 'medium' }: AvatarProps) => {
|
10
|
+
const sizeClasses = {
|
11
|
+
small: 'w-8 h-8',
|
12
|
+
medium: 'w-12 h-12',
|
13
|
+
large: 'w-16 h-16',
|
14
|
+
};
|
15
|
+
|
16
|
+
return (
|
17
|
+
<img
|
18
|
+
src={src}
|
19
|
+
alt={alt}
|
20
|
+
className={`rounded-full ${sizeClasses[size]} object-cover`}
|
21
|
+
/>
|
22
|
+
);
|
23
|
+
};
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
interface BadgeProps {
|
4
|
+
label: string;
|
5
|
+
color?: 'blue' | 'green' | 'red' | 'gray';
|
6
|
+
}
|
7
|
+
|
8
|
+
export const Badge = ({ label, color = 'gray' }: BadgeProps) => {
|
9
|
+
const colorClasses = {
|
10
|
+
blue: 'bg-blue-500 text-white',
|
11
|
+
green: 'bg-green-500 text-white',
|
12
|
+
red: 'bg-red-500 text-white',
|
13
|
+
gray: 'bg-gray-500 text-white',
|
14
|
+
};
|
15
|
+
|
16
|
+
return (
|
17
|
+
<span className={`px-2 py-1 text-sm rounded ${colorClasses[color]}`}>
|
18
|
+
{label}
|
19
|
+
</span>
|
20
|
+
);
|
21
|
+
};
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { Link } from './Link';
|
3
|
+
|
4
|
+
interface BreadCrumbItem {
|
5
|
+
label: string;
|
6
|
+
href: string;
|
7
|
+
}
|
8
|
+
|
9
|
+
interface BreadCrumbProps {
|
10
|
+
items: BreadCrumbItem[];
|
11
|
+
className?: string;
|
12
|
+
}
|
13
|
+
|
14
|
+
export const BreadCrumb = ({ items, className = '' }: BreadCrumbProps) => {
|
15
|
+
return (
|
16
|
+
<nav className={`flex space-x-2 ${className}`} aria-label="breadcrumb">
|
17
|
+
{items.map((item, index) => (
|
18
|
+
<React.Fragment key={index}>
|
19
|
+
<Link href={item.href} className="text-gray-500 hover:text-gray-700">
|
20
|
+
{item.label}
|
21
|
+
</Link>
|
22
|
+
{index < items.length - 1 && <span className="text-gray-400">/</span>}
|
23
|
+
</React.Fragment>
|
24
|
+
))}
|
25
|
+
</nav>
|
26
|
+
);
|
27
|
+
};
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useTheme } from '../theme/ThemeProvider';
|
3
|
+
|
4
|
+
interface ButtonProps {
|
5
|
+
label: string;
|
6
|
+
onClick: () => void;
|
7
|
+
}
|
8
|
+
|
9
|
+
export const Button = ({ label, onClick }: ButtonProps) => {
|
10
|
+
const { theme } = useTheme();
|
11
|
+
|
12
|
+
return (
|
13
|
+
<button
|
14
|
+
onClick={onClick}
|
15
|
+
className={`px-4 py-2 rounded ${
|
16
|
+
theme === 'light' ? 'bg-blue-500 text-white' : 'bg-gray-700 text-gray-200'
|
17
|
+
}`}
|
18
|
+
>
|
19
|
+
{label}
|
20
|
+
</button>
|
21
|
+
);
|
22
|
+
};
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import React, { ReactNode } from 'react';
|
2
|
+
import { useTheme } from '../theme/ThemeProvider';
|
3
|
+
|
4
|
+
interface CardProps {
|
5
|
+
children: ReactNode;
|
6
|
+
}
|
7
|
+
|
8
|
+
export const Card = ({ children }: CardProps) => {
|
9
|
+
const { theme } = useTheme();
|
10
|
+
|
11
|
+
return (
|
12
|
+
<div
|
13
|
+
className={`p-4 rounded shadow ${
|
14
|
+
theme === 'light' ? 'bg-white text-black' : 'bg-gray-800 text-gray-100'
|
15
|
+
}`}
|
16
|
+
>
|
17
|
+
{children}
|
18
|
+
</div>
|
19
|
+
);
|
20
|
+
};
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useTheme } from '../theme/ThemeProvider';
|
3
|
+
|
4
|
+
interface CheckboxProps {
|
5
|
+
label: string;
|
6
|
+
checked: boolean;
|
7
|
+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
8
|
+
}
|
9
|
+
|
10
|
+
export const Checkbox = ({ label, checked, onChange }: CheckboxProps) => {
|
11
|
+
const { theme } = useTheme();
|
12
|
+
|
13
|
+
return (
|
14
|
+
<label className="flex items-center space-x-2">
|
15
|
+
<input
|
16
|
+
type="checkbox"
|
17
|
+
checked={checked}
|
18
|
+
onChange={onChange}
|
19
|
+
className={`rounded ${
|
20
|
+
theme === 'light' ? 'text-blue-500' : 'text-gray-400'
|
21
|
+
}`}
|
22
|
+
/>
|
23
|
+
<span className={theme === 'light' ? 'text-black' : 'text-gray-100'}>{label}</span>
|
24
|
+
</label>
|
25
|
+
);
|
26
|
+
};
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useTheme } from '../theme/ThemeProvider';
|
3
|
+
|
4
|
+
interface InputProps {
|
5
|
+
placeholder: string;
|
6
|
+
value: string;
|
7
|
+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
8
|
+
}
|
9
|
+
|
10
|
+
export const Input = ({ placeholder, value, onChange }: InputProps) => {
|
11
|
+
const { theme } = useTheme();
|
12
|
+
|
13
|
+
return (
|
14
|
+
<input
|
15
|
+
type="text"
|
16
|
+
value={value}
|
17
|
+
onChange={onChange}
|
18
|
+
placeholder={placeholder}
|
19
|
+
className={`px-3 py-2 rounded border ${
|
20
|
+
theme === 'light' ? 'border-gray-300 bg-white text-black' : 'border-gray-600 bg-gray-800 text-gray-100'
|
21
|
+
}`}
|
22
|
+
/>
|
23
|
+
);
|
24
|
+
};
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
interface LabelProps {
|
4
|
+
text: string;
|
5
|
+
htmlFor?: string;
|
6
|
+
className?: string;
|
7
|
+
}
|
8
|
+
|
9
|
+
export const Label = ({ text, htmlFor, className = '' }: LabelProps) => {
|
10
|
+
return (
|
11
|
+
<label htmlFor={htmlFor} className={`text-gray-700 ${className}`}>
|
12
|
+
{text}
|
13
|
+
</label>
|
14
|
+
);
|
15
|
+
};
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
interface LinkProps {
|
4
|
+
href: string;
|
5
|
+
children: React.ReactNode;
|
6
|
+
className?: string;
|
7
|
+
}
|
8
|
+
|
9
|
+
export const Link = ({ href, children, className = '' }: LinkProps) => {
|
10
|
+
return (
|
11
|
+
<a href={href} className={`text-blue-500 hover:underline ${className}`}>
|
12
|
+
{children}
|
13
|
+
</a>
|
14
|
+
);
|
15
|
+
};
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import React, { ReactNode } from 'react';
|
2
|
+
import { useTheme } from '../theme/ThemeProvider';
|
3
|
+
|
4
|
+
interface ModalProps {
|
5
|
+
isOpen: boolean;
|
6
|
+
onClose: () => void;
|
7
|
+
children: ReactNode;
|
8
|
+
}
|
9
|
+
|
10
|
+
export const Modal = ({ isOpen, onClose, children }: ModalProps) => {
|
11
|
+
const { theme } = useTheme();
|
12
|
+
|
13
|
+
if (!isOpen) return null;
|
14
|
+
|
15
|
+
return (
|
16
|
+
<div
|
17
|
+
className={`fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 ${
|
18
|
+
theme === 'light' ? 'text-black' : 'text-gray-100'
|
19
|
+
}`}
|
20
|
+
>
|
21
|
+
<div
|
22
|
+
className={`p-6 rounded shadow-lg ${
|
23
|
+
theme === 'light' ? 'bg-white' : 'bg-gray-800'
|
24
|
+
}`}
|
25
|
+
>
|
26
|
+
{children}
|
27
|
+
<button
|
28
|
+
onClick={onClose}
|
29
|
+
className={`mt-4 px-4 py-2 rounded ${
|
30
|
+
theme === 'light' ? 'bg-red-500 text-white' : 'bg-red-700 text-gray-200'
|
31
|
+
}`}
|
32
|
+
>
|
33
|
+
Close
|
34
|
+
</button>
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
);
|
38
|
+
};
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
|
3
|
+
interface Tab {
|
4
|
+
label: string;
|
5
|
+
content: React.ReactNode;
|
6
|
+
}
|
7
|
+
|
8
|
+
interface TabsProps {
|
9
|
+
tabs: Tab[];
|
10
|
+
defaultActiveTab?: number;
|
11
|
+
}
|
12
|
+
|
13
|
+
export const Tabs = ({ tabs, defaultActiveTab = 0 }: TabsProps) => {
|
14
|
+
const [activeTab, setActiveTab] = useState(defaultActiveTab);
|
15
|
+
|
16
|
+
return (
|
17
|
+
<div>
|
18
|
+
<div className="flex border-b">
|
19
|
+
{tabs.map((tab, index) => (
|
20
|
+
<button
|
21
|
+
key={index}
|
22
|
+
className={`px-4 py-2 -mb-px ${
|
23
|
+
activeTab === index
|
24
|
+
? 'border-b-2 border-blue-500 text-blue-500'
|
25
|
+
: 'text-gray-500'
|
26
|
+
}`}
|
27
|
+
onClick={() => setActiveTab(index)}
|
28
|
+
>
|
29
|
+
{tab.label}
|
30
|
+
</button>
|
31
|
+
))}
|
32
|
+
</div>
|
33
|
+
<div className="p-4">{tabs[activeTab]?.content}</div>
|
34
|
+
</div>
|
35
|
+
);
|
36
|
+
};
|
@@ -0,0 +1,8 @@
|
|
1
|
+
export { ThemeProvider, useTheme } from '../theme/ThemeProvider';
|
2
|
+
export { Button } from './Button';
|
3
|
+
export { Card } from './Card';
|
4
|
+
export { Input } from './Input';
|
5
|
+
export { Checkbox } from './Checkbox';
|
6
|
+
export { Modal } from './Modal';
|
7
|
+
export { Avatar } from './Avatar';
|
8
|
+
export { Badge } from './Badge';
|
package/src/index.tsx
CHANGED
@@ -3,16 +3,13 @@ import ReactDOM from 'react-dom/client';
|
|
3
3
|
import './index.css';
|
4
4
|
import App from './App';
|
5
5
|
import reportWebVitals from './reportWebVitals';
|
6
|
-
import Input from './components/input';
|
7
6
|
|
8
7
|
const root = ReactDOM.createRoot(
|
9
8
|
document.getElementById('root') as HTMLElement
|
10
9
|
);
|
11
10
|
root.render(
|
12
11
|
<React.StrictMode>
|
13
|
-
<
|
14
|
-
throw new Error('Function not implemented.');
|
15
|
-
} } />
|
12
|
+
<App/>
|
16
13
|
</React.StrictMode>
|
17
14
|
);
|
18
15
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
body.light {
|
2
|
+
background-color: #f9f9f9;
|
3
|
+
color: #333;
|
4
|
+
}
|
5
|
+
|
6
|
+
body.dark {
|
7
|
+
background-color: #121212;
|
8
|
+
color: #f9f9f9;
|
9
|
+
}
|
10
|
+
|
11
|
+
button {
|
12
|
+
font-family: inherit;
|
13
|
+
font-size: 1rem;
|
14
|
+
cursor: pointer;
|
15
|
+
}
|
16
|
+
|
17
|
+
div {
|
18
|
+
font-family: 'Arial', sans-serif;
|
19
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import React, { createContext, useContext, useState, ReactNode } from 'react';
|
2
|
+
|
3
|
+
const ThemeContext = createContext({
|
4
|
+
theme: 'light',
|
5
|
+
toggleTheme: () => {},
|
6
|
+
});
|
7
|
+
|
8
|
+
export const ThemeProvider = ({ children }: { children: ReactNode }) => {
|
9
|
+
const [theme, setTheme] = useState<'light' | 'dark'>('light');
|
10
|
+
|
11
|
+
const toggleTheme = () => {
|
12
|
+
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
|
13
|
+
};
|
14
|
+
|
15
|
+
return (
|
16
|
+
<ThemeContext.Provider value={{ theme, toggleTheme }}>
|
17
|
+
<div className={theme}>{children}</div>
|
18
|
+
</ThemeContext.Provider>
|
19
|
+
);
|
20
|
+
};
|
21
|
+
|
22
|
+
export const useTheme = () => useContext(ThemeContext);
|
@@ -1,49 +0,0 @@
|
|
1
|
-
export interface InputProps {
|
2
|
-
label: string;
|
3
|
-
value: string;
|
4
|
-
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
5
|
-
type?: string;
|
6
|
-
placeholder?: string;
|
7
|
-
disabled?: boolean;
|
8
|
-
error?: boolean;
|
9
|
-
errorMessage?: string;
|
10
|
-
required?: boolean;
|
11
|
-
maxLength?: number;
|
12
|
-
minLength?: number;
|
13
|
-
pattern?: string;
|
14
|
-
autoComplete?: string;
|
15
|
-
autoFocus?: boolean;
|
16
|
-
readOnly?: boolean;
|
17
|
-
size?: "small" | "medium" | "large";
|
18
|
-
className?: string;
|
19
|
-
style?: React.CSSProperties;
|
20
|
-
onFocus?: (event: React.FocusEvent<HTMLInputElement>) => void;
|
21
|
-
onBlur?: (event: React.FocusEvent<HTMLInputElement>) => void;
|
22
|
-
onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
23
|
-
onKeyUp?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
24
|
-
onKeyPress?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
25
|
-
onPaste?: (event: React.ClipboardEvent<HTMLInputElement>) => void;
|
26
|
-
onCut?: (event: React.ClipboardEvent<HTMLInputElement>) => void;
|
27
|
-
onCopy?: (event: React.ClipboardEvent<HTMLInputElement>) => void;
|
28
|
-
onContextMenu?: (event: React.MouseEvent<HTMLInputElement>) => void;
|
29
|
-
onSelect?: (event: React.SyntheticEvent<HTMLInputElement>) => void;
|
30
|
-
onChangeCapture?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
31
|
-
onFocusCapture?: (event: React.FocusEvent<HTMLInputElement>) => void;
|
32
|
-
onBlurCapture?: (event: React.FocusEvent<HTMLInputElement>) => void;
|
33
|
-
onKeyDownCapture?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
34
|
-
onKeyUpCapture?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
35
|
-
onKeyPressCapture?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
36
|
-
onPasteCapture?: (event: React.ClipboardEvent<HTMLInputElement>) => void;
|
37
|
-
onCutCapture?: (event: React.ClipboardEvent<HTMLInputElement>) => void;
|
38
|
-
onCopyCapture?: (event: React.ClipboardEvent<HTMLInputElement>) => void;
|
39
|
-
onContextMenuCapture?: (event: React.MouseEvent<HTMLInputElement>) => void;
|
40
|
-
onSelectCapture?: (event: React.SyntheticEvent<HTMLInputElement>) => void;
|
41
|
-
};
|
42
|
-
|
43
|
-
|
44
|
-
export default function Input({
|
45
|
-
placeholder = "Omkar",
|
46
|
-
type
|
47
|
-
}: InputProps) {
|
48
|
-
return(<input type={type} placeholder={placeholder}/>)
|
49
|
-
}
|