@schandlergarcia/sf-web-components 1.3.1 → 1.5.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/.a4drules/features/command-center-dashboard-rule.md +1 -1
- package/.a4drules/skills/command-center-project/SKILL.md +4 -4
- package/.a4drules/skills/component-library/SKILL.md +4 -1
- package/README.md +2 -0
- package/dist/components/library/heroui/Input.d.ts +5 -1
- package/dist/components/library/heroui/Input.js +0 -1
- package/dist/components/library/heroui/Input.js.map +1 -1
- package/dist/components/library/heroui/Kbd.d.ts +6 -5
- package/dist/components/library/heroui/Kbd.js +4 -5
- package/dist/components/library/heroui/Kbd.js.map +1 -1
- package/dist/components/library/heroui/Skeleton.d.ts +8 -5
- package/dist/components/library/heroui/Skeleton.js +4 -5
- package/dist/components/library/heroui/Skeleton.js.map +1 -1
- package/dist/components/library/heroui/Toast.d.ts +6 -3
- package/dist/components/library/heroui/Toast.js +3 -4
- package/dist/components/library/heroui/Toast.js.map +1 -1
- package/dist/components/library/ui/Avatar.d.ts +22 -10
- package/dist/components/library/ui/Avatar.js +40 -17
- package/dist/components/library/ui/Avatar.js.map +1 -1
- package/dist/components/library/ui/Card.d.ts +23 -37
- package/dist/components/library/ui/Chip.d.ts +18 -7
- package/dist/components/library/ui/Chip.js +11 -12
- package/dist/components/library/ui/Chip.js.map +1 -1
- package/dist/components/library/ui/Container.d.ts +12 -13
- package/dist/components/library/ui/Container.js +16 -17
- package/dist/components/library/ui/Container.js.map +1 -1
- package/dist/components/library/ui/EmptyState.d.ts +34 -7
- package/dist/components/library/ui/EmptyState.js +5 -6
- package/dist/components/library/ui/EmptyState.js.map +1 -1
- package/dist/components/library/ui/FieldGroup.d.ts +4 -5
- package/dist/components/library/ui/FieldGroup.js +4 -5
- package/dist/components/library/ui/FieldGroup.js.map +1 -1
- package/dist/components/library/ui/Spinner.d.ts +21 -5
- package/dist/components/library/ui/Text.d.ts +24 -10
- package/dist/components/library/ui/Text.js +20 -23
- package/dist/components/library/ui/Text.js.map +1 -1
- package/dist/components/library/ui/UIInput.d.ts +4 -5
- package/dist/components/library/ui/UIInput.js +5 -6
- package/dist/components/library/ui/UIInput.js.map +1 -1
- package/dist/components/library/ui/alert.d.ts +23 -21
- package/dist/components/library/ui/alert.js +13 -14
- package/dist/components/library/ui/alert.js.map +1 -1
- package/dist/components/library/ui/card.js +24 -26
- package/dist/components/library/ui/card.js.map +1 -1
- package/dist/components/library/ui/checkbox.d.ts +4 -4
- package/dist/components/library/ui/checkbox.js +4 -5
- package/dist/components/library/ui/checkbox.js.map +1 -1
- package/dist/components/library/ui/label.d.ts +5 -7
- package/dist/components/library/ui/label.js +9 -10
- package/dist/components/library/ui/label.js.map +1 -1
- package/dist/components/library/ui/spinner.js +16 -17
- package/dist/components/library/ui/spinner.js.map +1 -1
- package/package.json +1 -1
- package/scripts/convert-to-typescript.sh +52 -0
- package/src/components/library/heroui/Input.tsx +10 -0
- package/src/components/library/heroui/Kbd.tsx +11 -0
- package/src/components/library/heroui/Skeleton.tsx +14 -0
- package/src/components/library/heroui/{Toast.jsx → Toast.tsx} +5 -2
- package/src/components/library/ui/{Alert.jsx → Alert.tsx} +17 -7
- package/src/components/library/ui/Avatar.tsx +68 -0
- package/src/components/library/ui/{Card.jsx → Card.tsx} +24 -10
- package/src/components/library/ui/{Checkbox.jsx → Checkbox.tsx} +4 -2
- package/src/components/library/ui/{Chip.jsx → Chip.tsx} +11 -7
- package/src/components/library/ui/{Container.jsx → Container.tsx} +13 -4
- package/src/components/library/ui/{EmptyState.jsx → EmptyState.tsx} +13 -10
- package/src/components/library/ui/{FieldGroup.jsx → FieldGroup.tsx} +4 -2
- package/src/components/library/ui/{Label.jsx → Label.tsx} +9 -8
- package/src/components/library/ui/{Spinner.jsx → Spinner.tsx} +12 -10
- package/src/components/library/ui/{Text.jsx → Text.tsx} +19 -12
- package/src/components/library/ui/{UIInput.jsx → UIInput.tsx} +5 -5
- package/src/components/library/heroui/Input.jsx +0 -6
- package/src/components/library/heroui/Kbd.jsx +0 -8
- package/src/components/library/heroui/Skeleton.jsx +0 -8
- package/src/components/library/ui/Avatar.jsx +0 -44
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
return /* @__PURE__ */ o(
|
|
1
|
+
import { jsx as a } from "react/jsx-runtime";
|
|
2
|
+
function t({ className: r = "", ...e }) {
|
|
3
|
+
return /* @__PURE__ */ a(
|
|
5
4
|
"input",
|
|
6
5
|
{
|
|
7
6
|
type: "checkbox",
|
|
@@ -15,6 +14,6 @@ function n({ className: r = "", ...e }) {
|
|
|
15
14
|
);
|
|
16
15
|
}
|
|
17
16
|
export {
|
|
18
|
-
|
|
17
|
+
t as default
|
|
19
18
|
};
|
|
20
19
|
//# sourceMappingURL=Checkbox.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.js","sources":["../../../../src/components/library/ui/Checkbox.
|
|
1
|
+
{"version":3,"file":"Checkbox.js","sources":["../../../../src/components/library/ui/Checkbox.tsx"],"sourcesContent":["import * as React from \"react\";\n\nexport interface CheckboxProps extends React.InputHTMLAttributes<HTMLInputElement> {}\n\nexport default function Checkbox({ className = \"\", ...rest }: CheckboxProps) {\n return (\n <input\n type=\"checkbox\"\n className={[\n \"h-4 w-4 rounded border-slate-300 text-brand-600 focus:ring-brand-500\",\n \"dark:border-slate-600 dark:bg-slate-800 dark:focus:ring-brand-400\",\n className\n ]\n .filter(Boolean)\n .join(\" \")}\n {...rest}\n />\n );\n}\n"],"names":["Checkbox","className","rest","jsx"],"mappings":";AAIA,SAAwBA,EAAS,EAAE,WAAAC,IAAY,IAAI,GAAGC,KAAuB;AAC3E,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACAF;AAAA,MAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,MACV,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;"}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
className?: string | undefined;
|
|
7
|
-
}): import("react/jsx-runtime").JSX.Element;
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {
|
|
3
|
+
required?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export default function Label({ children, htmlFor, required, className, ...rest }: LabelProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
return /* @__PURE__ */ i(
|
|
6
|
-
n,
|
|
1
|
+
import { jsxs as r, jsx as n } from "react/jsx-runtime";
|
|
2
|
+
function o({ children: e, htmlFor: t, required: a, className: l = "", ...s }) {
|
|
3
|
+
return /* @__PURE__ */ r(
|
|
4
|
+
"label",
|
|
7
5
|
{
|
|
8
|
-
|
|
6
|
+
htmlFor: t,
|
|
9
7
|
className: [
|
|
10
8
|
"text-sm font-medium text-slate-700 dark:text-slate-200",
|
|
11
9
|
l
|
|
12
10
|
].filter(Boolean).join(" "),
|
|
11
|
+
...s,
|
|
13
12
|
children: [
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
e,
|
|
14
|
+
a && /* @__PURE__ */ n("span", { className: "ml-0.5 text-red-500", children: "*" })
|
|
16
15
|
]
|
|
17
16
|
}
|
|
18
17
|
);
|
|
19
18
|
}
|
|
20
19
|
export {
|
|
21
|
-
|
|
20
|
+
o as default
|
|
22
21
|
};
|
|
23
22
|
//# sourceMappingURL=Label.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Label.js","sources":["../../../../src/components/library/ui/Label.
|
|
1
|
+
{"version":3,"file":"Label.js","sources":["../../../../src/components/library/ui/Label.tsx"],"sourcesContent":["import * as React from \"react\";\n\nexport interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {\n required?: boolean;\n}\n\nexport default function Label({ children, htmlFor, required, className = \"\", ...rest }: LabelProps) {\n return (\n <label\n htmlFor={htmlFor}\n className={[\n \"text-sm font-medium text-slate-700 dark:text-slate-200\",\n className\n ]\n .filter(Boolean)\n .join(\" \")}\n {...rest}\n >\n {children}\n {required && <span className=\"ml-0.5 text-red-500\">*</span>}\n </label>\n );\n}\n"],"names":["Label","children","htmlFor","required","className","rest","jsxs","jsx"],"mappings":";AAMA,SAAwBA,EAAM,EAAE,UAAAC,GAAU,SAAAC,GAAS,UAAAC,GAAU,WAAAC,IAAY,IAAI,GAAGC,KAAoB;AAClG,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,SAAAJ;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACAE;AAAA,MAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,MACV,GAAGC;AAAA,MAEH,UAAA;AAAA,QAAAJ;AAAA,QACAE,KAAY,gBAAAI,EAAC,QAAA,EAAK,WAAU,uBAAsB,UAAA,IAAA,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAG1D;"}
|
|
@@ -1,39 +1,38 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
|
|
3
|
-
const e = {
|
|
1
|
+
import { jsxs as n, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
const o = {
|
|
4
3
|
xs: "h-3 w-3",
|
|
5
4
|
sm: "h-4 w-4",
|
|
6
5
|
md: "h-5 w-5",
|
|
7
6
|
lg: "h-6 w-6",
|
|
8
7
|
xl: "h-8 w-8"
|
|
9
|
-
},
|
|
8
|
+
}, i = {
|
|
10
9
|
brand: "text-brand-500",
|
|
11
10
|
white: "text-white",
|
|
12
11
|
muted: "text-slate-400 dark:text-slate-500",
|
|
13
12
|
current: "text-current"
|
|
14
13
|
};
|
|
15
|
-
function
|
|
16
|
-
size:
|
|
17
|
-
tone:
|
|
18
|
-
label:
|
|
19
|
-
className:
|
|
20
|
-
...
|
|
14
|
+
function x({
|
|
15
|
+
size: e = "md",
|
|
16
|
+
tone: r = "brand",
|
|
17
|
+
label: a = "Loading",
|
|
18
|
+
className: s = "",
|
|
19
|
+
...l
|
|
21
20
|
}) {
|
|
22
|
-
return /* @__PURE__ */
|
|
21
|
+
return /* @__PURE__ */ n(
|
|
23
22
|
"svg",
|
|
24
23
|
{
|
|
25
|
-
...
|
|
24
|
+
...l,
|
|
26
25
|
className: [
|
|
27
26
|
"animate-spin",
|
|
28
|
-
e
|
|
29
|
-
r
|
|
30
|
-
|
|
27
|
+
o[e],
|
|
28
|
+
i[r],
|
|
29
|
+
s
|
|
31
30
|
].filter(Boolean).join(" "),
|
|
32
31
|
xmlns: "http://www.w3.org/2000/svg",
|
|
33
32
|
fill: "none",
|
|
34
33
|
viewBox: "0 0 24 24",
|
|
35
34
|
role: "status",
|
|
36
|
-
"aria-label":
|
|
35
|
+
"aria-label": a,
|
|
37
36
|
children: [
|
|
38
37
|
/* @__PURE__ */ t(
|
|
39
38
|
"circle",
|
|
@@ -59,6 +58,6 @@ function m({
|
|
|
59
58
|
);
|
|
60
59
|
}
|
|
61
60
|
export {
|
|
62
|
-
|
|
61
|
+
x as default
|
|
63
62
|
};
|
|
64
63
|
//# sourceMappingURL=Spinner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Spinner.js","sources":["../../../../src/components/library/ui/Spinner.
|
|
1
|
+
{"version":3,"file":"Spinner.js","sources":["../../../../src/components/library/ui/Spinner.tsx"],"sourcesContent":["import * as React from \"react\";\n\nconst SIZE_CLASSES = {\n xs: \"h-3 w-3\",\n sm: \"h-4 w-4\",\n md: \"h-5 w-5\",\n lg: \"h-6 w-6\",\n xl: \"h-8 w-8\",\n} as const;\n\nconst TONE_CLASSES = {\n brand: \"text-brand-500\",\n white: \"text-white\",\n muted: \"text-slate-400 dark:text-slate-500\",\n current: \"text-current\",\n} as const;\n\nexport interface SpinnerProps extends React.SVGAttributes<SVGSVGElement> {\n size?: keyof typeof SIZE_CLASSES;\n tone?: keyof typeof TONE_CLASSES;\n label?: string;\n}\n\n/**\n * Animated spinner.\n */\nexport default function Spinner({\n size = \"md\",\n tone = \"brand\",\n label = \"Loading\",\n className = \"\",\n ...rest\n}: SpinnerProps) {\n return (\n <svg\n {...rest}\n className={[\n \"animate-spin\",\n SIZE_CLASSES[size],\n TONE_CLASSES[tone],\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n role=\"status\"\n aria-label={label}\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n );\n}\n"],"names":["SIZE_CLASSES","TONE_CLASSES","Spinner","size","tone","label","className","rest","jsxs","jsx"],"mappings":";AAEA,MAAMA,IAAe;AAAA,EACnB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN,GAEMC,IAAe;AAAA,EACnB,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,SAAS;AACX;AAWA,SAAwBC,EAAQ;AAAA,EAC9B,MAAAC,IAAO;AAAA,EACP,MAAAC,IAAO;AAAA,EACP,OAAAC,IAAQ;AAAA,EACR,WAAAC,IAAY;AAAA,EACZ,GAAGC;AACL,GAAiB;AACf,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAGD;AAAA,MACJ,WAAW;AAAA,QACT;AAAA,QACAP,EAAaG,CAAI;AAAA,QACjBF,EAAaG,CAAI;AAAA,QACjBE;AAAA,MAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,MACX,OAAM;AAAA,MACN,MAAK;AAAA,MACL,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,cAAYD;AAAA,MAEZ,UAAA;AAAA,QAAA,gBAAAI;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,IAAG;AAAA,YACH,IAAG;AAAA,YACH,GAAE;AAAA,YACF,QAAO;AAAA,YACP,aAAY;AAAA,UAAA;AAAA,QAAA;AAAA,QAEd,gBAAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,MAAK;AAAA,YACL,GAAE;AAAA,UAAA;AAAA,QAAA;AAAA,MACJ;AAAA,IAAA;AAAA,EAAA;AAGN;"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Bulk TypeScript conversion script
|
|
4
|
+
# Converts .jsx files to .tsx and updates import statements
|
|
5
|
+
#
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
echo "TypeScript Conversion Script"
|
|
9
|
+
echo "============================"
|
|
10
|
+
echo ""
|
|
11
|
+
|
|
12
|
+
# List of files to convert (add more as needed)
|
|
13
|
+
FILES=(
|
|
14
|
+
"src/components/library/ui/Text.jsx"
|
|
15
|
+
"src/components/library/ui/Container.jsx"
|
|
16
|
+
"src/components/library/ui/Chip.jsx"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
converted=0
|
|
20
|
+
failed=0
|
|
21
|
+
|
|
22
|
+
for file in "${FILES[@]}"; do
|
|
23
|
+
if [ ! -f "$file" ]; then
|
|
24
|
+
echo "⏭️ Skipping $file (not found)"
|
|
25
|
+
continue
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
newfile="${file%.jsx}.tsx"
|
|
29
|
+
echo "🔄 Converting $file → $newfile"
|
|
30
|
+
|
|
31
|
+
# Rename file
|
|
32
|
+
mv "$file" "$newfile"
|
|
33
|
+
|
|
34
|
+
# Update import statement
|
|
35
|
+
sed -i '' 's/import React from "react";/import * as React from "react";/g' "$newfile"
|
|
36
|
+
|
|
37
|
+
echo "✅ Renamed and updated imports"
|
|
38
|
+
converted=$((converted + 1))
|
|
39
|
+
done
|
|
40
|
+
|
|
41
|
+
echo ""
|
|
42
|
+
echo "============================"
|
|
43
|
+
echo "✅ Converted: $converted files"
|
|
44
|
+
echo "❌ Failed: $failed files"
|
|
45
|
+
echo ""
|
|
46
|
+
echo "Next steps:"
|
|
47
|
+
echo "1. Add TypeScript interfaces to each converted file"
|
|
48
|
+
echo "2. Type all function parameters"
|
|
49
|
+
echo "3. Add 'as const' to constant objects"
|
|
50
|
+
echo "4. Export prop interfaces"
|
|
51
|
+
echo "5. Run 'npm run build' to verify"
|
|
52
|
+
echo ""
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Input } from "@heroui/react";
|
|
2
|
+
import type { InputProps } from "@heroui/react";
|
|
3
|
+
|
|
4
|
+
export interface HeroUIInputProps extends InputProps {}
|
|
5
|
+
|
|
6
|
+
export default function HeroUIInput(props: HeroUIInputProps) {
|
|
7
|
+
return <Input {...props} />;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type { InputProps };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Kbd } from "@heroui/react";
|
|
2
|
+
import type { KbdProps } from "@heroui/react";
|
|
3
|
+
|
|
4
|
+
export interface HeroUIKbdProps extends KbdProps {}
|
|
5
|
+
|
|
6
|
+
export default function HeroUIKbd({ children, ...props }: HeroUIKbdProps) {
|
|
7
|
+
return <Kbd {...props}>{children}</Kbd>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { Kbd };
|
|
11
|
+
export type { KbdProps };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { Skeleton } from "@heroui/react";
|
|
3
|
+
import type { SkeletonProps } from "@heroui/react";
|
|
4
|
+
|
|
5
|
+
export interface HeroUISkeletonProps extends SkeletonProps {
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default function HeroUISkeleton({ children, ...props }: HeroUISkeletonProps) {
|
|
10
|
+
return <Skeleton {...props}>{children}</Skeleton>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export { Skeleton };
|
|
14
|
+
export type { SkeletonProps };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React from "react";
|
|
2
1
|
import { Toast, toast } from "@heroui/react";
|
|
2
|
+
import type { ToastProps } from "@heroui/react";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* HeroUI v3 Toast — notification system.
|
|
@@ -18,8 +18,11 @@ import { Toast, toast } from "@heroui/react";
|
|
|
18
18
|
* Toast.Title, Toast.Description, Toast.ActionButton,
|
|
19
19
|
* Toast.CloseButton
|
|
20
20
|
*/
|
|
21
|
-
export
|
|
21
|
+
export interface HeroUIToastProps extends ToastProps {}
|
|
22
|
+
|
|
23
|
+
export default function HeroUIToast(props: HeroUIToastProps) {
|
|
22
24
|
return <Toast {...props} />;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export { Toast, toast };
|
|
28
|
+
export type { ToastProps };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import * as React from "react";
|
|
2
2
|
|
|
3
3
|
const VARIANT_CLASSES = {
|
|
4
4
|
default: "bg-slate-50 border-slate-200 text-slate-900 dark:bg-slate-900 dark:border-slate-800 dark:text-slate-50",
|
|
@@ -7,10 +7,14 @@ const VARIANT_CLASSES = {
|
|
|
7
7
|
warning: "bg-yellow-50 border-yellow-200 text-yellow-900 dark:bg-yellow-950 dark:border-yellow-800 dark:text-yellow-50",
|
|
8
8
|
error: "bg-red-50 border-red-200 text-red-900 dark:bg-red-950 dark:border-red-800 dark:text-red-50",
|
|
9
9
|
destructive: "bg-red-50 border-red-200 text-red-900 dark:bg-red-950 dark:border-red-800 dark:text-red-50"
|
|
10
|
-
};
|
|
10
|
+
} as const;
|
|
11
11
|
|
|
12
|
-
export
|
|
13
|
-
|
|
12
|
+
export interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
13
|
+
variant?: keyof typeof VARIANT_CLASSES;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default function Alert({ variant = "default", className = "", children, ...rest }: AlertProps) {
|
|
17
|
+
const variantClasses = VARIANT_CLASSES[variant];
|
|
14
18
|
|
|
15
19
|
return (
|
|
16
20
|
<div
|
|
@@ -29,7 +33,9 @@ export default function Alert({ variant = "default", className = "", children, .
|
|
|
29
33
|
);
|
|
30
34
|
}
|
|
31
35
|
|
|
32
|
-
export
|
|
36
|
+
export interface AlertTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {}
|
|
37
|
+
|
|
38
|
+
export function AlertTitle({ className = "", children, ...rest }: AlertTitleProps) {
|
|
33
39
|
return (
|
|
34
40
|
<h5
|
|
35
41
|
className={[
|
|
@@ -45,7 +51,9 @@ export function AlertTitle({ className = "", children, ...rest }) {
|
|
|
45
51
|
);
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
export
|
|
54
|
+
export interface AlertDescriptionProps extends React.HTMLAttributes<HTMLDivElement> {}
|
|
55
|
+
|
|
56
|
+
export function AlertDescription({ className = "", children, ...rest }: AlertDescriptionProps) {
|
|
49
57
|
return (
|
|
50
58
|
<div
|
|
51
59
|
className={[
|
|
@@ -61,7 +69,9 @@ export function AlertDescription({ className = "", children, ...rest }) {
|
|
|
61
69
|
);
|
|
62
70
|
}
|
|
63
71
|
|
|
64
|
-
export
|
|
72
|
+
export interface AlertActionProps extends React.HTMLAttributes<HTMLDivElement> {}
|
|
73
|
+
|
|
74
|
+
export function AlertAction({ className = "", children, ...rest }: AlertActionProps) {
|
|
65
75
|
return (
|
|
66
76
|
<div
|
|
67
77
|
className={[
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
const SIZE_MAP = {
|
|
4
|
+
xs: "h-6 w-6 text-[9px]",
|
|
5
|
+
sm: "h-8 w-8 text-[10px]",
|
|
6
|
+
md: "h-9 w-9 text-xs",
|
|
7
|
+
lg: "h-11 w-11 text-sm",
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
const TONE_MAP = {
|
|
11
|
+
slate: "bg-slate-800 text-white",
|
|
12
|
+
brand: "bg-brand-500 text-white",
|
|
13
|
+
neutral: "bg-slate-100 text-slate-700 dark:bg-slate-800 dark:text-slate-200",
|
|
14
|
+
} as const;
|
|
15
|
+
|
|
16
|
+
export interface AvatarProps extends React.HTMLAttributes<HTMLDivElement | HTMLImageElement> {
|
|
17
|
+
src?: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
initials?: string;
|
|
20
|
+
icon?: React.ReactNode;
|
|
21
|
+
size?: keyof typeof SIZE_MAP;
|
|
22
|
+
tone?: keyof typeof TONE_MAP;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default function Avatar({
|
|
26
|
+
src,
|
|
27
|
+
name,
|
|
28
|
+
initials,
|
|
29
|
+
icon,
|
|
30
|
+
size = "sm",
|
|
31
|
+
tone = "slate",
|
|
32
|
+
className = "",
|
|
33
|
+
...rest
|
|
34
|
+
}: AvatarProps) {
|
|
35
|
+
const sizeClass = SIZE_MAP[size];
|
|
36
|
+
|
|
37
|
+
if (src) {
|
|
38
|
+
return (
|
|
39
|
+
<img
|
|
40
|
+
src={src}
|
|
41
|
+
alt={name ?? ""}
|
|
42
|
+
className={`${sizeClass} shrink-0 rounded-full border border-slate-200 object-cover dark:border-slate-800 ${className}`}
|
|
43
|
+
{...(rest as React.ImgHTMLAttributes<HTMLImageElement>)}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (React.isValidElement(icon)) {
|
|
49
|
+
return (
|
|
50
|
+
<div
|
|
51
|
+
className={`${sizeClass} ${TONE_MAP[tone]} flex shrink-0 items-center justify-center rounded-full ${className}`}
|
|
52
|
+
{...(rest as React.HTMLAttributes<HTMLDivElement>)}
|
|
53
|
+
>
|
|
54
|
+
{icon}
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const label = initials ?? (name ? name.split(" ").map(w => w[0]).join("").slice(0, 2).toUpperCase() : "?");
|
|
60
|
+
return (
|
|
61
|
+
<div
|
|
62
|
+
className={`${sizeClass} ${TONE_MAP[tone]} flex shrink-0 items-center justify-center rounded-full font-bold ${className}`}
|
|
63
|
+
{...(rest as React.HTMLAttributes<HTMLDivElement>)}
|
|
64
|
+
>
|
|
65
|
+
{label}
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export interface UICardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
padding?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export default function UICard({ children, padding = "p-5", className = "", ...rest }: UICardProps) {
|
|
4
8
|
return (
|
|
5
9
|
<div
|
|
6
|
-
style={style}
|
|
7
10
|
className={[
|
|
8
11
|
"rounded-2xl border border-slate-200 bg-white shadow-sm dark:border-slate-800 dark:bg-slate-900",
|
|
9
12
|
padding,
|
|
@@ -19,7 +22,9 @@ export default function UICard({ children, padding = "p-5", style, className = "
|
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
// shadcn-compatible Card components
|
|
22
|
-
export
|
|
25
|
+
export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {}
|
|
26
|
+
|
|
27
|
+
export function Card({ className = "", children, ...rest }: CardProps) {
|
|
23
28
|
return (
|
|
24
29
|
<div
|
|
25
30
|
className={[
|
|
@@ -35,7 +40,9 @@ export function Card({ className = "", children, ...rest }) {
|
|
|
35
40
|
);
|
|
36
41
|
}
|
|
37
42
|
|
|
38
|
-
export
|
|
43
|
+
export interface CardHeaderProps extends React.HTMLAttributes<HTMLDivElement> {}
|
|
44
|
+
|
|
45
|
+
export function CardHeader({ className = "", children, ...rest }: CardHeaderProps) {
|
|
39
46
|
return (
|
|
40
47
|
<div
|
|
41
48
|
className={[
|
|
@@ -51,7 +58,9 @@ export function CardHeader({ className = "", children, ...rest }) {
|
|
|
51
58
|
);
|
|
52
59
|
}
|
|
53
60
|
|
|
54
|
-
export
|
|
61
|
+
export interface CardTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {}
|
|
62
|
+
|
|
63
|
+
export function CardTitle({ className = "", children, ...rest }: CardTitleProps) {
|
|
55
64
|
return (
|
|
56
65
|
<h3
|
|
57
66
|
className={[
|
|
@@ -67,7 +76,9 @@ export function CardTitle({ className = "", children, ...rest }) {
|
|
|
67
76
|
);
|
|
68
77
|
}
|
|
69
78
|
|
|
70
|
-
export
|
|
79
|
+
export interface CardDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {}
|
|
80
|
+
|
|
81
|
+
export function CardDescription({ className = "", children, ...rest }: CardDescriptionProps) {
|
|
71
82
|
return (
|
|
72
83
|
<p
|
|
73
84
|
className={[
|
|
@@ -83,7 +94,9 @@ export function CardDescription({ className = "", children, ...rest }) {
|
|
|
83
94
|
);
|
|
84
95
|
}
|
|
85
96
|
|
|
86
|
-
export
|
|
97
|
+
export interface CardContentProps extends React.HTMLAttributes<HTMLDivElement> {}
|
|
98
|
+
|
|
99
|
+
export function CardContent({ className = "", children, ...rest }: CardContentProps) {
|
|
87
100
|
return (
|
|
88
101
|
<div
|
|
89
102
|
className={[
|
|
@@ -99,7 +112,9 @@ export function CardContent({ className = "", children, ...rest }) {
|
|
|
99
112
|
);
|
|
100
113
|
}
|
|
101
114
|
|
|
102
|
-
export
|
|
115
|
+
export interface CardFooterProps extends React.HTMLAttributes<HTMLDivElement> {}
|
|
116
|
+
|
|
117
|
+
export function CardFooter({ className = "", children, ...rest }: CardFooterProps) {
|
|
103
118
|
return (
|
|
104
119
|
<div
|
|
105
120
|
className={[
|
|
@@ -114,4 +129,3 @@ export function CardFooter({ className = "", children, ...rest }) {
|
|
|
114
129
|
</div>
|
|
115
130
|
);
|
|
116
131
|
}
|
|
117
|
-
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export interface CheckboxProps extends React.InputHTMLAttributes<HTMLInputElement> {}
|
|
4
|
+
|
|
5
|
+
export default function Checkbox({ className = "", ...rest }: CheckboxProps) {
|
|
4
6
|
return (
|
|
5
7
|
<input
|
|
6
8
|
type="checkbox"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import * as React from "react";
|
|
2
2
|
|
|
3
3
|
const TONE_STYLES = {
|
|
4
4
|
neutral:
|
|
@@ -11,20 +11,25 @@ const TONE_STYLES = {
|
|
|
11
11
|
"border-amber-200/80 bg-amber-50/70 text-amber-900 ring-amber-900/5 hover:bg-amber-50 dark:border-amber-900/40 dark:bg-amber-950/20 dark:text-amber-200 dark:ring-amber-300/10 dark:hover:bg-amber-950/30",
|
|
12
12
|
danger:
|
|
13
13
|
"border-rose-200/80 bg-rose-50/70 text-rose-900 ring-rose-900/5 hover:bg-rose-50 dark:border-rose-900/40 dark:bg-rose-950/20 dark:text-rose-200 dark:ring-rose-300/10 dark:hover:bg-rose-950/30"
|
|
14
|
-
};
|
|
14
|
+
} as const;
|
|
15
15
|
|
|
16
16
|
const SIZE_STYLES = {
|
|
17
17
|
xs: "px-2 py-0.5 text-[11px]",
|
|
18
18
|
sm: "px-2.5 py-1 text-xs"
|
|
19
|
-
};
|
|
19
|
+
} as const;
|
|
20
20
|
|
|
21
|
-
export
|
|
21
|
+
export interface UIChipProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
22
|
+
tone?: keyof typeof TONE_STYLES;
|
|
23
|
+
size?: keyof typeof SIZE_STYLES;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default function UIChip({ tone = "neutral", size = "xs", className = "", children, ...rest }: UIChipProps) {
|
|
22
27
|
return (
|
|
23
28
|
<span
|
|
24
29
|
className={[
|
|
25
30
|
"inline-flex items-center gap-1 rounded-full border font-semibold shadow-sm ring-1 transition",
|
|
26
|
-
SIZE_STYLES[size]
|
|
27
|
-
TONE_STYLES[tone]
|
|
31
|
+
SIZE_STYLES[size],
|
|
32
|
+
TONE_STYLES[tone],
|
|
28
33
|
className
|
|
29
34
|
]
|
|
30
35
|
.filter(Boolean)
|
|
@@ -35,4 +40,3 @@ export default function UIChip({ tone = "neutral", size = "xs", className = "",
|
|
|
35
40
|
</span>
|
|
36
41
|
);
|
|
37
42
|
}
|
|
38
|
-
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import * as React from "react";
|
|
2
2
|
import UIText from "./Text";
|
|
3
3
|
|
|
4
|
+
export interface UIContainerProps extends React.HTMLAttributes<HTMLElement> {
|
|
5
|
+
title?: string;
|
|
6
|
+
subtitle?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
actions?: React.ReactNode;
|
|
9
|
+
empty?: boolean;
|
|
10
|
+
emptyText?: string;
|
|
11
|
+
emptyIcon?: React.ReactNode;
|
|
12
|
+
emptyHeight?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
4
15
|
export default function UIContainer({
|
|
5
16
|
title,
|
|
6
17
|
subtitle,
|
|
@@ -13,7 +24,7 @@ export default function UIContainer({
|
|
|
13
24
|
className = "",
|
|
14
25
|
style,
|
|
15
26
|
children
|
|
16
|
-
}) {
|
|
27
|
+
}: UIContainerProps) {
|
|
17
28
|
const sub = subtitle ?? description;
|
|
18
29
|
|
|
19
30
|
return (
|
|
@@ -52,5 +63,3 @@ export default function UIContainer({
|
|
|
52
63
|
</section>
|
|
53
64
|
);
|
|
54
65
|
}
|
|
55
|
-
|
|
56
|
-
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import * as React from "react";
|
|
2
2
|
|
|
3
3
|
const SIZES = {
|
|
4
4
|
sm: { icon: "h-8 w-8", heading: "text-sm", body: "text-xs", gap: "gap-2", pad: "py-6" },
|
|
5
5
|
md: { icon: "h-10 w-10", heading: "text-base", body: "text-sm", gap: "gap-3", pad: "py-10" },
|
|
6
6
|
lg: { icon: "h-14 w-14", heading: "text-lg", body: "text-sm", gap: "gap-4", pad: "py-16" },
|
|
7
|
-
};
|
|
7
|
+
} as const;
|
|
8
|
+
|
|
9
|
+
export interface EmptyStateProps {
|
|
10
|
+
icon?: React.ReactNode;
|
|
11
|
+
heading?: string;
|
|
12
|
+
body?: string;
|
|
13
|
+
action?: React.ReactNode;
|
|
14
|
+
size?: keyof typeof SIZES;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
8
17
|
|
|
9
18
|
/**
|
|
10
19
|
* Empty state placeholder — shows when a list, table, or section has no content.
|
|
11
|
-
*
|
|
12
|
-
* @param {ReactNode} icon Optional icon element
|
|
13
|
-
* @param {string} heading Primary message
|
|
14
|
-
* @param {string} body Secondary description
|
|
15
|
-
* @param {ReactNode} action Optional CTA (button, link, etc.)
|
|
16
|
-
* @param {"sm"|"md"|"lg"} size Visual density
|
|
17
20
|
*/
|
|
18
21
|
export default function EmptyState({
|
|
19
22
|
icon,
|
|
@@ -22,8 +25,8 @@ export default function EmptyState({
|
|
|
22
25
|
action,
|
|
23
26
|
size = "md",
|
|
24
27
|
className = "",
|
|
25
|
-
}) {
|
|
26
|
-
const s = SIZES[size]
|
|
28
|
+
}: EmptyStateProps) {
|
|
29
|
+
const s = SIZES[size];
|
|
27
30
|
|
|
28
31
|
return (
|
|
29
32
|
<div className={`flex flex-col items-center justify-center text-center ${s.pad} ${s.gap} ${className}`}>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export interface FieldGroupProps extends React.HTMLAttributes<HTMLDivElement> {}
|
|
4
|
+
|
|
5
|
+
export default function FieldGroup({ className = "", children, ...rest }: FieldGroupProps) {
|
|
4
6
|
return (
|
|
5
7
|
<div
|
|
6
8
|
className={[
|