@seekho/ui 0.1.1 → 0.1.3

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 CHANGED
@@ -26,6 +26,20 @@ interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
26
26
  }
27
27
  declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
28
28
 
29
+ interface ModalProps {
30
+ show: boolean;
31
+ title?: string;
32
+ className?: string;
33
+ children?: React.ReactNode;
34
+ isLoading?: boolean;
35
+ onHide?: () => void;
36
+ isWarning?: boolean;
37
+ isButtonsRequired?: boolean;
38
+ handleConfirmation?: () => void;
39
+ handleConfirmationBtnText?: string;
40
+ }
41
+ declare function Modal({ show, title, className, children, isLoading, onHide, isWarning, isButtonsRequired, handleConfirmation, handleConfirmationBtnText, }: ModalProps): react_jsx_runtime.JSX.Element | null;
42
+
29
43
  /**
30
44
  * useState backed by localStorage — syncs value on mount and persists on change.
31
45
  */
@@ -37,4 +51,4 @@ declare function useLocalStorage<T>(key: string, initialValue: T): readonly [T,
37
51
  */
38
52
  declare function cn(...classes: (string | undefined | null | false)[]): string;
39
53
 
40
- export { Badge, type BadgeProps, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Input, type InputProps, cn, useLocalStorage };
54
+ export { Badge, type BadgeProps, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Input, type InputProps, Modal, type ModalProps, cn, useLocalStorage };
package/dist/index.d.ts CHANGED
@@ -26,6 +26,20 @@ interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
26
26
  }
27
27
  declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
28
28
 
29
+ interface ModalProps {
30
+ show: boolean;
31
+ title?: string;
32
+ className?: string;
33
+ children?: React.ReactNode;
34
+ isLoading?: boolean;
35
+ onHide?: () => void;
36
+ isWarning?: boolean;
37
+ isButtonsRequired?: boolean;
38
+ handleConfirmation?: () => void;
39
+ handleConfirmationBtnText?: string;
40
+ }
41
+ declare function Modal({ show, title, className, children, isLoading, onHide, isWarning, isButtonsRequired, handleConfirmation, handleConfirmationBtnText, }: ModalProps): react_jsx_runtime.JSX.Element | null;
42
+
29
43
  /**
30
44
  * useState backed by localStorage — syncs value on mount and persists on change.
31
45
  */
