@seekho/ui 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.mts +40 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +217 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +207 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +57 -0
- package/readme.md +118 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
type ButtonVariant = "primary" | "secondary" | "danger" | "ghost";
|
|
5
|
+
type ButtonSize = "sm" | "md" | "lg";
|
|
6
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
7
|
+
variant?: ButtonVariant;
|
|
8
|
+
size?: ButtonSize;
|
|
9
|
+
loading?: boolean;
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
declare function Button({ variant, size, loading, disabled, className, children, ...props }: ButtonProps): react_jsx_runtime.JSX.Element;
|
|
13
|
+
|
|
14
|
+
type BadgeVariant = "default" | "success" | "warning" | "danger" | "info";
|
|
15
|
+
interface BadgeProps {
|
|
16
|
+
variant?: BadgeVariant;
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
declare function Badge({ variant, children, className }: BadgeProps): react_jsx_runtime.JSX.Element;
|
|
21
|
+
|
|
22
|
+
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
23
|
+
label?: string;
|
|
24
|
+
error?: string;
|
|
25
|
+
hint?: string;
|
|
26
|
+
}
|
|
27
|
+
declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* useState backed by localStorage — syncs value on mount and persists on change.
|
|
31
|
+
*/
|
|
32
|
+
declare function useLocalStorage<T>(key: string, initialValue: T): readonly [T, (value: T | ((prev: T) => T)) => void, () => void];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Merges class names, filtering out falsy values.
|
|
36
|
+
* Lightweight alternative to clsx for simple use cases.
|
|
37
|
+
*/
|
|
38
|
+
declare function cn(...classes: (string | undefined | null | false)[]): string;
|
|
39
|
+
|
|
40
|
+
export { Badge, type BadgeProps, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Input, type InputProps, cn, useLocalStorage };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
type ButtonVariant = "primary" | "secondary" | "danger" | "ghost";
|
|
5
|
+
type ButtonSize = "sm" | "md" | "lg";
|
|
6
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
7
|
+
variant?: ButtonVariant;
|
|
8
|
+
size?: ButtonSize;
|
|
9
|
+
loading?: boolean;
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
declare function Button({ variant, size, loading, disabled, className, children, ...props }: ButtonProps): react_jsx_runtime.JSX.Element;
|
|
13
|
+
|
|
14
|
+
type BadgeVariant = "default" | "success" | "warning" | "danger" | "info";
|
|
15
|
+
interface BadgeProps {
|
|
16
|
+
variant?: BadgeVariant;
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
declare function Badge({ variant, children, className }: BadgeProps): react_jsx_runtime.JSX.Element;
|
|
21
|
+
|
|
22
|
+
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
23
|
+
label?: string;
|
|
24
|
+
error?: string;
|
|
25
|
+
hint?: string;
|
|
26
|
+
}
|
|
27
|
+
declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* useState backed by localStorage — syncs value on mount and persists on change.
|
|
31
|
+
*/
|
|
32
|
+
declare function useLocalStorage<T>(key: string, initialValue: T): readonly [T, (value: T | ((prev: T) => T)) => void, () => void];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Merges class names, filtering out falsy values.
|
|
36
|
+
* Lightweight alternative to clsx for simple use cases.
|
|
37
|
+
*/
|
|
38
|
+
declare function cn(...classes: (string | undefined | null | false)[]): string;
|
|
39
|
+
|
|
40
|
+
export { Badge, type BadgeProps, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Input, type InputProps, cn, useLocalStorage };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
|
|
6
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
|
|
8
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __defProps = Object.defineProperties;
|
|
12
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
13
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
14
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
15
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
16
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
17
|
+
var __spreadValues = (a, b) => {
|
|
18
|
+
for (var prop in b || (b = {}))
|
|
19
|
+
if (__hasOwnProp.call(b, prop))
|
|
20
|
+
__defNormalProp(a, prop, b[prop]);
|
|
21
|
+
if (__getOwnPropSymbols)
|
|
22
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
23
|
+
if (__propIsEnum.call(b, prop))
|
|
24
|
+
__defNormalProp(a, prop, b[prop]);
|
|
25
|
+
}
|
|
26
|
+
return a;
|
|
27
|
+
};
|
|
28
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
29
|
+
var __objRest = (source, exclude) => {
|
|
30
|
+
var target = {};
|
|
31
|
+
for (var prop in source)
|
|
32
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
33
|
+
target[prop] = source[prop];
|
|
34
|
+
if (source != null && __getOwnPropSymbols)
|
|
35
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
36
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
37
|
+
target[prop] = source[prop];
|
|
38
|
+
}
|
|
39
|
+
return target;
|
|
40
|
+
};
|
|
41
|
+
var variantClasses = {
|
|
42
|
+
primary: "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500",
|
|
43
|
+
secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200 focus:ring-gray-400",
|
|
44
|
+
danger: "bg-red-600 text-white hover:bg-red-700 focus:ring-red-500",
|
|
45
|
+
ghost: "bg-transparent text-gray-700 hover:bg-gray-100 focus:ring-gray-300"
|
|
46
|
+
};
|
|
47
|
+
var sizeClasses = {
|
|
48
|
+
sm: "px-3 py-1.5 text-sm",
|
|
49
|
+
md: "px-4 py-2 text-sm",
|
|
50
|
+
lg: "px-5 py-2.5 text-base"
|
|
51
|
+
};
|
|
52
|
+
function Button(_a) {
|
|
53
|
+
var _b = _a, {
|
|
54
|
+
variant = "primary",
|
|
55
|
+
size = "md",
|
|
56
|
+
loading = false,
|
|
57
|
+
disabled,
|
|
58
|
+
className = "",
|
|
59
|
+
children
|
|
60
|
+
} = _b, props = __objRest(_b, [
|
|
61
|
+
"variant",
|
|
62
|
+
"size",
|
|
63
|
+
"loading",
|
|
64
|
+
"disabled",
|
|
65
|
+
"className",
|
|
66
|
+
"children"
|
|
67
|
+
]);
|
|
68
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
69
|
+
"button",
|
|
70
|
+
__spreadProps(__spreadValues({
|
|
71
|
+
disabled: disabled || loading,
|
|
72
|
+
className: [
|
|
73
|
+
"inline-flex items-center justify-center gap-2 rounded-md font-medium",
|
|
74
|
+
"focus:outline-none focus:ring-2 focus:ring-offset-2",
|
|
75
|
+
"transition-colors duration-150",
|
|
76
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
77
|
+
variantClasses[variant],
|
|
78
|
+
sizeClasses[size],
|
|
79
|
+
className
|
|
80
|
+
].join(" ")
|
|
81
|
+
}, props), {
|
|
82
|
+
children: [
|
|
83
|
+
loading && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
84
|
+
"svg",
|
|
85
|
+
{
|
|
86
|
+
className: "animate-spin h-4 w-4",
|
|
87
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
88
|
+
fill: "none",
|
|
89
|
+
viewBox: "0 0 24 24",
|
|
90
|
+
children: [
|
|
91
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
92
|
+
"circle",
|
|
93
|
+
{
|
|
94
|
+
className: "opacity-25",
|
|
95
|
+
cx: "12",
|
|
96
|
+
cy: "12",
|
|
97
|
+
r: "10",
|
|
98
|
+
stroke: "currentColor",
|
|
99
|
+
strokeWidth: "4"
|
|
100
|
+
}
|
|
101
|
+
),
|
|
102
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
103
|
+
"path",
|
|
104
|
+
{
|
|
105
|
+
className: "opacity-75",
|
|
106
|
+
fill: "currentColor",
|
|
107
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
),
|
|
113
|
+
children
|
|
114
|
+
]
|
|
115
|
+
})
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
var variantClasses2 = {
|
|
119
|
+
default: "bg-gray-100 text-gray-800",
|
|
120
|
+
success: "bg-green-100 text-green-800",
|
|
121
|
+
warning: "bg-yellow-100 text-yellow-800",
|
|
122
|
+
danger: "bg-red-100 text-red-800",
|
|
123
|
+
info: "bg-blue-100 text-blue-800"
|
|
124
|
+
};
|
|
125
|
+
function Badge({ variant = "default", children, className = "" }) {
|
|
126
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
127
|
+
"span",
|
|
128
|
+
{
|
|
129
|
+
className: [
|
|
130
|
+
"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium",
|
|
131
|
+
variantClasses2[variant],
|
|
132
|
+
className
|
|
133
|
+
].join(" "),
|
|
134
|
+
children
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
var Input = React__default.default.forwardRef(
|
|
139
|
+
(_a, ref) => {
|
|
140
|
+
var _b = _a, { label, error, hint, className = "", id } = _b, props = __objRest(_b, ["label", "error", "hint", "className", "id"]);
|
|
141
|
+
const inputId = id || (label == null ? void 0 : label.toLowerCase().replace(/\s+/g, "-"));
|
|
142
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
143
|
+
label && /* @__PURE__ */ jsxRuntime.jsx(
|
|
144
|
+
"label",
|
|
145
|
+
{
|
|
146
|
+
htmlFor: inputId,
|
|
147
|
+
className: "text-sm font-medium text-gray-700",
|
|
148
|
+
children: label
|
|
149
|
+
}
|
|
150
|
+
),
|
|
151
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
152
|
+
"input",
|
|
153
|
+
__spreadValues({
|
|
154
|
+
ref,
|
|
155
|
+
id: inputId,
|
|
156
|
+
className: [
|
|
157
|
+
"block w-full rounded-md border px-3 py-2 text-sm shadow-sm",
|
|
158
|
+
"placeholder:text-gray-400",
|
|
159
|
+
"focus:outline-none focus:ring-2 focus:ring-offset-0",
|
|
160
|
+
error ? "border-red-400 focus:border-red-500 focus:ring-red-300" : "border-gray-300 focus:border-blue-500 focus:ring-blue-200",
|
|
161
|
+
"disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-500",
|
|
162
|
+
className
|
|
163
|
+
].join(" ")
|
|
164
|
+
}, props)
|
|
165
|
+
),
|
|
166
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-600", children: error }),
|
|
167
|
+
hint && !error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500", children: hint })
|
|
168
|
+
] });
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
Input.displayName = "Input";
|
|
172
|
+
function useLocalStorage(key, initialValue) {
|
|
173
|
+
const [storedValue, setStoredValue] = React.useState(() => {
|
|
174
|
+
if (typeof window === "undefined") return initialValue;
|
|
175
|
+
try {
|
|
176
|
+
const item = window.localStorage.getItem(key);
|
|
177
|
+
return item ? JSON.parse(item) : initialValue;
|
|
178
|
+
} catch (e) {
|
|
179
|
+
return initialValue;
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
const setValue = (value) => {
|
|
183
|
+
try {
|
|
184
|
+
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
185
|
+
setStoredValue(valueToStore);
|
|
186
|
+
if (typeof window !== "undefined") {
|
|
187
|
+
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.warn(`useLocalStorage: failed to set "${key}"`, error);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
const remove = () => {
|
|
194
|
+
try {
|
|
195
|
+
setStoredValue(initialValue);
|
|
196
|
+
if (typeof window !== "undefined") {
|
|
197
|
+
window.localStorage.removeItem(key);
|
|
198
|
+
}
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.warn(`useLocalStorage: failed to remove "${key}"`, error);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
return [storedValue, setValue, remove];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// src/utils/cn.ts
|
|
207
|
+
function cn(...classes) {
|
|
208
|
+
return classes.filter(Boolean).join(" ");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
exports.Badge = Badge;
|
|
212
|
+
exports.Button = Button;
|
|
213
|
+
exports.Input = Input;
|
|
214
|
+
exports.cn = cn;
|
|
215
|
+
exports.useLocalStorage = useLocalStorage;
|
|
216
|
+
//# sourceMappingURL=index.js.map
|
|
217
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Button/Button.tsx","../src/components/Badge/Badge.tsx","../src/components/Input/Input.tsx","../src/hooks/useLocalStorage.ts","../src/utils/cn.ts"],"names":["jsxs","jsx","variantClasses","React","useState"],"mappings":"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","file":"index.js","sourcesContent":["import React from \"react\";\n\nexport type ButtonVariant = \"primary\" | \"secondary\" | \"danger\" | \"ghost\";\nexport type ButtonSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n loading?: boolean;\n children: React.ReactNode;\n}\n\nconst variantClasses: Record<ButtonVariant, string> = {\n primary: \"bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500\",\n secondary: \"bg-gray-100 text-gray-900 hover:bg-gray-200 focus:ring-gray-400\",\n danger: \"bg-red-600 text-white hover:bg-red-700 focus:ring-red-500\",\n ghost: \"bg-transparent text-gray-700 hover:bg-gray-100 focus:ring-gray-300\",\n};\n\nconst sizeClasses: Record<ButtonSize, string> = {\n sm: \"px-3 py-1.5 text-sm\",\n md: \"px-4 py-2 text-sm\",\n lg: \"px-5 py-2.5 text-base\",\n};\n\nexport function Button({\n variant = \"primary\",\n size = \"md\",\n loading = false,\n disabled,\n className = \"\",\n children,\n ...props\n}: ButtonProps) {\n return (\n <button\n disabled={disabled || loading}\n className={[\n \"inline-flex items-center justify-center gap-2 rounded-md font-medium\",\n \"focus:outline-none focus:ring-2 focus:ring-offset-2\",\n \"transition-colors duration-150\",\n \"disabled:opacity-50 disabled:cursor-not-allowed\",\n variantClasses[variant],\n sizeClasses[size],\n className,\n ].join(\" \")}\n {...props}\n >\n {loading && (\n <svg\n className=\"animate-spin h-4 w-4\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\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 12h4z\"\n />\n </svg>\n )}\n {children}\n </button>\n );\n}\n","import React from \"react\";\n\nexport type BadgeVariant = \"default\" | \"success\" | \"warning\" | \"danger\" | \"info\";\n\nexport interface BadgeProps {\n variant?: BadgeVariant;\n children: React.ReactNode;\n className?: string;\n}\n\nconst variantClasses: Record<BadgeVariant, string> = {\n default: \"bg-gray-100 text-gray-800\",\n success: \"bg-green-100 text-green-800\",\n warning: \"bg-yellow-100 text-yellow-800\",\n danger: \"bg-red-100 text-red-800\",\n info: \"bg-blue-100 text-blue-800\",\n};\n\nexport function Badge({ variant = \"default\", children, className = \"\" }: BadgeProps) {\n return (\n <span\n className={[\n \"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium\",\n variantClasses[variant],\n className,\n ].join(\" \")}\n >\n {children}\n </span>\n );\n}\n","import React from \"react\";\n\nexport interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {\n label?: string;\n error?: string;\n hint?: string;\n}\n\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ label, error, hint, className = \"\", id, ...props }, ref) => {\n const inputId = id || label?.toLowerCase().replace(/\\s+/g, \"-\");\n\n return (\n <div className=\"flex flex-col gap-1\">\n {label && (\n <label\n htmlFor={inputId}\n className=\"text-sm font-medium text-gray-700\"\n >\n {label}\n </label>\n )}\n <input\n ref={ref}\n id={inputId}\n className={[\n \"block w-full rounded-md border px-3 py-2 text-sm shadow-sm\",\n \"placeholder:text-gray-400\",\n \"focus:outline-none focus:ring-2 focus:ring-offset-0\",\n error\n ? \"border-red-400 focus:border-red-500 focus:ring-red-300\"\n : \"border-gray-300 focus:border-blue-500 focus:ring-blue-200\",\n \"disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-500\",\n className,\n ].join(\" \")}\n {...props}\n />\n {error && <p className=\"text-xs text-red-600\">{error}</p>}\n {hint && !error && <p className=\"text-xs text-gray-500\">{hint}</p>}\n </div>\n );\n }\n);\n\nInput.displayName = \"Input\";\n","import { useState } from \"react\";\n\n/**\n * useState backed by localStorage — syncs value on mount and persists on change.\n */\nexport function useLocalStorage<T>(key: string, initialValue: T) {\n const [storedValue, setStoredValue] = useState<T>(() => {\n if (typeof window === \"undefined\") return initialValue;\n try {\n const item = window.localStorage.getItem(key);\n return item ? (JSON.parse(item) as T) : initialValue;\n } catch {\n return initialValue;\n }\n });\n\n const setValue = (value: T | ((prev: T) => T)) => {\n try {\n const valueToStore = value instanceof Function ? value(storedValue) : value;\n setStoredValue(valueToStore);\n if (typeof window !== \"undefined\") {\n window.localStorage.setItem(key, JSON.stringify(valueToStore));\n }\n } catch (error) {\n console.warn(`useLocalStorage: failed to set \"${key}\"`, error);\n }\n };\n\n const remove = () => {\n try {\n setStoredValue(initialValue);\n if (typeof window !== \"undefined\") {\n window.localStorage.removeItem(key);\n }\n } catch (error) {\n console.warn(`useLocalStorage: failed to remove \"${key}\"`, error);\n }\n };\n\n return [storedValue, setValue, remove] as const;\n}\n","/**\n * Merges class names, filtering out falsy values.\n * Lightweight alternative to clsx for simple use cases.\n */\nexport function cn(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(\" \");\n}\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __defProps = Object.defineProperties;
|
|
6
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
7
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
10
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
11
|
+
var __spreadValues = (a, b) => {
|
|
12
|
+
for (var prop in b || (b = {}))
|
|
13
|
+
if (__hasOwnProp.call(b, prop))
|
|
14
|
+
__defNormalProp(a, prop, b[prop]);
|
|
15
|
+
if (__getOwnPropSymbols)
|
|
16
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
17
|
+
if (__propIsEnum.call(b, prop))
|
|
18
|
+
__defNormalProp(a, prop, b[prop]);
|
|
19
|
+
}
|
|
20
|
+
return a;
|
|
21
|
+
};
|
|
22
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
23
|
+
var __objRest = (source, exclude) => {
|
|
24
|
+
var target = {};
|
|
25
|
+
for (var prop in source)
|
|
26
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
27
|
+
target[prop] = source[prop];
|
|
28
|
+
if (source != null && __getOwnPropSymbols)
|
|
29
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
30
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
31
|
+
target[prop] = source[prop];
|
|
32
|
+
}
|
|
33
|
+
return target;
|
|
34
|
+
};
|
|
35
|
+
var variantClasses = {
|
|
36
|
+
primary: "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500",
|
|
37
|
+
secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200 focus:ring-gray-400",
|
|
38
|
+
danger: "bg-red-600 text-white hover:bg-red-700 focus:ring-red-500",
|
|
39
|
+
ghost: "bg-transparent text-gray-700 hover:bg-gray-100 focus:ring-gray-300"
|
|
40
|
+
};
|
|
41
|
+
var sizeClasses = {
|
|
42
|
+
sm: "px-3 py-1.5 text-sm",
|
|
43
|
+
md: "px-4 py-2 text-sm",
|
|
44
|
+
lg: "px-5 py-2.5 text-base"
|
|
45
|
+
};
|
|
46
|
+
function Button(_a) {
|
|
47
|
+
var _b = _a, {
|
|
48
|
+
variant = "primary",
|
|
49
|
+
size = "md",
|
|
50
|
+
loading = false,
|
|
51
|
+
disabled,
|
|
52
|
+
className = "",
|
|
53
|
+
children
|
|
54
|
+
} = _b, props = __objRest(_b, [
|
|
55
|
+
"variant",
|
|
56
|
+
"size",
|
|
57
|
+
"loading",
|
|
58
|
+
"disabled",
|
|
59
|
+
"className",
|
|
60
|
+
"children"
|
|
61
|
+
]);
|
|
62
|
+
return /* @__PURE__ */ jsxs(
|
|
63
|
+
"button",
|
|
64
|
+
__spreadProps(__spreadValues({
|
|
65
|
+
disabled: disabled || loading,
|
|
66
|
+
className: [
|
|
67
|
+
"inline-flex items-center justify-center gap-2 rounded-md font-medium",
|
|
68
|
+
"focus:outline-none focus:ring-2 focus:ring-offset-2",
|
|
69
|
+
"transition-colors duration-150",
|
|
70
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
71
|
+
variantClasses[variant],
|
|
72
|
+
sizeClasses[size],
|
|
73
|
+
className
|
|
74
|
+
].join(" ")
|
|
75
|
+
}, props), {
|
|
76
|
+
children: [
|
|
77
|
+
loading && /* @__PURE__ */ jsxs(
|
|
78
|
+
"svg",
|
|
79
|
+
{
|
|
80
|
+
className: "animate-spin h-4 w-4",
|
|
81
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
82
|
+
fill: "none",
|
|
83
|
+
viewBox: "0 0 24 24",
|
|
84
|
+
children: [
|
|
85
|
+
/* @__PURE__ */ jsx(
|
|
86
|
+
"circle",
|
|
87
|
+
{
|
|
88
|
+
className: "opacity-25",
|
|
89
|
+
cx: "12",
|
|
90
|
+
cy: "12",
|
|
91
|
+
r: "10",
|
|
92
|
+
stroke: "currentColor",
|
|
93
|
+
strokeWidth: "4"
|
|
94
|
+
}
|
|
95
|
+
),
|
|
96
|
+
/* @__PURE__ */ jsx(
|
|
97
|
+
"path",
|
|
98
|
+
{
|
|
99
|
+
className: "opacity-75",
|
|
100
|
+
fill: "currentColor",
|
|
101
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
),
|
|
107
|
+
children
|
|
108
|
+
]
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
var variantClasses2 = {
|
|
113
|
+
default: "bg-gray-100 text-gray-800",
|
|
114
|
+
success: "bg-green-100 text-green-800",
|
|
115
|
+
warning: "bg-yellow-100 text-yellow-800",
|
|
116
|
+
danger: "bg-red-100 text-red-800",
|
|
117
|
+
info: "bg-blue-100 text-blue-800"
|
|
118
|
+
};
|
|
119
|
+
function Badge({ variant = "default", children, className = "" }) {
|
|
120
|
+
return /* @__PURE__ */ jsx(
|
|
121
|
+
"span",
|
|
122
|
+
{
|
|
123
|
+
className: [
|
|
124
|
+
"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium",
|
|
125
|
+
variantClasses2[variant],
|
|
126
|
+
className
|
|
127
|
+
].join(" "),
|
|
128
|
+
children
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
var Input = React.forwardRef(
|
|
133
|
+
(_a, ref) => {
|
|
134
|
+
var _b = _a, { label, error, hint, className = "", id } = _b, props = __objRest(_b, ["label", "error", "hint", "className", "id"]);
|
|
135
|
+
const inputId = id || (label == null ? void 0 : label.toLowerCase().replace(/\s+/g, "-"));
|
|
136
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
137
|
+
label && /* @__PURE__ */ jsx(
|
|
138
|
+
"label",
|
|
139
|
+
{
|
|
140
|
+
htmlFor: inputId,
|
|
141
|
+
className: "text-sm font-medium text-gray-700",
|
|
142
|
+
children: label
|
|
143
|
+
}
|
|
144
|
+
),
|
|
145
|
+
/* @__PURE__ */ jsx(
|
|
146
|
+
"input",
|
|
147
|
+
__spreadValues({
|
|
148
|
+
ref,
|
|
149
|
+
id: inputId,
|
|
150
|
+
className: [
|
|
151
|
+
"block w-full rounded-md border px-3 py-2 text-sm shadow-sm",
|
|
152
|
+
"placeholder:text-gray-400",
|
|
153
|
+
"focus:outline-none focus:ring-2 focus:ring-offset-0",
|
|
154
|
+
error ? "border-red-400 focus:border-red-500 focus:ring-red-300" : "border-gray-300 focus:border-blue-500 focus:ring-blue-200",
|
|
155
|
+
"disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-500",
|
|
156
|
+
className
|
|
157
|
+
].join(" ")
|
|
158
|
+
}, props)
|
|
159
|
+
),
|
|
160
|
+
error && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-600", children: error }),
|
|
161
|
+
hint && !error && /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500", children: hint })
|
|
162
|
+
] });
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
Input.displayName = "Input";
|
|
166
|
+
function useLocalStorage(key, initialValue) {
|
|
167
|
+
const [storedValue, setStoredValue] = useState(() => {
|
|
168
|
+
if (typeof window === "undefined") return initialValue;
|
|
169
|
+
try {
|
|
170
|
+
const item = window.localStorage.getItem(key);
|
|
171
|
+
return item ? JSON.parse(item) : initialValue;
|
|
172
|
+
} catch (e) {
|
|
173
|
+
return initialValue;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
const setValue = (value) => {
|
|
177
|
+
try {
|
|
178
|
+
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
179
|
+
setStoredValue(valueToStore);
|
|
180
|
+
if (typeof window !== "undefined") {
|
|
181
|
+
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
182
|
+
}
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.warn(`useLocalStorage: failed to set "${key}"`, error);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
const remove = () => {
|
|
188
|
+
try {
|
|
189
|
+
setStoredValue(initialValue);
|
|
190
|
+
if (typeof window !== "undefined") {
|
|
191
|
+
window.localStorage.removeItem(key);
|
|
192
|
+
}
|
|
193
|
+
} catch (error) {
|
|
194
|
+
console.warn(`useLocalStorage: failed to remove "${key}"`, error);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
return [storedValue, setValue, remove];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// src/utils/cn.ts
|
|
201
|
+
function cn(...classes) {
|
|
202
|
+
return classes.filter(Boolean).join(" ");
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export { Badge, Button, Input, cn, useLocalStorage };
|
|
206
|
+
//# sourceMappingURL=index.mjs.map
|
|
207
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Button/Button.tsx","../src/components/Badge/Badge.tsx","../src/components/Input/Input.tsx","../src/hooks/useLocalStorage.ts","../src/utils/cn.ts"],"names":["variantClasses","jsx","jsxs"],"mappings":"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","file":"index.mjs","sourcesContent":["import React from \"react\";\n\nexport type ButtonVariant = \"primary\" | \"secondary\" | \"danger\" | \"ghost\";\nexport type ButtonSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n loading?: boolean;\n children: React.ReactNode;\n}\n\nconst variantClasses: Record<ButtonVariant, string> = {\n primary: \"bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500\",\n secondary: \"bg-gray-100 text-gray-900 hover:bg-gray-200 focus:ring-gray-400\",\n danger: \"bg-red-600 text-white hover:bg-red-700 focus:ring-red-500\",\n ghost: \"bg-transparent text-gray-700 hover:bg-gray-100 focus:ring-gray-300\",\n};\n\nconst sizeClasses: Record<ButtonSize, string> = {\n sm: \"px-3 py-1.5 text-sm\",\n md: \"px-4 py-2 text-sm\",\n lg: \"px-5 py-2.5 text-base\",\n};\n\nexport function Button({\n variant = \"primary\",\n size = \"md\",\n loading = false,\n disabled,\n className = \"\",\n children,\n ...props\n}: ButtonProps) {\n return (\n <button\n disabled={disabled || loading}\n className={[\n \"inline-flex items-center justify-center gap-2 rounded-md font-medium\",\n \"focus:outline-none focus:ring-2 focus:ring-offset-2\",\n \"transition-colors duration-150\",\n \"disabled:opacity-50 disabled:cursor-not-allowed\",\n variantClasses[variant],\n sizeClasses[size],\n className,\n ].join(\" \")}\n {...props}\n >\n {loading && (\n <svg\n className=\"animate-spin h-4 w-4\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\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 12h4z\"\n />\n </svg>\n )}\n {children}\n </button>\n );\n}\n","import React from \"react\";\n\nexport type BadgeVariant = \"default\" | \"success\" | \"warning\" | \"danger\" | \"info\";\n\nexport interface BadgeProps {\n variant?: BadgeVariant;\n children: React.ReactNode;\n className?: string;\n}\n\nconst variantClasses: Record<BadgeVariant, string> = {\n default: \"bg-gray-100 text-gray-800\",\n success: \"bg-green-100 text-green-800\",\n warning: \"bg-yellow-100 text-yellow-800\",\n danger: \"bg-red-100 text-red-800\",\n info: \"bg-blue-100 text-blue-800\",\n};\n\nexport function Badge({ variant = \"default\", children, className = \"\" }: BadgeProps) {\n return (\n <span\n className={[\n \"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium\",\n variantClasses[variant],\n className,\n ].join(\" \")}\n >\n {children}\n </span>\n );\n}\n","import React from \"react\";\n\nexport interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {\n label?: string;\n error?: string;\n hint?: string;\n}\n\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ label, error, hint, className = \"\", id, ...props }, ref) => {\n const inputId = id || label?.toLowerCase().replace(/\\s+/g, \"-\");\n\n return (\n <div className=\"flex flex-col gap-1\">\n {label && (\n <label\n htmlFor={inputId}\n className=\"text-sm font-medium text-gray-700\"\n >\n {label}\n </label>\n )}\n <input\n ref={ref}\n id={inputId}\n className={[\n \"block w-full rounded-md border px-3 py-2 text-sm shadow-sm\",\n \"placeholder:text-gray-400\",\n \"focus:outline-none focus:ring-2 focus:ring-offset-0\",\n error\n ? \"border-red-400 focus:border-red-500 focus:ring-red-300\"\n : \"border-gray-300 focus:border-blue-500 focus:ring-blue-200\",\n \"disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-500\",\n className,\n ].join(\" \")}\n {...props}\n />\n {error && <p className=\"text-xs text-red-600\">{error}</p>}\n {hint && !error && <p className=\"text-xs text-gray-500\">{hint}</p>}\n </div>\n );\n }\n);\n\nInput.displayName = \"Input\";\n","import { useState } from \"react\";\n\n/**\n * useState backed by localStorage — syncs value on mount and persists on change.\n */\nexport function useLocalStorage<T>(key: string, initialValue: T) {\n const [storedValue, setStoredValue] = useState<T>(() => {\n if (typeof window === \"undefined\") return initialValue;\n try {\n const item = window.localStorage.getItem(key);\n return item ? (JSON.parse(item) as T) : initialValue;\n } catch {\n return initialValue;\n }\n });\n\n const setValue = (value: T | ((prev: T) => T)) => {\n try {\n const valueToStore = value instanceof Function ? value(storedValue) : value;\n setStoredValue(valueToStore);\n if (typeof window !== \"undefined\") {\n window.localStorage.setItem(key, JSON.stringify(valueToStore));\n }\n } catch (error) {\n console.warn(`useLocalStorage: failed to set \"${key}\"`, error);\n }\n };\n\n const remove = () => {\n try {\n setStoredValue(initialValue);\n if (typeof window !== \"undefined\") {\n window.localStorage.removeItem(key);\n }\n } catch (error) {\n console.warn(`useLocalStorage: failed to remove \"${key}\"`, error);\n }\n };\n\n return [storedValue, setValue, remove] as const;\n}\n","/**\n * Merges class names, filtering out falsy values.\n * Lightweight alternative to clsx for simple use cases.\n */\nexport function cn(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(\" \");\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@seekho/ui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Seekho internal UI component library",
|
|
5
|
+
"keywords": ["seekho", "ui", "components", "react", "tailwind"],
|
|
6
|
+
"author": "Seekho",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"module": "dist/index.mjs",
|
|
13
|
+
"types": "dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.mjs",
|
|
18
|
+
"require": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": ["dist"],
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsup",
|
|
25
|
+
"build:watch": "tsup --watch",
|
|
26
|
+
"storybook": "storybook dev -p 6006",
|
|
27
|
+
"build-storybook": "storybook build",
|
|
28
|
+
"lint": "tsc --noEmit",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"react": ">=17",
|
|
33
|
+
"react-dom": ">=17"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/react": "^19.2.14",
|
|
37
|
+
"@types/react-dom": "^19.2.3",
|
|
38
|
+
"autoprefixer": "^10.4.27",
|
|
39
|
+
"postcss": "^8.5.8",
|
|
40
|
+
"react": "^19.2.4",
|
|
41
|
+
"react-dom": "^19.2.4",
|
|
42
|
+
"tailwindcss": "^4.2.2",
|
|
43
|
+
"tsup": "^8.5.1",
|
|
44
|
+
"typescript": "^6.0.2",
|
|
45
|
+
"storybook": "^10.3.3",
|
|
46
|
+
"@storybook/react-vite": "^10.3.3",
|
|
47
|
+
"@chromatic-com/storybook": "^5.1.1",
|
|
48
|
+
"@storybook/addon-vitest": "^10.3.3",
|
|
49
|
+
"@storybook/addon-a11y": "^10.3.3",
|
|
50
|
+
"@storybook/addon-docs": "^10.3.3",
|
|
51
|
+
"@storybook/addon-onboarding": "^10.3.3",
|
|
52
|
+
"vitest": "^4.1.2",
|
|
53
|
+
"playwright": "^1.58.2",
|
|
54
|
+
"@vitest/browser-playwright": "^4.1.2",
|
|
55
|
+
"@vitest/coverage-v8": "^4.1.2"
|
|
56
|
+
}
|
|
57
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# seekho-ui
|
|
2
|
+
|
|
3
|
+
Seekho internal UI component library — shared components, hooks, and utilities for internal tools built on React + Tailwind.
|
|
4
|
+
|
|
5
|
+
## What's included
|
|
6
|
+
|
|
7
|
+
| Export | Description |
|
|
8
|
+
| ------ | ----------- |
|
|
9
|
+
| `<Button>` | Primary, secondary, danger, ghost variants with loading state |
|
|
10
|
+
| `<Badge>` | Status badges (success, warning, danger, info) |
|
|
11
|
+
| `<Input>` | Form input with label, hint, and error state |
|
|
12
|
+
| `useLocalStorage` | useState backed by localStorage |
|
|
13
|
+
| `cn()` | Utility to merge Tailwind class names |
|
|
14
|
+
|
|
15
|
+
## Development
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install
|
|
19
|
+
npm run storybook # component playground at http://localhost:6006
|
|
20
|
+
npm run build # build dist/
|
|
21
|
+
npm run lint # type check
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Using in a consumer project
|
|
25
|
+
|
|
26
|
+
### 1. Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# If published to npm:
|
|
30
|
+
npm install seekho-ui
|
|
31
|
+
|
|
32
|
+
# If using local path during development:
|
|
33
|
+
npm install ../seekho-ui
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 2. Add library source to your Tailwind content paths
|
|
37
|
+
|
|
38
|
+
In your app's `tailwind.config.js` (or `tailwind.css` for v4):
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
// tailwind.config.js
|
|
42
|
+
module.exports = {
|
|
43
|
+
content: [
|
|
44
|
+
"./src/**/*.{ts,tsx}",
|
|
45
|
+
"./node_modules/seekho-ui/dist/**/*.js", // <-- add this
|
|
46
|
+
],
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 3. Import and use
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { Button, Badge, Input, useLocalStorage, cn } from "seekho-ui";
|
|
54
|
+
|
|
55
|
+
export function MyPage() {
|
|
56
|
+
return (
|
|
57
|
+
<div>
|
|
58
|
+
<Button variant="primary" onClick={() => {}}>Save</Button>
|
|
59
|
+
<Badge variant="success">Active</Badge>
|
|
60
|
+
<Input label="Email" placeholder="you@seekho.ai" />
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Publishing
|
|
67
|
+
|
|
68
|
+
### npm (recommended for internal use)
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Login once
|
|
72
|
+
npm login
|
|
73
|
+
|
|
74
|
+
# Publish
|
|
75
|
+
npm publish
|
|
76
|
+
|
|
77
|
+
# Or bump version first
|
|
78
|
+
npm version patch # 0.1.0 → 0.1.1
|
|
79
|
+
npm publish
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### GitHub Packages (free private hosting)
|
|
83
|
+
|
|
84
|
+
1. Add to `package.json`: `"name": "@seekho/ui"`
|
|
85
|
+
2. Create `.npmrc`:
|
|
86
|
+
|
|
87
|
+
```ini
|
|
88
|
+
@seekho:registry=https://npm.pkg.github.com
|
|
89
|
+
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
3. `npm publish`
|
|
93
|
+
|
|
94
|
+
## Adding a new component
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
src/components/
|
|
98
|
+
└── MyComponent/
|
|
99
|
+
├── MyComponent.tsx # component + types
|
|
100
|
+
├── MyComponent.stories.tsx
|
|
101
|
+
└── index.ts # re-export
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Then add `export * from "./MyComponent"` to [src/components/index.ts](src/components/index.ts).
|
|
105
|
+
|
|
106
|
+
## Project structure
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
seekho-ui/
|
|
110
|
+
├── src/
|
|
111
|
+
│ ├── components/ # React components
|
|
112
|
+
│ ├── hooks/ # Shared React hooks
|
|
113
|
+
│ ├── utils/ # Pure utility functions
|
|
114
|
+
│ └── index.ts # Single entry point
|
|
115
|
+
├── .storybook/ # Storybook config
|
|
116
|
+
├── tsup.config.ts # Build config
|
|
117
|
+
└── tailwind.config.js # Tailwind (for Storybook)
|
|
118
|
+
```
|