@pands/ui 0.0.0-stage → 0.1.0
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/dist/index.d.ts +65 -0
- package/dist/index.js +242 -0
- package/package.json +50 -3
- package/src/styles.css +31 -0
- package/README.md +0 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { ClassValue } from 'clsx';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
5
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
6
|
+
variant?: "primary" | "secondary" | "danger" | "ghost";
|
|
7
|
+
size?: "sm" | "md" | "lg";
|
|
8
|
+
}
|
|
9
|
+
declare function Button({ variant, size, className, children, ...props }: ButtonProps): React.JSX.Element;
|
|
10
|
+
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
11
|
+
label?: string;
|
|
12
|
+
}
|
|
13
|
+
declare function Input({ label, className, id, ...props }: InputProps): React.JSX.Element;
|
|
14
|
+
interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
15
|
+
label?: string;
|
|
16
|
+
}
|
|
17
|
+
declare function Textarea({ label, className, id, ...props }: TextareaProps): React.JSX.Element;
|
|
18
|
+
interface SelectOption {
|
|
19
|
+
label: string;
|
|
20
|
+
value: string;
|
|
21
|
+
}
|
|
22
|
+
interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {
|
|
23
|
+
label?: string;
|
|
24
|
+
options: SelectOption[];
|
|
25
|
+
}
|
|
26
|
+
declare function Select({ label, options, className, id, ...props }: SelectProps): React.JSX.Element;
|
|
27
|
+
interface CheckboxProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
28
|
+
label?: string;
|
|
29
|
+
}
|
|
30
|
+
declare function Checkbox({ label, className, id, ...props }: CheckboxProps): React.JSX.Element;
|
|
31
|
+
interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
32
|
+
variant?: "default" | "success" | "warning" | "danger";
|
|
33
|
+
}
|
|
34
|
+
declare function Badge({ variant, className, children, ...props }: BadgeProps): React.JSX.Element;
|
|
35
|
+
declare function Card({ className, children, ...props }: React.HTMLAttributes<HTMLDivElement>): React.JSX.Element;
|
|
36
|
+
interface DialogProps {
|
|
37
|
+
open: boolean;
|
|
38
|
+
title: string;
|
|
39
|
+
onClose: () => void;
|
|
40
|
+
children: React.ReactNode;
|
|
41
|
+
}
|
|
42
|
+
declare function Dialog({ open, title, onClose, children }: DialogProps): React.JSX.Element | null;
|
|
43
|
+
declare function Table({ className, children, ...props }: React.TableHTMLAttributes<HTMLTableElement>): React.JSX.Element;
|
|
44
|
+
interface NavItem {
|
|
45
|
+
label: string;
|
|
46
|
+
to: string;
|
|
47
|
+
}
|
|
48
|
+
interface AppShellProps {
|
|
49
|
+
title: string;
|
|
50
|
+
navItems: NavItem[];
|
|
51
|
+
currentPath?: string;
|
|
52
|
+
onNavigate?: (to: string) => void;
|
|
53
|
+
userEmail?: string | null;
|
|
54
|
+
onSignOut?: () => void;
|
|
55
|
+
children: React.ReactNode;
|
|
56
|
+
}
|
|
57
|
+
declare function AppShell({ title, navItems, currentPath, onNavigate, userEmail, onSignOut, children, }: AppShellProps): React.JSX.Element;
|
|
58
|
+
interface ToastProps {
|
|
59
|
+
message: string | null;
|
|
60
|
+
variant?: "info" | "success" | "error";
|
|
61
|
+
onDismiss?: () => void;
|
|
62
|
+
}
|
|
63
|
+
declare function Toast({ message, variant, onDismiss }: ToastProps): React.JSX.Element | null;
|
|
64
|
+
|
|
65
|
+
export { AppShell, type AppShellProps, Badge, type BadgeProps, Button, type ButtonProps, Card, Checkbox, type CheckboxProps, Dialog, type DialogProps, Input, type InputProps, type NavItem, Select, type SelectOption, type SelectProps, Table, Textarea, type TextareaProps, Toast, type ToastProps, cn };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// src/index.tsx
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
function cn(...inputs) {
|
|
6
|
+
return twMerge(clsx(inputs));
|
|
7
|
+
}
|
|
8
|
+
function Button({
|
|
9
|
+
variant = "primary",
|
|
10
|
+
size = "md",
|
|
11
|
+
className,
|
|
12
|
+
children,
|
|
13
|
+
...props
|
|
14
|
+
}) {
|
|
15
|
+
const variantStyles = {
|
|
16
|
+
primary: "bg-blue-600 text-white hover:bg-blue-700 border-transparent",
|
|
17
|
+
secondary: "bg-white text-slate-900 border-slate-300 hover:bg-slate-50",
|
|
18
|
+
danger: "bg-red-600 text-white hover:bg-red-700 border-transparent",
|
|
19
|
+
ghost: "bg-transparent text-slate-700 hover:bg-slate-100 border-transparent"
|
|
20
|
+
};
|
|
21
|
+
const sizeStyles = {
|
|
22
|
+
sm: "px-2.5 py-1.5 text-xs",
|
|
23
|
+
md: "px-4 py-2 text-sm",
|
|
24
|
+
lg: "px-5 py-2.5 text-base"
|
|
25
|
+
};
|
|
26
|
+
return /* @__PURE__ */ jsx(
|
|
27
|
+
"button",
|
|
28
|
+
{
|
|
29
|
+
type: "button",
|
|
30
|
+
className: cn(
|
|
31
|
+
"inline-flex items-center justify-center rounded-md border font-medium transition-colors disabled:opacity-50 disabled:pointer-events-none cursor-pointer",
|
|
32
|
+
variantStyles[variant],
|
|
33
|
+
sizeStyles[size],
|
|
34
|
+
className
|
|
35
|
+
),
|
|
36
|
+
...props,
|
|
37
|
+
children
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
function Input({ label, className, id, ...props }) {
|
|
42
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
43
|
+
label ? /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-xs font-medium text-slate-700", children: label }) : null,
|
|
44
|
+
/* @__PURE__ */ jsx(
|
|
45
|
+
"input",
|
|
46
|
+
{
|
|
47
|
+
id,
|
|
48
|
+
className: cn(
|
|
49
|
+
"w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 focus:border-blue-500 focus:outline-none",
|
|
50
|
+
className
|
|
51
|
+
),
|
|
52
|
+
...props
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
] });
|
|
56
|
+
}
|
|
57
|
+
function Textarea({ label, className, id, ...props }) {
|
|
58
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
59
|
+
label ? /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-xs font-medium text-slate-700", children: label }) : null,
|
|
60
|
+
/* @__PURE__ */ jsx(
|
|
61
|
+
"textarea",
|
|
62
|
+
{
|
|
63
|
+
id,
|
|
64
|
+
className: cn(
|
|
65
|
+
"w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 focus:border-blue-500 focus:outline-none",
|
|
66
|
+
className
|
|
67
|
+
),
|
|
68
|
+
...props
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
] });
|
|
72
|
+
}
|
|
73
|
+
function Select({ label, options, className, id, ...props }) {
|
|
74
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
75
|
+
label ? /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-xs font-medium text-slate-700", children: label }) : null,
|
|
76
|
+
/* @__PURE__ */ jsx(
|
|
77
|
+
"select",
|
|
78
|
+
{
|
|
79
|
+
id,
|
|
80
|
+
className: cn(
|
|
81
|
+
"w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 focus:border-blue-500 focus:outline-none",
|
|
82
|
+
className
|
|
83
|
+
),
|
|
84
|
+
...props,
|
|
85
|
+
children: options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
] });
|
|
89
|
+
}
|
|
90
|
+
function Checkbox({ label, className, id, ...props }) {
|
|
91
|
+
return /* @__PURE__ */ jsxs("label", { htmlFor: id, className: cn("inline-flex items-center gap-2 text-sm", className), children: [
|
|
92
|
+
/* @__PURE__ */ jsx(
|
|
93
|
+
"input",
|
|
94
|
+
{
|
|
95
|
+
id,
|
|
96
|
+
type: "checkbox",
|
|
97
|
+
className: "h-4 w-4 rounded border-slate-300 text-blue-600 focus:ring-blue-500",
|
|
98
|
+
...props
|
|
99
|
+
}
|
|
100
|
+
),
|
|
101
|
+
label ? /* @__PURE__ */ jsx("span", { className: "text-slate-700", children: label }) : null
|
|
102
|
+
] });
|
|
103
|
+
}
|
|
104
|
+
function Badge({ variant = "default", className, children, ...props }) {
|
|
105
|
+
const styles = {
|
|
106
|
+
default: "bg-slate-100 text-slate-800",
|
|
107
|
+
success: "bg-emerald-100 text-emerald-800",
|
|
108
|
+
warning: "bg-amber-100 text-amber-800",
|
|
109
|
+
danger: "bg-red-100 text-red-800"
|
|
110
|
+
};
|
|
111
|
+
return /* @__PURE__ */ jsx(
|
|
112
|
+
"span",
|
|
113
|
+
{
|
|
114
|
+
className: cn(
|
|
115
|
+
"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium",
|
|
116
|
+
styles[variant],
|
|
117
|
+
className
|
|
118
|
+
),
|
|
119
|
+
...props,
|
|
120
|
+
children
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
function Card({ className, children, ...props }) {
|
|
125
|
+
return /* @__PURE__ */ jsx(
|
|
126
|
+
"div",
|
|
127
|
+
{
|
|
128
|
+
className: cn("rounded-lg border border-slate-200 bg-white p-5 shadow-xs", className),
|
|
129
|
+
...props,
|
|
130
|
+
children
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
function Dialog({ open, title, onClose, children }) {
|
|
135
|
+
if (!open) return null;
|
|
136
|
+
return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-lg rounded-lg bg-white p-6 shadow-xl", children: [
|
|
137
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-4 flex items-center justify-between border-b border-slate-100 pb-3", children: [
|
|
138
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-slate-900", children: title }),
|
|
139
|
+
/* @__PURE__ */ jsx(
|
|
140
|
+
"button",
|
|
141
|
+
{
|
|
142
|
+
type: "button",
|
|
143
|
+
onClick: onClose,
|
|
144
|
+
className: "text-slate-400 hover:text-slate-600 cursor-pointer",
|
|
145
|
+
children: "\u2715"
|
|
146
|
+
}
|
|
147
|
+
)
|
|
148
|
+
] }),
|
|
149
|
+
/* @__PURE__ */ jsx("div", { children })
|
|
150
|
+
] }) });
|
|
151
|
+
}
|
|
152
|
+
function Table({
|
|
153
|
+
className,
|
|
154
|
+
children,
|
|
155
|
+
...props
|
|
156
|
+
}) {
|
|
157
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full overflow-x-auto rounded-lg border border-slate-200 bg-white", children: /* @__PURE__ */ jsx("table", { className: cn("w-full border-collapse text-left text-sm", className), ...props, children }) });
|
|
158
|
+
}
|
|
159
|
+
function AppShell({
|
|
160
|
+
title,
|
|
161
|
+
navItems,
|
|
162
|
+
currentPath,
|
|
163
|
+
onNavigate,
|
|
164
|
+
userEmail,
|
|
165
|
+
onSignOut,
|
|
166
|
+
children
|
|
167
|
+
}) {
|
|
168
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-screen bg-slate-50 text-slate-900", children: [
|
|
169
|
+
/* @__PURE__ */ jsxs("aside", { className: "flex w-64 flex-col border-r border-slate-200 bg-white", children: [
|
|
170
|
+
/* @__PURE__ */ jsx("div", { className: "border-b border-slate-200 px-6 py-4", children: /* @__PURE__ */ jsx("span", { className: "text-lg font-bold tracking-tight text-slate-900", children: title }) }),
|
|
171
|
+
/* @__PURE__ */ jsx("nav", { className: "flex-1 space-y-1 p-3", children: navItems.map((item) => {
|
|
172
|
+
const active = currentPath === item.to;
|
|
173
|
+
return /* @__PURE__ */ jsx(
|
|
174
|
+
"a",
|
|
175
|
+
{
|
|
176
|
+
href: item.to,
|
|
177
|
+
onClick: (e) => {
|
|
178
|
+
if (onNavigate) {
|
|
179
|
+
e.preventDefault();
|
|
180
|
+
onNavigate(item.to);
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
className: cn(
|
|
184
|
+
"block rounded-md px-3 py-2 text-sm font-medium transition-colors",
|
|
185
|
+
active ? "bg-blue-50 text-blue-700" : "text-slate-600 hover:bg-slate-100 hover:text-slate-900"
|
|
186
|
+
),
|
|
187
|
+
children: item.label
|
|
188
|
+
},
|
|
189
|
+
item.to
|
|
190
|
+
);
|
|
191
|
+
}) }),
|
|
192
|
+
userEmail ? /* @__PURE__ */ jsxs("div", { className: "border-t border-slate-200 p-4 text-xs text-slate-600", children: [
|
|
193
|
+
/* @__PURE__ */ jsx("div", { className: "truncate font-medium text-slate-900", children: userEmail }),
|
|
194
|
+
onSignOut ? /* @__PURE__ */ jsx(
|
|
195
|
+
"button",
|
|
196
|
+
{
|
|
197
|
+
type: "button",
|
|
198
|
+
onClick: onSignOut,
|
|
199
|
+
className: "mt-2 text-blue-600 hover:underline cursor-pointer",
|
|
200
|
+
children: "Sign out"
|
|
201
|
+
}
|
|
202
|
+
) : null
|
|
203
|
+
] }) : null
|
|
204
|
+
] }),
|
|
205
|
+
/* @__PURE__ */ jsx("main", { className: "flex-1 p-8", children })
|
|
206
|
+
] });
|
|
207
|
+
}
|
|
208
|
+
function Toast({ message, variant = "info", onDismiss }) {
|
|
209
|
+
if (!message) return null;
|
|
210
|
+
const styles = {
|
|
211
|
+
info: "bg-slate-900 text-white",
|
|
212
|
+
success: "bg-emerald-600 text-white",
|
|
213
|
+
error: "bg-red-600 text-white"
|
|
214
|
+
};
|
|
215
|
+
return /* @__PURE__ */ jsxs(
|
|
216
|
+
"div",
|
|
217
|
+
{
|
|
218
|
+
className: cn(
|
|
219
|
+
"fixed right-4 bottom-4 z-50 flex items-center gap-3 rounded-lg px-4 py-3 text-sm shadow-lg",
|
|
220
|
+
styles[variant]
|
|
221
|
+
),
|
|
222
|
+
children: [
|
|
223
|
+
/* @__PURE__ */ jsx("span", { children: message }),
|
|
224
|
+
onDismiss ? /* @__PURE__ */ jsx("button", { type: "button", onClick: onDismiss, className: "opacity-80 hover:opacity-100", children: "\u2715" }) : null
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
export {
|
|
230
|
+
AppShell,
|
|
231
|
+
Badge,
|
|
232
|
+
Button,
|
|
233
|
+
Card,
|
|
234
|
+
Checkbox,
|
|
235
|
+
Dialog,
|
|
236
|
+
Input,
|
|
237
|
+
Select,
|
|
238
|
+
Table,
|
|
239
|
+
Textarea,
|
|
240
|
+
Toast,
|
|
241
|
+
cn
|
|
242
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,53 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pands/ui",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./styles.css": "./src/styles.css"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"clsx": "^2.1.1",
|
|
17
|
+
"lucide-react": "^0.475.0",
|
|
18
|
+
"tailwind-merge": "^3.0.2"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"react": "^19.0.0",
|
|
22
|
+
"react-dom": "^19.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/react": "^19.0.10",
|
|
26
|
+
"@types/react-dom": "^19.0.4",
|
|
27
|
+
"react": "^19.0.0",
|
|
28
|
+
"react-dom": "^19.0.0"
|
|
29
|
+
},
|
|
30
|
+
"description": "Tailwind CSS and React component library for Pand applications",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"author": "Mehdi Nosrati",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/MehdiNosrati/pand.git"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/MehdiNosrati/pand#readme",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/MehdiNosrati/pand/issues"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"dist",
|
|
46
|
+
"src/styles.css"
|
|
47
|
+
],
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsup src/index.tsx --format esm --dts --clean --external react --external react-dom",
|
|
50
|
+
"typecheck": "tsc --noEmit",
|
|
51
|
+
"test": "node -e \"console.log('@pands/ui ok')\""
|
|
52
|
+
}
|
|
6
53
|
}
|
package/src/styles.css
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@source "./";
|
|
3
|
+
@source "../dist";
|
|
4
|
+
@source "../../admin-ui";
|
|
5
|
+
@source "../node_modules/@pands/ui";
|
|
6
|
+
@source "../node_modules/@pands/admin-ui";
|
|
7
|
+
|
|
8
|
+
:root {
|
|
9
|
+
color-scheme: light;
|
|
10
|
+
--pand-bg: #f8fafc;
|
|
11
|
+
--pand-surface: #ffffff;
|
|
12
|
+
--pand-border: #e2e8f0;
|
|
13
|
+
--pand-text: #0f172a;
|
|
14
|
+
--pand-muted: #64748b;
|
|
15
|
+
--pand-primary: #2563eb;
|
|
16
|
+
--pand-primary-hover: #1d4ed8;
|
|
17
|
+
--pand-danger: #dc2626;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
*,
|
|
21
|
+
*::before,
|
|
22
|
+
*::after {
|
|
23
|
+
box-sizing: border-box;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
body {
|
|
27
|
+
background-color: var(--pand-bg);
|
|
28
|
+
color: var(--pand-text);
|
|
29
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
30
|
+
margin: 0;
|
|
31
|
+
}
|
package/README.md
DELETED