@@ -37,4 +51,4 @@ declare function useLocalStorage<T>(key: string, initialValue: T): readonly [T,
37
51
  */
38
52
  declare function cn(...classes: (string | undefined | null | false)[]): string;
39
53
 
40
- export { Badge, type BadgeProps, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Input, type InputProps, cn, useLocalStorage };
54
+ export { Badge, type BadgeProps, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Input, type InputProps, Modal, type ModalProps, cn, useLocalStorage };
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var React = require('react');
5
+ var reactHotkeysHook = require('react-hotkeys-hook');
5
6
 
6
7
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
8
 
@@ -39,7 +40,7 @@ var __objRest = (source, exclude) => {
39
40
  return target;
40
41
  };
41
42
  var variantClasses = {
42
- primary: "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500",
43
+ primary: "bg-basePurple text-white hover:bg-basePurple/80 focus:ring-basePurple/50",
43
44
  secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200 focus:ring-gray-400",
44
45
  danger: "bg-red-600 text-white hover:bg-red-700 focus:ring-red-500",
45
46
  ghost: "bg-transparent text-gray-700 hover:bg-gray-100 focus:ring-gray-300"
@@ -169,6 +170,155 @@ var Input = React__default.default.forwardRef(
169
170
  }
170
171
  );
171
172
  Input.displayName = "Input";
173
+
174
+ // src/utils/modalStack.ts
175
+ var stack = [];
176
+ function handlePushModal({ id }) {
177
+ if (!stack.find((m) => m.id === id)) {
178
+ stack.push({ id });
179
+ }
180
+ }
181
+ function handlePopModal({ id }) {
182
+ const idx = stack.findIndex((m) => m.id === id);
183
+ if (idx !== -1) stack.splice(idx, 1);
184
+ }
185
+ function handleIsTopModal({ id }) {
186
+ return stack.length > 0 && stack[stack.length - 1].id === id;
187
+ }
188
+ function Modal({
189
+ show,
190
+ title = "",
191
+ className,
192
+ children,
193
+ isLoading = false,
194
+ onHide,
195
+ isWarning = false,
196
+ isButtonsRequired = true,
197
+ handleConfirmation,
198
+ handleConfirmationBtnText = "Confirm"
199
+ }) {
200
+ const modalId = React.useId();
201
+ React.useEffect(() => {
202
+ if (show) handlePushModal({ id: modalId });
203
+ return () => handlePopModal({ id: modalId });
204
+ }, [show, modalId]);
205
+ reactHotkeysHook.useHotkeys(
206
+ "enter",
207
+ (e) => {
208
+ e.preventDefault();
209
+ if (show && handleIsTopModal({ id: modalId }) && handleConfirmation)
210
+ handleConfirmation();
211
+ },
212
+ { enabled: show && !isLoading }
213
+ );
214
+ reactHotkeysHook.useHotkeys(
215
+ "esc",
216
+ (e) => {
217
+ e.preventDefault();
218
+ if (show && handleIsTopModal({ id: modalId }) && onHide) onHide();
219
+ },
220
+ { enabled: show && !isLoading }
221
+ );
222
+ if (!show) return null;
223
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-999 bg-gray-800/50 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs(
224
+ "div",
225
+ {
226
+ className: [
227
+ "w-[95%] bg-white rounded-lg shadow-lg flex flex-col",
228
+ "md:w-[60%] lg:w-[30%] max-h-[95vh]",
229
+ className || ""
230
+ ].join(" "),
231
+ children: [
232
+ title && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3.5 py-3 border-b border-gray-200 flex justify-between items-start gap-x-3", children: [
233
+ /* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "text-[17px] font-semibold line-clamp-2 capitalize flex gap-x-2 items-center", children: [
234
+ isWarning && /* @__PURE__ */ jsxRuntime.jsx(
235
+ "svg",
236
+ {
237
+ className: "text-red-500 w-6 h-6 shrink-0",
238
+ viewBox: "0 0 24 24",
239
+ fill: "currentColor",
240
+ children: /* @__PURE__ */ jsxRuntime.jsx(
241
+ "path",
242
+ {
243
+ fillRule: "evenodd",
244
+ d: "M12 2a10 10 0 100 20A10 10 0 0012 2zm0 5a1 1 0 011 1v4a1 1 0 11-2 0V8a1 1 0 011-1zm0 8a1.25 1.25 0 110 2.5A1.25 1.25 0 0112 15z",
245
+ clipRule: "evenodd"
246
+ }
247
+ )
248
+ }
249
+ ),
250
+ title
251
+ ] }),
252
+ onHide && /* @__PURE__ */ jsxRuntime.jsx(
253
+ "button",
254
+ {
255
+ onClick: onHide,
256
+ className: "text-gray-400 hover:text-gray-600 transition-colors shrink-0",
257
+ "aria-label": "Close",
258
+ children: "\u2715"
259
+ }
260
+ )
261
+ ] }),
262
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto px-3.5 py-3", children }),
263
+ isButtonsRequired && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-3 bg-gray-100 flex justify-end space-x-3 rounded-b-md border-t", children: [
264
+ onHide && /* @__PURE__ */ jsxRuntime.jsx(
265
+ "button",
266
+ {
267
+ onClick: onHide,
268
+ className: "px-4 py-2 border bg-white rounded-md font-semibold text-[14px] hover:bg-gray-50 transition-colors",
269
+ children: "Cancel"
270
+ }
271
+ ),
272
+ /* @__PURE__ */ jsxRuntime.jsx(
273
+ "button",
274
+ {
275
+ onClick: handleConfirmation,
276
+ disabled: isLoading,
277
+ className: [
278
+ "px-4 py-2 text-white rounded-md text-[14px] font-semibold",
279
+ "disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
280
+ isWarning ? "bg-red-600 hover:bg-red-700" : "bg-basePurple hover:bg-basePurple/80"
281
+ ].join(" "),
282
+ children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
283
+ /* @__PURE__ */ jsxRuntime.jsxs(
284
+ "svg",
285
+ {
286
+ className: "animate-spin h-4 w-4",
287
+ xmlns: "http://www.w3.org/2000/svg",
288
+ fill: "none",
289
+ viewBox: "0 0 24 24",
290
+ children: [
291
+ /* @__PURE__ */ jsxRuntime.jsx(
292
+ "circle",
293
+ {
294
+ className: "opacity-25",
295
+ cx: "12",
296
+ cy: "12",
297
+ r: "10",
298
+ stroke: "currentColor",
299
+ strokeWidth: "4"
300
+ }
301
+ ),
302
+ /* @__PURE__ */ jsxRuntime.jsx(
303
+ "path",
304
+ {
305
+ className: "opacity-75",
306
+ fill: "currentColor",
307
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
308
+ }
309
+ )
310
+ ]
311
+ }
312
+ ),
313
+ handleConfirmationBtnText
314
+ ] }) : handleConfirmationBtnText
315
+ }
316
+ )
317
+ ] })
318
+ ]
319
+ }
320
+ ) });
321
+ }
172
322
  function useLocalStorage(key, initialValue) {
173
323
  const [storedValue, setStoredValue] = React.useState(() => {
174
324
  if (typeof window === "undefined") return initialValue;
@@ -211,6 +361,7 @@ function cn(...classes) {
211
361
  exports.Badge = Badge;
212
362
  exports.Button = Button;
213
363
  exports.Input = Input;
364
+ exports.Modal = Modal;
214
365
  exports.cn = cn;
215
366
  exports.useLocalStorage = useLocalStorage;
216
367
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYA,IAAM,cAAA,GAAgD;AAAA,EACpD,OAAA,EAAS,8DAAA;AAAA,EACT,SAAA,EAAW,iEAAA;AAAA,EACX,MAAA,EAAQ,2DAAA;AAAA,EACR,KAAA,EAAO;AACT,CAAA;AAEA,IAAM,WAAA,GAA0C;AAAA,EAC9C,EAAA,EAAI,qBAAA;AAAA,EACJ,EAAA,EAAI,mBAAA;AAAA,EACJ,EAAA,EAAI;AACN,CAAA;AAEO,SAAS,OAAO,EAAA,EAQP;AARO,EAAA,IAAA,EAAA,GAAA,EAAA,EACrB;AAAA,IAAA,OAAA,GAAU,SAAA;AAAA,IACV,IAAA,GAAO,IAAA;AAAA,IACP,OAAA,GAAU,KAAA;AAAA,IACV,QAAA;AAAA,IACA,SAAA,GAAY,EAAA;AAAA,IACZ;AAAA,GA/BF,GAyBuB,EAAA,EAOlB,KAAA,GAAA,SAAA,CAPkB,EAAA,EAOlB;AAAA,IANH,SAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA;AAAA,IACA,UAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GAAA,CAAA;AAGA,EAAA,uBACEA,eAAA;AAAA,IAAC,QAAA;AAAA,IAAA,aAAA,CAAA,cAAA,CAAA;AAAA,MACC,UAAU,QAAA,IAAY,OAAA;AAAA,MACtB,SAAA,EAAW;AAAA,QACT,sEAAA;AAAA,QACA,qDAAA;AAAA,QACA,gCAAA;AAAA,QACA,iDAAA;AAAA,QACA,eAAe,OAAO,CAAA;AAAA,QACtB,YAAY,IAAI,CAAA;AAAA,QAChB;AAAA,OACF,CAAE,KAAK,GAAG;AAAA,KAAA,EACN,KAAA,CAAA,EAXL;AAAA,MAaE,QAAA,EAAA;AAAA,QAAA,OAAA,oBACCA,eAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,sBAAA;AAAA,YACV,KAAA,EAAM,4BAAA;AAAA,YACN,IAAA,EAAK,MAAA;AAAA,YACL,OAAA,EAAQ,WAAA;AAAA,YAER,QAAA,EAAA;AAAA,8BAAAC,cAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBACC,SAAA,EAAU,YAAA;AAAA,kBACV,EAAA,EAAG,IAAA;AAAA,kBACH,EAAA,EAAG,IAAA;AAAA,kBACH,CAAA,EAAE,IAAA;AAAA,kBACF,MAAA,EAAO,cAAA;AAAA,kBACP,WAAA,EAAY;AAAA;AAAA,eACd;AAAA,8BACAA,cAAA;AAAA,gBAAC,MAAA;AAAA,gBAAA;AAAA,kBACC,SAAA,EAAU,YAAA;AAAA,kBACV,IAAA,EAAK,cAAA;AAAA,kBACL,CAAA,EAAE;AAAA;AAAA;AACJ;AAAA;AAAA,SACF;AAAA,QAED;AAAA;AAAA,KAAA;AAAA,GACH;AAEJ;AC/DA,IAAMC,eAAAA,GAA+C;AAAA,EACnD,OAAA,EAAS,2BAAA;AAAA,EACT,OAAA,EAAS,6BAAA;AAAA,EACT,OAAA,EAAS,+BAAA;AAAA,EACT,MAAA,EAAQ,yBAAA;AAAA,EACR,IAAA,EAAM;AACR,CAAA;AAEO,SAAS,MAAM,EAAE,OAAA,GAAU,WAAW,QAAA,EAAU,SAAA,GAAY,IAAG,EAAe;AACnF,EAAA,uBACED,cAAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW;AAAA,QACT,yEAAA;AAAA,QACAC,gBAAe,OAAO,CAAA;AAAA,QACtB;AAAA,OACF,CAAE,KAAK,GAAG,CAAA;AAAA,MAET;AAAA;AAAA,GACH;AAEJ;ACtBO,IAAM,QAAQC,sBAAA,CAAM,UAAA;AAAA,EACzB,CAAC,IAAsD,GAAA,KAAQ;AAA9D,IAAA,IAAA,EAAA,GAAA,EAAA,EAAE,EAAA,KAAA,EAAO,KAAA,EAAO,IAAA,EAAM,SAAA,GAAY,IAAI,EAAA,EATzC,GASG,EAAA,EAA6C,KAAA,GAAA,SAAA,CAA7C,EAAA,EAA6C,CAA3C,OAAA,EAAO,OAAA,EAAO,QAAM,WAAA,EAAgB,IAAA,CAAA,CAAA;AACrC,IAAA,MAAM,OAAA,GAAU,EAAA,KAAM,KAAA,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAO,WAAA,EAAA,CAAc,QAAQ,MAAA,EAAQ,GAAA,CAAA,CAAA;AAE3D,IAAA,uBACEH,eAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qBAAA,EACZ,QAAA,EAAA;AAAA,MAAA,KAAA,oBACCC,cAAAA;AAAA,QAAC,OAAA;AAAA,QAAA;AAAA,UACC,OAAA,EAAS,OAAA;AAAA,UACT,SAAA,EAAU,mCAAA;AAAA,UAET,QAAA,EAAA;AAAA;AAAA,OACH;AAAA,sBAEFA,cAAAA;AAAA,QAAC,OAAA;AAAA,QAAA,cAAA,CAAA;AAAA,UACC,GAAA;AAAA,UACA,EAAA,EAAI,OAAA;AAAA,UACJ,SAAA,EAAW;AAAA,YACT,4DAAA;AAAA,YACA,2BAAA;AAAA,YACA,qDAAA;AAAA,YACA,QACI,wDAAA,GACA,2DAAA;AAAA,YACJ,wEAAA;AAAA,YACA;AAAA,WACF,CAAE,KAAK,GAAG;AAAA,SAAA,EACN,KAAA;AAAA,OACN;AAAA,MACC,yBAASA,cAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,wBAAwB,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,MACpD,IAAA,IAAQ,CAAC,KAAA,oBAASA,eAAC,GAAA,EAAA,EAAE,SAAA,EAAU,yBAAyB,QAAA,EAAA,IAAA,EAAK;AAAA,KAAA,EAChE,CAAA;AAAA,EAEJ;AACF;AAEA,KAAA,CAAM,WAAA,GAAc,OAAA;ACvCb,SAAS,eAAA,CAAmB,KAAa,YAAA,EAAiB;AAC/D,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAIG,eAAY,MAAM;AACtD,IAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,YAAA;AAC1C,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAA,CAAO,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA;AAC5C,MAAA,OAAO,IAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,GAAU,YAAA;AAAA,IAC1C,CAAA,CAAA,OAAQ,CAAA,EAAA;AACN,MAAA,OAAO,YAAA;AAAA,IACT;AAAA,EACF,CAAC,CAAA;AAED,EAAA,MAAM,QAAA,GAAW,CAAC,KAAA,KAAgC;AAChD,IAAA,IAAI;AACF,MAAA,MAAM,YAAA,GAAe,KAAA,YAAiB,QAAA,GAAW,KAAA,CAAM,WAAW,CAAA,GAAI,KAAA;AACtE,MAAA,cAAA,CAAe,YAAY,CAAA;AAC3B,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,QAAA,MAAA,CAAO,aAAa,OAAA,CAAQ,GAAA,EAAK,IAAA,CAAK,SAAA,CAAU,YAAY,CAAC,CAAA;AAAA,MAC/D;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,gCAAA,EAAmC,GAAG,CAAA,CAAA,CAAA,EAAK,KAAK,CAAA;AAAA,IAC/D;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,IAAI;AACF,MAAA,cAAA,CAAe,YAAY,CAAA;AAC3B,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,QAAA,MAAA,CAAO,YAAA,CAAa,WAAW,GAAG,CAAA;AAAA,MACpC;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,mCAAA,EAAsC,GAAG,CAAA,CAAA,CAAA,EAAK,KAAK,CAAA;AAAA,IAClE;AAAA,EACF,CAAA;AAEA,EAAA,OAAO,CAAC,WAAA,EAAa,QAAA,EAAU,MAAM,CAAA;AACvC;;;ACpCO,SAAS,MAAM,OAAA,EAAwD;AAC5E,EAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,GAAG,CAAA;AACzC","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"]}
1
+ {"version":3,"sources":["../src/components/Button/Button.tsx","../src/components/Badge/Badge.tsx","../src/components/Input/Input.tsx","../src/utils/modalStack.ts","../src/components/Modal/Modal.tsx","../src/hooks/useLocalStorage.ts","../src/utils/cn.ts"],"names":["jsxs","jsx","variantClasses","React","useId","useEffect","useHotkeys","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-basePurple text-white hover:bg-basePurple/80 focus:ring-basePurple/50\",\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","type ModalEntry = { id: string };\n\nconst stack: ModalEntry[] = [];\n\nexport function handlePushModal({ id }: ModalEntry) {\n if (!stack.find((m) => m.id === id)) {\n stack.push({ id });\n }\n}\n\nexport function handlePopModal({ id }: ModalEntry) {\n const idx = stack.findIndex((m) => m.id === id);\n if (idx !== -1) stack.splice(idx, 1);\n}\n\nexport function handleIsTopModal({ id }: ModalEntry): boolean {\n return stack.length > 0 && stack[stack.length - 1].id === id;\n}\n","import React, { useEffect, useId } from \"react\";\nimport { useHotkeys } from \"react-hotkeys-hook\";\nimport {\n handleIsTopModal,\n handlePopModal,\n handlePushModal,\n} from \"../../utils/modalStack\";\n\nexport interface ModalProps {\n show: boolean;\n title?: string;\n className?: string;\n children?: React.ReactNode;\n isLoading?: boolean;\n onHide?: () => void;\n isWarning?: boolean;\n isButtonsRequired?: boolean;\n handleConfirmation?: () => void;\n handleConfirmationBtnText?: string;\n}\n\nexport function Modal({\n show,\n title = \"\",\n className,\n children,\n isLoading = false,\n onHide,\n isWarning = false,\n isButtonsRequired = true,\n handleConfirmation,\n handleConfirmationBtnText = \"Confirm\",\n}: ModalProps) {\n const modalId = useId();\n\n useEffect(() => {\n if (show) handlePushModal({ id: modalId });\n return () => handlePopModal({ id: modalId });\n }, [show, modalId]);\n\n useHotkeys(\n \"enter\",\n (e) => {\n e.preventDefault();\n if (show && handleIsTopModal({ id: modalId }) && handleConfirmation)\n handleConfirmation();\n },\n { enabled: show && !isLoading }\n );\n\n useHotkeys(\n \"esc\",\n (e) => {\n e.preventDefault();\n if (show && handleIsTopModal({ id: modalId }) && onHide) onHide();\n },\n { enabled: show && !isLoading }\n );\n\n if (!show) return null;\n\n return (\n <div className=\"fixed inset-0 z-999 bg-gray-800/50 flex items-center justify-center\">\n <div\n className={[\n \"w-[95%] bg-white rounded-lg shadow-lg flex flex-col\",\n \"md:w-[60%] lg:w-[30%] max-h-[95vh]\",\n className || \"\",\n ].join(\" \")}\n >\n {/* Header */}\n {title && (\n <div className=\"px-3.5 py-3 border-b border-gray-200 flex justify-between items-start gap-x-3\">\n <h2 className=\"text-[17px] font-semibold line-clamp-2 capitalize flex gap-x-2 items-center\">\n {isWarning && (\n <svg\n className=\"text-red-500 w-6 h-6 shrink-0\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M12 2a10 10 0 100 20A10 10 0 0012 2zm0 5a1 1 0 011 1v4a1 1 0 11-2 0V8a1 1 0 011-1zm0 8a1.25 1.25 0 110 2.5A1.25 1.25 0 0112 15z\"\n clipRule=\"evenodd\"\n />\n </svg>\n )}\n {title}\n </h2>\n {onHide && (\n <button\n onClick={onHide}\n className=\"text-gray-400 hover:text-gray-600 transition-colors shrink-0\"\n aria-label=\"Close\"\n >\n ✕\n </button>\n )}\n </div>\n )}\n\n {/* Body */}\n <div className=\"flex-1 overflow-y-auto px-3.5 py-3\">{children}</div>\n\n {/* Footer */}\n {isButtonsRequired && (\n <div className=\"px-6 py-3 bg-gray-100 flex justify-end space-x-3 rounded-b-md border-t\">\n {onHide && (\n <button\n onClick={onHide}\n className=\"px-4 py-2 border bg-white rounded-md font-semibold text-[14px] hover:bg-gray-50 transition-colors\"\n >\n Cancel\n </button>\n )}\n <button\n onClick={handleConfirmation}\n disabled={isLoading}\n className={[\n \"px-4 py-2 text-white rounded-md text-[14px] font-semibold\",\n \"disabled:opacity-50 disabled:cursor-not-allowed transition-colors\",\n isWarning\n ? \"bg-red-600 hover:bg-red-700\"\n : \"bg-basePurple hover:bg-basePurple/80\",\n ].join(\" \")}\n >\n {isLoading ? (\n <span className=\"inline-flex items-center gap-2\">\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 {handleConfirmationBtnText}\n </span>\n ) : (\n handleConfirmationBtnText\n )}\n </button>\n </div>\n )}\n </div>\n </div>\n );\n}\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 CHANGED
@@ -1,5 +1,6 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import React, { useState } from 'react';
2
+ import React, { useId, useEffect, useState } from 'react';
3
+ import { useHotkeys } from 'react-hotkeys-hook';
3
4
 
4
5
  var __defProp = Object.defineProperty;
5
6
  var __defProps = Object.defineProperties;
@@ -33,7 +34,7 @@ var __objRest = (source, exclude) => {
33
34
  return target;
34
35
  };
35
36
  var variantClasses = {
36
- primary: "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500",
37
+ primary: "bg-basePurple text-white hover:bg-basePurple/80 focus:ring-basePurple/50",
37
38
  secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200 focus:ring-gray-400",
38
39
  danger: "bg-red-600 text-white hover:bg-red-700 focus:ring-red-500",
39
40
  ghost: "bg-transparent text-gray-700 hover:bg-gray-100 focus:ring-gray-300"
@@ -163,6 +164,155 @@ var Input = React.forwardRef(
163
164
  }
164
165
  );
165
166
  Input.displayName = "Input";
167
+
168
+ // src/utils/modalStack.ts
169
+ var stack = [];
170
+ function handlePushModal({ id }) {
171
+ if (!stack.find((m) => m.id === id)) {
172
+ stack.push({ id });
173
+ }
174
+ }
175
+ function handlePopModal({ id }) {
176
+ const idx = stack.findIndex((m) => m.id === id);
177
+ if (idx !== -1) stack.splice(idx, 1);
178
+ }
179
+ function handleIsTopModal({ id }) {
180
+ return stack.length > 0 && stack[stack.length - 1].id === id;
181
+ }
182
+ function Modal({
183
+ show,
184
+ title = "",
185
+ className,
186
+ children,
187
+ isLoading = false,
188
+ onHide,
189
+ isWarning = false,
190
+ isButtonsRequired = true,
191
+ handleConfirmation,
192
+ handleConfirmationBtnText = "Confirm"
193
+ }) {
194
+ const modalId = useId();
195
+ useEffect(() => {
196
+ if (show) handlePushModal({ id: modalId });
197
+ return () => handlePopModal({ id: modalId });
198
+ }, [show, modalId]);
199
+ useHotkeys(
200
+ "enter",
201
+ (e) => {
202
+ e.preventDefault();
203
+ if (show && handleIsTopModal({ id: modalId }) && handleConfirmation)
204
+ handleConfirmation();
205
+ },
206
+ { enabled: show && !isLoading }
207
+ );
208
+ useHotkeys(
209
+ "esc",
210
+ (e) => {
211
+ e.preventDefault();
212
+ if (show && handleIsTopModal({ id: modalId }) && onHide) onHide();
213
+ },
214
+ { enabled: show && !isLoading }
215
+ );
216
+ if (!show) return null;
217
+ return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-999 bg-gray-800/50 flex items-center justify-center", children: /* @__PURE__ */ jsxs(
218
+ "div",
219
+ {
220
+ className: [
221
+ "w-[95%] bg-white rounded-lg shadow-lg flex flex-col",
222
+ "md:w-[60%] lg:w-[30%] max-h-[95vh]",
223
+ className || ""
224
+ ].join(" "),
225
+ children: [
226
+ title && /* @__PURE__ */ jsxs("div", { className: "px-3.5 py-3 border-b border-gray-200 flex justify-between items-start gap-x-3", children: [
227
+ /* @__PURE__ */ jsxs("h2", { className: "text-[17px] font-semibold line-clamp-2 capitalize flex gap-x-2 items-center", children: [
228
+ isWarning && /* @__PURE__ */ jsx(
229
+ "svg",
230
+ {
231
+ className: "text-red-500 w-6 h-6 shrink-0",
232
+ viewBox: "0 0 24 24",
233
+ fill: "currentColor",
234
+ children: /* @__PURE__ */ jsx(
235
+ "path",
236
+ {
237
+ fillRule: "evenodd",
238
+ d: "M12 2a10 10 0 100 20A10 10 0 0012 2zm0 5a1 1 0 011 1v4a1 1 0 11-2 0V8a1 1 0 011-1zm0 8a1.25 1.25 0 110 2.5A1.25 1.25 0 0112 15z",
239
+ clipRule: "evenodd"
240
+ }
241
+ )
242
+ }
243
+ ),
244
+ title
245
+ ] }),
246
+ onHide && /* @__PURE__ */ jsx(
247
+ "button",
248
+ {
249
+ onClick: onHide,
250
+ className: "text-gray-400 hover:text-gray-600 transition-colors shrink-0",
251
+ "aria-label": "Close",
252
+ children: "\u2715"
253
+ }
254
+ )
255
+ ] }),
256
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto px-3.5 py-3", children }),
257
+ isButtonsRequired && /* @__PURE__ */ jsxs("div", { className: "px-6 py-3 bg-gray-100 flex justify-end space-x-3 rounded-b-md border-t", children: [
258
+ onHide && /* @__PURE__ */ jsx(
259
+ "button",
260
+ {
261
+ onClick: onHide,
262
+ className: "px-4 py-2 border bg-white rounded-md font-semibold text-[14px] hover:bg-gray-50 transition-colors",
263
+ children: "Cancel"
264
+ }
265
+ ),
266
+ /* @__PURE__ */ jsx(
267
+ "button",
268
+ {
269
+ onClick: handleConfirmation,
270
+ disabled: isLoading,
271
+ className: [
272
+ "px-4 py-2 text-white rounded-md text-[14px] font-semibold",
273
+ "disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
274
+ isWarning ? "bg-red-600 hover:bg-red-700" : "bg-basePurple hover:bg-basePurple/80"
275
+ ].join(" "),
276
+ children: isLoading ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
277
+ /* @__PURE__ */ jsxs(
278
+ "svg",
279
+ {
280
+ className: "animate-spin h-4 w-4",
281
+ xmlns: "http://www.w3.org/2000/svg",
282
+ fill: "none",
283
+ viewBox: "0 0 24 24",
284
+ children: [
285
+ /* @__PURE__ */ jsx(
286
+ "circle",
287
+ {
288
+ className: "opacity-25",
289
+ cx: "12",
290
+ cy: "12",
291
+ r: "10",
292
+ stroke: "currentColor",
293
+ strokeWidth: "4"
294
+ }
295
+ ),
296
+ /* @__PURE__ */ jsx(
297
+ "path",
298
+ {
299
+ className: "opacity-75",
300
+ fill: "currentColor",
301
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
302
+ }
303
+ )
304
+ ]
305
+ }
306
+ ),
307
+ handleConfirmationBtnText
308
+ ] }) : handleConfirmationBtnText
309
+ }
310
+ )
311
+ ] })
312
+ ]
313
+ }
314
+ ) });
315
+ }
166
316
  function useLocalStorage(key, initialValue) {
167
317
  const [storedValue, setStoredValue] = useState(() => {
168
318
  if (typeof window === "undefined") return initialValue;
@@ -202,6 +352,6 @@ function cn(...classes) {
202
352
  return classes.filter(Boolean).join(" ");
203
353
  }
204
354
 
205
- export { Badge, Button, Input, cn, useLocalStorage };
355
+ export { Badge, Button, Input, Modal, cn, useLocalStorage };
206
356
  //# sourceMappingURL=index.mjs.map
207
357
  //# sourceMappingURL=index.mjs.map
@@ -1 +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"]}
1
+ {"version":3,"sources":["../src/components/Button/Button.tsx","../src/components/Badge/Badge.tsx","../src/components/Input/Input.tsx","../src/utils/modalStack.ts","../src/components/Modal/Modal.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-basePurple text-white hover:bg-basePurple/80 focus:ring-basePurple/50\",\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","type ModalEntry = { id: string };\n\nconst stack: ModalEntry[] = [];\n\nexport function handlePushModal({ id }: ModalEntry) {\n if (!stack.find((m) => m.id === id)) {\n stack.push({ id });\n }\n}\n\nexport function handlePopModal({ id }: ModalEntry) {\n const idx = stack.findIndex((m) => m.id === id);\n if (idx !== -1) stack.splice(idx, 1);\n}\n\nexport function handleIsTopModal({ id }: ModalEntry): boolean {\n return stack.length > 0 && stack[stack.length - 1].id === id;\n}\n","import React, { useEffect, useId } from \"react\";\nimport { useHotkeys } from \"react-hotkeys-hook\";\nimport {\n handleIsTopModal,\n handlePopModal,\n handlePushModal,\n} from \"../../utils/modalStack\";\n\nexport interface ModalProps {\n show: boolean;\n title?: string;\n className?: string;\n children?: React.ReactNode;\n isLoading?: boolean;\n onHide?: () => void;\n isWarning?: boolean;\n isButtonsRequired?: boolean;\n handleConfirmation?: () => void;\n handleConfirmationBtnText?: string;\n}\n\nexport function Modal({\n show,\n title = \"\",\n className,\n children,\n isLoading = false,\n onHide,\n isWarning = false,\n isButtonsRequired = true,\n handleConfirmation,\n handleConfirmationBtnText = \"Confirm\",\n}: ModalProps) {\n const modalId = useId();\n\n useEffect(() => {\n if (show) handlePushModal({ id: modalId });\n return () => handlePopModal({ id: modalId });\n }, [show, modalId]);\n\n useHotkeys(\n \"enter\",\n (e) => {\n e.preventDefault();\n if (show && handleIsTopModal({ id: modalId }) && handleConfirmation)\n handleConfirmation();\n },\n { enabled: show && !isLoading }\n );\n\n useHotkeys(\n \"esc\",\n (e) => {\n e.preventDefault();\n if (show && handleIsTopModal({ id: modalId }) && onHide) onHide();\n },\n { enabled: show && !isLoading }\n );\n\n if (!show) return null;\n\n return (\n <div className=\"fixed inset-0 z-999 bg-gray-800/50 flex items-center justify-center\">\n <div\n className={[\n \"w-[95%] bg-white rounded-lg shadow-lg flex flex-col\",\n \"md:w-[60%] lg:w-[30%] max-h-[95vh]\",\n className || \"\",\n ].join(\" \")}\n >\n {/* Header */}\n {title && (\n <div className=\"px-3.5 py-3 border-b border-gray-200 flex justify-between items-start gap-x-3\">\n <h2 className=\"text-[17px] font-semibold line-clamp-2 capitalize flex gap-x-2 items-center\">\n {isWarning && (\n <svg\n className=\"text-red-500 w-6 h-6 shrink-0\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M12 2a10 10 0 100 20A10 10 0 0012 2zm0 5a1 1 0 011 1v4a1 1 0 11-2 0V8a1 1 0 011-1zm0 8a1.25 1.25 0 110 2.5A1.25 1.25 0 0112 15z\"\n clipRule=\"evenodd\"\n />\n </svg>\n )}\n {title}\n </h2>\n {onHide && (\n <button\n onClick={onHide}\n className=\"text-gray-400 hover:text-gray-600 transition-colors shrink-0\"\n aria-label=\"Close\"\n >\n ✕\n </button>\n )}\n </div>\n )}\n\n {/* Body */}\n <div className=\"flex-1 overflow-y-auto px-3.5 py-3\">{children}</div>\n\n {/* Footer */}\n {isButtonsRequired && (\n <div className=\"px-6 py-3 bg-gray-100 flex justify-end space-x-3 rounded-b-md border-t\">\n {onHide && (\n <button\n onClick={onHide}\n className=\"px-4 py-2 border bg-white rounded-md font-semibold text-[14px] hover:bg-gray-50 transition-colors\"\n >\n Cancel\n </button>\n )}\n <button\n onClick={handleConfirmation}\n disabled={isLoading}\n className={[\n \"px-4 py-2 text-white rounded-md text-[14px] font-semibold\",\n \"disabled:opacity-50 disabled:cursor-not-allowed transition-colors\",\n isWarning\n ? \"bg-red-600 hover:bg-red-700\"\n : \"bg-basePurple hover:bg-basePurple/80\",\n ].join(\" \")}\n >\n {isLoading ? (\n <span className=\"inline-flex items-center gap-2\">\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 {handleConfirmationBtnText}\n </span>\n ) : (\n handleConfirmationBtnText\n )}\n </button>\n </div>\n )}\n </div>\n </div>\n );\n}\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/styles.css CHANGED
@@ -1,2 +1,2 @@
1
1
  /*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-100:oklch(93.6% .032 17.717);--color-red-300:oklch(80.8% .114 19.571);--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-800:oklch(47.6% .114 61.907);--color-green-100:oklch(96.2% .044 156.743);--color-green-800:oklch(44.8% .119 151.328);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-200:oklch(88.2% .059 254.128);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-blue-800:oklch(42.4% .199 265.638);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--font-weight-medium:500;--radius-md:.375rem;--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.static{position:static}.block{display:block}.contents{display:contents}.flex{display:flex}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-4{height:calc(var(--spacing) * 4)}.w-4{width:calc(var(--spacing) * 4)}.w-full{width:100%}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-spin{animation:var(--animate-spin)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.rounded-full{border-radius:3.40282e38px}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-gray-300{border-color:var(--color-gray-300)}.border-red-400{border-color:var(--color-red-400)}.bg-blue-100{background-color:var(--color-blue-100)}.bg-blue-600{background-color:var(--color-blue-600)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-green-100{background-color:var(--color-green-100)}.bg-red-100{background-color:var(--color-red-100)}.bg-red-600{background-color:var(--color-red-600)}.bg-transparent{background-color:#0000}.bg-yellow-100{background-color:var(--color-yellow-100)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.text-blue-800{color:var(--color-blue-800)}.text-gray-500{color:var(--color-gray-500)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-green-800{color:var(--color-green-800)}.text-red-600{color:var(--color-red-600)}.text-red-800{color:var(--color-red-800)}.text-white{color:var(--color-white)}.text-yellow-800{color:var(--color-yellow-800)}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.placeholder\:text-gray-400::placeholder{color:var(--color-gray-400)}@media (hover:hover){.hover\:bg-blue-700:hover{background-color:var(--color-blue-700)}.hover\:bg-gray-100:hover{background-color:var(--color-gray-100)}.hover\:bg-gray-200:hover{background-color:var(--color-gray-200)}.hover\:bg-red-700:hover{background-color:var(--color-red-700)}}.focus\:border-blue-500:focus{border-color:var(--color-blue-500)}.focus\:border-red-500:focus{border-color:var(--color-red-500)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-blue-200:focus{--tw-ring-color:var(--color-blue-200)}.focus\:ring-blue-500:focus{--tw-ring-color:var(--color-blue-500)}.focus\:ring-gray-300:focus{--tw-ring-color:var(--color-gray-300)}.focus\:ring-gray-400:focus{--tw-ring-color:var(--color-gray-400)}.focus\:ring-red-300:focus{--tw-ring-color:var(--color-red-300)}.focus\:ring-red-500:focus{--tw-ring-color:var(--color-red-500)}.focus\:ring-offset-0:focus{--tw-ring-offset-width:0px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-gray-50:disabled{background-color:var(--color-gray-50)}.disabled\:text-gray-500:disabled{color:var(--color-gray-500)}.disabled\:opacity-50:disabled{opacity:.5}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-duration{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-x-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-100:oklch(93.6% .032 17.717);--color-red-300:oklch(80.8% .114 19.571);--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-800:oklch(47.6% .114 61.907);--color-green-100:oklch(96.2% .044 156.743);--color-green-800:oklch(44.8% .119 151.328);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-200:oklch(88.2% .059 254.128);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-800:oklch(42.4% .199 265.638);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--font-weight-medium:500;--font-weight-semibold:600;--radius-md:.375rem;--radius-lg:.5rem;--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-basePurple:#534f8f}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.fixed{position:fixed}.static{position:static}.inset-0{inset:calc(var(--spacing) * 0)}.z-999{z-index:999}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.max-h-\[95vh\]{max-height:95vh}.w-4{width:calc(var(--spacing) * 4)}.w-6{width:calc(var(--spacing) * 6)}.w-\[95\%\]{width:95%}.w-full{width:100%}.flex-1{flex:1}.shrink-0{flex-shrink:0}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-spin{animation:var(--animate-spin)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}:where(.space-x-3>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing) * 3) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-x-reverse)))}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-b-md{border-bottom-right-radius:var(--radius-md);border-bottom-left-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-300{border-color:var(--color-gray-300)}.border-red-400{border-color:var(--color-red-400)}.bg-basePurple{background-color:var(--color-basePurple)}.bg-blue-100{background-color:var(--color-blue-100)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-800\/50{background-color:#1e293980}@supports (color:color-mix(in lab, red, red)){.bg-gray-800\/50{background-color:color-mix(in oklab, var(--color-gray-800) 50%, transparent)}}.bg-green-100{background-color:var(--color-green-100)}.bg-red-100{background-color:var(--color-red-100)}.bg-red-600{background-color:var(--color-red-600)}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.bg-yellow-100{background-color:var(--color-yellow-100)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[14px\]{font-size:14px}.text-\[17px\]{font-size:17px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.text-blue-800{color:var(--color-blue-800)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-green-800{color:var(--color-green-800)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-red-800{color:var(--color-red-800)}.text-white{color:var(--color-white)}.text-yellow-800{color:var(--color-yellow-800)}.capitalize{text-transform:capitalize}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.placeholder\:text-gray-400::placeholder{color:var(--color-gray-400)}@media (hover:hover){.hover\:bg-basePurple\/80:hover{background-color:#534f8fcc}@supports (color:color-mix(in lab, red, red)){.hover\:bg-basePurple\/80:hover{background-color:color-mix(in oklab, var(--color-basePurple) 80%, transparent)}}.hover\:bg-gray-50:hover{background-color:var(--color-gray-50)}.hover\:bg-gray-100:hover{background-color:var(--color-gray-100)}.hover\:bg-gray-200:hover{background-color:var(--color-gray-200)}.hover\:bg-red-700:hover{background-color:var(--color-red-700)}.hover\:text-gray-600:hover{color:var(--color-gray-600)}}.focus\:border-blue-500:focus{border-color:var(--color-blue-500)}.focus\:border-red-500:focus{border-color:var(--color-red-500)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-basePurple\/50:focus{--tw-ring-color:#534f8f80}@supports (color:color-mix(in lab, red, red)){.focus\:ring-basePurple\/50:focus{--tw-ring-color:color-mix(in oklab, var(--color-basePurple) 50%, transparent)}}.focus\:ring-blue-200:focus{--tw-ring-color:var(--color-blue-200)}.focus\:ring-gray-300:focus{--tw-ring-color:var(--color-gray-300)}.focus\:ring-gray-400:focus{--tw-ring-color:var(--color-gray-400)}.focus\:ring-red-300:focus{--tw-ring-color:var(--color-red-300)}.focus\:ring-red-500:focus{--tw-ring-color:var(--color-red-500)}.focus\:ring-offset-0:focus{--tw-ring-offset-width:0px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-gray-50:disabled{background-color:var(--color-gray-50)}.disabled\:text-gray-500:disabled{color:var(--color-gray-500)}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:48rem){.md\:w-\[60\%\]{width:60%}}@media (min-width:64rem){.lg\:w-\[30\%\]{width:30%}}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-duration{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seekho/ui",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Seekho internal UI component library",
5
5
  "keywords": [
6
6
  "seekho",
@@ -42,7 +42,8 @@
42
42
  },
43
43
  "peerDependencies": {
44
44
  "react": ">=17",
45
- "react-dom": ">=17"
45
+ "react-dom": ">=17",
46
+ "react-hotkeys-hook": ">=4"
46
47
  },
47
48
  "devDependencies": {
48
49
  "@chromatic-com/storybook": "^5.1.1",
@@ -52,6 +53,7 @@
52
53
  "@storybook/addon-vitest": "^10.3.3",
53
54
  "@storybook/react-vite": "^10.3.3",
54
55
  "@tailwindcss/cli": "^4.2.2",
56
+ "@tailwindcss/vite": "^4.2.2",
55
57
  "@types/react": "^19.2.14",
56
58
  "@types/react-dom": "^19.2.3",
57
59
  "@vitest/browser-playwright": "^4.1.2",
@@ -61,6 +63,7 @@
61
63
  "postcss": "^8.5.8",
62
64
  "react": "^19.2.4",
63
65
  "react-dom": "^19.2.4",
66
+ "react-hotkeys-hook": "^5.2.4",
64
67
  "storybook": "^10.3.3",
65
68
  "tailwindcss": "^4.2.2",
66
69
  "tsup": "^8.5.1",
package/readme.md CHANGED
@@ -116,3 +116,4 @@ seekho-ui/
116
116
  ├── tsup.config.ts # Build config
117
117
  └── tailwind.config.js # Tailwind (for Storybook)
118
118
  ```
119
+ # seekho-ui