@mohasinac/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.cjs ADDED
@@ -0,0 +1,2440 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __defProps = Object.defineProperties;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
9
+ var __getProtoOf = Object.getPrototypeOf;
10
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
11
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
12
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
+ var __spreadValues = (a, b) => {
14
+ for (var prop in b || (b = {}))
15
+ if (__hasOwnProp.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ if (__getOwnPropSymbols)
18
+ for (var prop of __getOwnPropSymbols(b)) {
19
+ if (__propIsEnum.call(b, prop))
20
+ __defNormalProp(a, prop, b[prop]);
21
+ }
22
+ return a;
23
+ };
24
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
+ var __objRest = (source, exclude) => {
26
+ var target = {};
27
+ for (var prop in source)
28
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
29
+ target[prop] = source[prop];
30
+ if (source != null && __getOwnPropSymbols)
31
+ for (var prop of __getOwnPropSymbols(source)) {
32
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
33
+ target[prop] = source[prop];
34
+ }
35
+ return target;
36
+ };
37
+ var __export = (target, all) => {
38
+ for (var name in all)
39
+ __defProp(target, name, { get: all[name], enumerable: true });
40
+ };
41
+ var __copyProps = (to, from, except, desc) => {
42
+ if (from && typeof from === "object" || typeof from === "function") {
43
+ for (let key of __getOwnPropNames(from))
44
+ if (!__hasOwnProp.call(to, key) && key !== except)
45
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
46
+ }
47
+ return to;
48
+ };
49
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
50
+ // If the importer is in node compatibility mode or this is not an ESM
51
+ // file that has been converted to a CommonJS file using a Babel-
52
+ // compatible transform (i.e. "__esModule" has not been set), then set
53
+ // "default" to the CommonJS "module.exports" for node compatibility.
54
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
55
+ mod
56
+ ));
57
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
58
+
59
+ // src/index.ts
60
+ var index_exports = {};
61
+ __export(index_exports, {
62
+ Alert: () => Alert,
63
+ Article: () => Article,
64
+ Aside: () => Aside,
65
+ Badge: () => Badge,
66
+ BlockFooter: () => BlockFooter,
67
+ BlockHeader: () => BlockHeader,
68
+ Breadcrumb: () => Breadcrumb,
69
+ Button: () => Button,
70
+ Caption: () => Caption,
71
+ Container: () => Container,
72
+ DEFAULT_PAGINATION_CONFIG: () => import_contracts3.DEFAULT_PAGINATION_CONFIG,
73
+ DEFAULT_STICKY_CONFIG: () => import_contracts3.DEFAULT_STICKY_CONFIG,
74
+ DEFAULT_TABLE_CONFIG: () => import_contracts3.DEFAULT_TABLE_CONFIG,
75
+ DataTable: () => DataTable,
76
+ Divider: () => Divider,
77
+ Drawer: () => Drawer,
78
+ GRID_MAP: () => GRID_MAP,
79
+ Grid: () => Grid,
80
+ Heading: () => Heading,
81
+ ImageLightbox: () => ImageLightbox,
82
+ IndeterminateProgress: () => IndeterminateProgress,
83
+ Label: () => Label,
84
+ Li: () => Li,
85
+ Main: () => Main,
86
+ Modal: () => Modal,
87
+ Nav: () => Nav,
88
+ Ol: () => Ol,
89
+ Pagination: () => Pagination,
90
+ Progress: () => Progress,
91
+ Row: () => Row,
92
+ Section: () => Section,
93
+ Select: () => Select,
94
+ Skeleton: () => Skeleton,
95
+ Span: () => Span,
96
+ Spinner: () => Spinner,
97
+ Stack: () => Stack,
98
+ StarRating: () => StarRating,
99
+ StatusBadge: () => StatusBadge,
100
+ Text: () => Text,
101
+ Ul: () => Ul,
102
+ mergeTableConfig: () => import_contracts3.mergeTableConfig
103
+ });
104
+ module.exports = __toCommonJS(index_exports);
105
+
106
+ // src/components/Semantic.tsx
107
+ var import_react = __toESM(require("react"), 1);
108
+ var import_jsx_runtime = require("react/jsx-runtime");
109
+ var Section = import_react.default.forwardRef(
110
+ (_a, ref) => {
111
+ var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
112
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", __spreadProps(__spreadValues({ className, ref }, props), { children }));
113
+ }
114
+ );
115
+ Section.displayName = "Section";
116
+ function Article(_a) {
117
+ var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
118
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("article", __spreadProps(__spreadValues({ className }, props), { children }));
119
+ }
120
+ function Main(_a) {
121
+ var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
122
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("main", __spreadProps(__spreadValues({ className }, props), { children }));
123
+ }
124
+ var Aside = import_react.default.forwardRef(
125
+ (_a, ref) => {
126
+ var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
127
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("aside", __spreadProps(__spreadValues({ className, ref }, props), { children }));
128
+ }
129
+ );
130
+ Aside.displayName = "Aside";
131
+ function Nav(_a) {
132
+ var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
133
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("nav", __spreadProps(__spreadValues({ className }, props), { children }));
134
+ }
135
+ function BlockHeader(_a) {
136
+ var _b = _a, {
137
+ className = "",
138
+ children
139
+ } = _b, props = __objRest(_b, [
140
+ "className",
141
+ "children"
142
+ ]);
143
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("header", __spreadProps(__spreadValues({ className }, props), { children }));
144
+ }
145
+ function BlockFooter(_a) {
146
+ var _b = _a, {
147
+ className = "",
148
+ children
149
+ } = _b, props = __objRest(_b, [
150
+ "className",
151
+ "children"
152
+ ]);
153
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("footer", __spreadProps(__spreadValues({ className }, props), { children }));
154
+ }
155
+ function Ul(_a) {
156
+ var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
157
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", __spreadProps(__spreadValues({ className }, props), { children }));
158
+ }
159
+ function Ol(_a) {
160
+ var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
161
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", __spreadProps(__spreadValues({ className }, props), { children }));
162
+ }
163
+ function Li(_a) {
164
+ var _b = _a, { className = "", children } = _b, props = __objRest(_b, ["className", "children"]);
165
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", __spreadProps(__spreadValues({ className }, props), { children }));
166
+ }
167
+
168
+ // src/components/Typography.tsx
169
+ var import_jsx_runtime2 = require("react/jsx-runtime");
170
+ var UI_THEME = {
171
+ typography: {
172
+ h1: "text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight font-display",
173
+ h2: "text-2xl md:text-3xl lg:text-4xl font-bold tracking-tight font-display",
174
+ h3: "text-xl md:text-2xl lg:text-3xl font-bold tracking-tight font-display",
175
+ h4: "text-lg md:text-xl lg:text-2xl font-bold font-display",
176
+ h5: "text-base md:text-lg lg:text-xl font-medium",
177
+ h6: "text-sm md:text-base lg:text-lg font-medium",
178
+ body: "text-base lg:text-lg",
179
+ small: "text-sm lg:text-base",
180
+ xs: "text-xs lg:text-sm"
181
+ },
182
+ themed: {
183
+ textPrimary: "text-zinc-900 dark:text-zinc-50",
184
+ textSecondary: "text-zinc-500 dark:text-zinc-400",
185
+ textMuted: "text-zinc-400 dark:text-zinc-500",
186
+ textError: "text-red-600 dark:text-red-400",
187
+ textSuccess: "text-emerald-600 dark:text-emerald-400"
188
+ },
189
+ colors: {
190
+ form: {
191
+ required: "text-red-500"
192
+ }
193
+ }
194
+ };
195
+ function Heading(_a) {
196
+ var _b = _a, {
197
+ level = 1,
198
+ variant = "primary",
199
+ className = "",
200
+ children
201
+ } = _b, props = __objRest(_b, [
202
+ "level",
203
+ "variant",
204
+ "className",
205
+ "children"
206
+ ]);
207
+ const Tag = `h${level}`;
208
+ const { typography, themed } = UI_THEME;
209
+ const sizeClasses = {
210
+ 1: typography.h1,
211
+ 2: typography.h2,
212
+ 3: typography.h3,
213
+ 4: typography.h4,
214
+ 5: typography.h5,
215
+ 6: typography.h6
216
+ };
217
+ const variantClasses = {
218
+ primary: themed.textPrimary,
219
+ secondary: themed.textSecondary,
220
+ muted: themed.textMuted,
221
+ none: ""
222
+ };
223
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
224
+ Tag,
225
+ __spreadProps(__spreadValues({
226
+ className: `${sizeClasses[level]} ${variantClasses[variant]} ${className}`
227
+ }, props), {
228
+ children
229
+ })
230
+ );
231
+ }
232
+ function Text(_a) {
233
+ var _b = _a, {
234
+ variant = "primary",
235
+ size = "base",
236
+ weight = "normal",
237
+ className = "",
238
+ children
239
+ } = _b, props = __objRest(_b, [
240
+ "variant",
241
+ "size",
242
+ "weight",
243
+ "className",
244
+ "children"
245
+ ]);
246
+ const { typography, themed } = UI_THEME;
247
+ const sizeClasses = {
248
+ xs: typography.xs,
249
+ sm: typography.small,
250
+ base: typography.body,
251
+ lg: "text-lg",
252
+ xl: "text-xl"
253
+ };
254
+ const weightClasses = {
255
+ normal: "font-normal",
256
+ medium: "font-medium",
257
+ semibold: "font-semibold",
258
+ bold: "font-bold"
259
+ };
260
+ const variantClasses = {
261
+ primary: themed.textPrimary,
262
+ secondary: themed.textSecondary,
263
+ muted: themed.textMuted,
264
+ error: themed.textError,
265
+ success: themed.textSuccess,
266
+ none: ""
267
+ };
268
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
269
+ "p",
270
+ __spreadProps(__spreadValues({
271
+ className: `${sizeClasses[size]} ${weightClasses[weight]} ${variantClasses[variant]} ${className}`
272
+ }, props), {
273
+ children
274
+ })
275
+ );
276
+ }
277
+ function Label(_a) {
278
+ var _b = _a, {
279
+ required,
280
+ className = "",
281
+ children
282
+ } = _b, props = __objRest(_b, [
283
+ "required",
284
+ "className",
285
+ "children"
286
+ ]);
287
+ const { themed, typography, colors } = UI_THEME;
288
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
289
+ "label",
290
+ __spreadProps(__spreadValues({
291
+ className: `block ${typography.small} font-medium ${themed.textSecondary} mb-1.5 ${className}`
292
+ }, props), {
293
+ children: [
294
+ children,
295
+ required && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `${colors.form.required} ml-1`, children: "*" })
296
+ ]
297
+ })
298
+ );
299
+ }
300
+ function Caption(_a) {
301
+ var _b = _a, {
302
+ variant = "default",
303
+ className = "",
304
+ children
305
+ } = _b, props = __objRest(_b, [
306
+ "variant",
307
+ "className",
308
+ "children"
309
+ ]);
310
+ const { themed, typography } = UI_THEME;
311
+ const variantClasses = {
312
+ default: themed.textMuted,
313
+ accent: "text-primary font-semibold",
314
+ inverse: "text-primary/40"
315
+ };
316
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
317
+ "span",
318
+ __spreadProps(__spreadValues({
319
+ className: `${typography.xs} ${variantClasses[variant]} ${className}`
320
+ }, props), {
321
+ children
322
+ })
323
+ );
324
+ }
325
+ function Span(_a) {
326
+ var _b = _a, {
327
+ variant = "inherit",
328
+ size,
329
+ weight,
330
+ className = "",
331
+ children
332
+ } = _b, props = __objRest(_b, [
333
+ "variant",
334
+ "size",
335
+ "weight",
336
+ "className",
337
+ "children"
338
+ ]);
339
+ const { themed, typography } = UI_THEME;
340
+ const variantClasses = {
341
+ inherit: "",
342
+ primary: themed.textPrimary,
343
+ secondary: themed.textSecondary,
344
+ muted: themed.textMuted,
345
+ error: themed.textError,
346
+ success: themed.textSuccess,
347
+ accent: "text-primary"
348
+ };
349
+ const sizeClasses = {
350
+ xs: typography.xs,
351
+ sm: typography.small,
352
+ base: typography.body,
353
+ lg: "text-lg",
354
+ xl: "text-xl"
355
+ };
356
+ const weightClasses = {
357
+ normal: "font-normal",
358
+ medium: "font-medium",
359
+ semibold: "font-semibold",
360
+ bold: "font-bold"
361
+ };
362
+ const classes = [
363
+ size ? sizeClasses[size] : "",
364
+ weight ? weightClasses[weight] : "",
365
+ variantClasses[variant],
366
+ className
367
+ ].filter(Boolean).join(" ");
368
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", __spreadProps(__spreadValues({ className: classes }, props), { children }));
369
+ }
370
+
371
+ // src/components/Spinner.tsx
372
+ var import_jsx_runtime3 = require("react/jsx-runtime");
373
+ function Spinner({
374
+ size = "md",
375
+ variant = "primary",
376
+ className = "",
377
+ label = "Loading..."
378
+ }) {
379
+ const sizeClasses = {
380
+ sm: "w-4 h-4 border-2",
381
+ md: "w-8 h-8 border-2",
382
+ lg: "w-12 h-12 border-[3px]",
383
+ xl: "w-16 h-16 border-4"
384
+ };
385
+ const variantClasses = {
386
+ primary: "border-primary-600 border-t-transparent dark:border-secondary-500 dark:border-t-transparent",
387
+ white: "border-white border-t-transparent",
388
+ current: "border-current border-t-transparent"
389
+ };
390
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
391
+ "div",
392
+ {
393
+ className: `inline-flex items-center gap-3 ${className}`,
394
+ role: "status",
395
+ "aria-label": label,
396
+ children: [
397
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
398
+ "div",
399
+ {
400
+ className: `${sizeClasses[size]} ${variantClasses[variant]} rounded-full animate-spin`
401
+ }
402
+ ),
403
+ label && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "sr-only", children: label })
404
+ ]
405
+ }
406
+ );
407
+ }
408
+
409
+ // src/components/Skeleton.tsx
410
+ var import_jsx_runtime4 = require("react/jsx-runtime");
411
+ var BG_TERTIARY = "bg-zinc-100 dark:bg-slate-800";
412
+ var WAVE_CSS = `
413
+ @keyframes lir-skeleton-wave {
414
+ 0% { transform: translateX(-100%); }
415
+ 50%, 100% { transform: translateX(100%); }
416
+ }
417
+ .lir-skeleton-wave {
418
+ position: relative;
419
+ overflow: hidden;
420
+ }
421
+ .lir-skeleton-wave::after {
422
+ content: "";
423
+ position: absolute;
424
+ top: 0; left: 0; right: 0; bottom: 0;
425
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.5), transparent);
426
+ animation: lir-skeleton-wave 1.5s infinite;
427
+ }
428
+ `;
429
+ function Skeleton({
430
+ variant = "text",
431
+ width,
432
+ height,
433
+ className = "",
434
+ animation = "pulse"
435
+ }) {
436
+ const variantClass = variant === "circular" ? "rounded-full" : "rounded";
437
+ const defaultSize = {
438
+ circular: { width: "40px", height: "40px" },
439
+ rectangular: { width: "100%", height: "140px" },
440
+ text: { width: "100%", height: "1em" }
441
+ }[variant];
442
+ const animationClass = {
443
+ pulse: "animate-pulse",
444
+ wave: "lir-skeleton-wave",
445
+ none: ""
446
+ }[animation];
447
+ const style = {
448
+ width: width != null ? width : defaultSize.width,
449
+ height: height != null ? height : defaultSize.height
450
+ };
451
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
452
+ animation === "wave" && // eslint-disable-next-line react/no-danger
453
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { dangerouslySetInnerHTML: { __html: WAVE_CSS } }),
454
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
455
+ "div",
456
+ {
457
+ className: `${BG_TERTIARY} ${variantClass} ${animationClass} ${className}`,
458
+ style,
459
+ role: "status",
460
+ "aria-label": "Loading",
461
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "sr-only", children: "Loading..." })
462
+ }
463
+ )
464
+ ] });
465
+ }
466
+
467
+ // src/components/Button.tsx
468
+ var import_tailwind_merge = require("tailwind-merge");
469
+ var import_lucide_react = require("lucide-react");
470
+ var import_jsx_runtime5 = require("react/jsx-runtime");
471
+ var UI_BUTTON = {
472
+ base: "inline-flex items-center justify-center font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed",
473
+ active: "active:scale-95",
474
+ variants: {
475
+ primary: "bg-primary-600 text-white hover:bg-primary-700 active:bg-primary-800 shadow-sm focus:ring-primary-500/30 dark:bg-secondary-500 dark:text-white dark:hover:bg-secondary-400 dark:active:bg-secondary-600 dark:focus:ring-secondary-400/30",
476
+ secondary: "bg-primary-700 text-white hover:bg-primary-600 active:bg-primary-800 shadow-md focus:ring-primary-500 dark:bg-secondary-700 dark:text-white dark:hover:bg-secondary-600 dark:active:bg-secondary-800 dark:focus:ring-secondary-500",
477
+ outline: "border border-zinc-200 dark:border-slate-700 bg-white dark:bg-transparent text-zinc-900 dark:text-zinc-100 hover:bg-zinc-50 dark:hover:bg-slate-800 focus:ring-zinc-400",
478
+ ghost: "text-zinc-700 dark:text-zinc-300 hover:bg-zinc-100 dark:hover:bg-slate-800 focus:ring-zinc-400",
479
+ danger: "bg-red-600 text-white hover:bg-red-500 active:bg-red-700 shadow-sm shadow-red-600/10 focus:ring-red-500",
480
+ warning: "bg-amber-500 text-white hover:bg-amber-400 active:bg-amber-600 shadow-sm shadow-amber-500/10 focus:ring-amber-500"
481
+ },
482
+ sizes: {
483
+ sm: "px-2.5 py-1.5 text-xs sm:px-3 sm:text-sm gap-1.5 min-h-[36px]",
484
+ md: "px-3 py-2 text-sm sm:px-4 sm:py-2.5 sm:text-base gap-2 min-h-[44px]",
485
+ lg: "px-4 py-2.5 text-base sm:px-6 sm:py-3 sm:text-lg gap-2.5 min-h-[44px]"
486
+ }
487
+ };
488
+ function Button(_a) {
489
+ var _b = _a, {
490
+ variant = "primary",
491
+ size = "md",
492
+ className = "",
493
+ isLoading = false,
494
+ disabled,
495
+ children
496
+ } = _b, props = __objRest(_b, [
497
+ "variant",
498
+ "size",
499
+ "className",
500
+ "isLoading",
501
+ "disabled",
502
+ "children"
503
+ ]);
504
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
505
+ "button",
506
+ __spreadProps(__spreadValues({
507
+ className: (0, import_tailwind_merge.twMerge)(
508
+ UI_BUTTON.base,
509
+ UI_BUTTON.active,
510
+ UI_BUTTON.variants[variant],
511
+ UI_BUTTON.sizes[size],
512
+ className
513
+ ),
514
+ disabled: disabled || isLoading,
515
+ "aria-busy": isLoading || void 0
516
+ }, props), {
517
+ children: [
518
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
519
+ import_lucide_react.Loader2,
520
+ {
521
+ className: "w-4 h-4 animate-spin flex-shrink-0",
522
+ "aria-hidden": "true"
523
+ }
524
+ ),
525
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "opacity-70", children }) : children
526
+ ]
527
+ })
528
+ );
529
+ }
530
+
531
+ // src/components/Badge.tsx
532
+ var import_jsx_runtime6 = require("react/jsx-runtime");
533
+ var BADGE_CLASSES = {
534
+ // Status badges
535
+ active: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-emerald-50 text-emerald-700 ring-1 ring-emerald-600/20 dark:bg-emerald-900/30 dark:text-emerald-300 dark:ring-emerald-400/20",
536
+ inactive: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-zinc-100 text-zinc-600 ring-1 ring-zinc-500/10 dark:bg-slate-800 dark:text-zinc-400 dark:ring-zinc-400/20",
537
+ pending: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-amber-50 text-amber-700 ring-1 ring-amber-600/20 dark:bg-amber-900/30 dark:text-amber-300 dark:ring-amber-400/20",
538
+ approved: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-emerald-50 text-emerald-700 ring-1 ring-emerald-600/20 dark:bg-emerald-900/30 dark:text-emerald-300 dark:ring-emerald-400/20",
539
+ rejected: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-rose-50 text-rose-700 ring-1 ring-rose-600/20 dark:bg-rose-900/30 dark:text-rose-300 dark:ring-rose-400/20",
540
+ // Semantic badges
541
+ success: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-emerald-50 text-emerald-700 ring-1 ring-emerald-600/20 dark:bg-emerald-900/30 dark:text-emerald-300 dark:ring-emerald-400/20",
542
+ warning: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-amber-50 text-amber-700 ring-1 ring-amber-600/20 dark:bg-amber-900/30 dark:text-amber-300 dark:ring-amber-400/20",
543
+ danger: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-rose-50 text-rose-700 ring-1 ring-rose-600/20 dark:bg-rose-900/30 dark:text-rose-300 dark:ring-rose-400/20",
544
+ info: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-sky-50 text-sky-700 ring-1 ring-sky-600/20 dark:bg-sky-900/30 dark:text-sky-300 dark:ring-sky-400/20",
545
+ // Role badges
546
+ admin: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-purple-50 text-purple-700 ring-1 ring-purple-600/20 dark:bg-purple-900/30 dark:text-purple-300 dark:ring-purple-400/20",
547
+ moderator: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-sky-50 text-sky-700 ring-1 ring-sky-600/20 dark:bg-sky-900/30 dark:text-sky-300 dark:ring-sky-400/20",
548
+ seller: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-teal-50 text-teal-700 ring-1 ring-teal-600/20 dark:bg-teal-900/30 dark:text-teal-300 dark:ring-teal-400/20",
549
+ user: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-zinc-100 text-zinc-700 ring-1 ring-zinc-500/10 dark:bg-slate-800 dark:text-zinc-300 dark:ring-zinc-400/20",
550
+ // Legacy / generic variants
551
+ default: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-zinc-100 text-zinc-700 ring-1 ring-zinc-500/10 dark:bg-slate-800 dark:text-zinc-300 dark:ring-zinc-400/20",
552
+ primary: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-primary-100 text-primary-700 dark:bg-primary-900/50 dark:text-primary-300",
553
+ secondary: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-primary-100 text-primary-700 dark:bg-primary-900/50 dark:text-primary-300"
554
+ };
555
+ function Badge({
556
+ children,
557
+ variant = "default",
558
+ className = ""
559
+ }) {
560
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Span, { className: `${BADGE_CLASSES[variant]} ${className}`, children });
561
+ }
562
+
563
+ // src/components/Alert.tsx
564
+ var import_jsx_runtime7 = require("react/jsx-runtime");
565
+ var ALERT_STYLES = {
566
+ info: {
567
+ container: "bg-sky-50 border-sky-200/80 dark:bg-sky-950/30 dark:border-sky-800/50",
568
+ icon: "text-sky-600 dark:text-sky-400",
569
+ title: "text-sky-900 dark:text-sky-200",
570
+ text: "text-sky-800 dark:text-sky-300"
571
+ },
572
+ success: {
573
+ container: "bg-emerald-50 border-emerald-200/80 dark:bg-emerald-950/30 dark:border-emerald-800/50",
574
+ icon: "text-emerald-600 dark:text-emerald-400",
575
+ title: "text-emerald-900 dark:text-emerald-200",
576
+ text: "text-emerald-800 dark:text-emerald-300"
577
+ },
578
+ warning: {
579
+ container: "bg-amber-50 border-amber-200/80 dark:bg-amber-950/30 dark:border-amber-800/50",
580
+ icon: "text-amber-600 dark:text-amber-400",
581
+ title: "text-amber-900 dark:text-amber-200",
582
+ text: "text-amber-800 dark:text-amber-300"
583
+ },
584
+ error: {
585
+ container: "bg-red-50 border-red-200/80 dark:bg-red-950/30 dark:border-red-800/50",
586
+ icon: "text-red-600 dark:text-red-400",
587
+ title: "text-red-900 dark:text-red-200",
588
+ text: "text-red-800 dark:text-red-300"
589
+ }
590
+ };
591
+ var ALERT_CLOSE_HOVER = "hover:bg-black/5 dark:hover:bg-white/5";
592
+ var ICONS = {
593
+ info: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
594
+ "svg",
595
+ {
596
+ className: "w-5 h-5",
597
+ fill: "currentColor",
598
+ viewBox: "0 0 20 20",
599
+ "aria-hidden": "true",
600
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
601
+ "path",
602
+ {
603
+ fillRule: "evenodd",
604
+ d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z",
605
+ clipRule: "evenodd"
606
+ }
607
+ )
608
+ }
609
+ ),
610
+ success: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
611
+ "svg",
612
+ {
613
+ className: "w-5 h-5",
614
+ fill: "currentColor",
615
+ viewBox: "0 0 20 20",
616
+ "aria-hidden": "true",
617
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
618
+ "path",
619
+ {
620
+ fillRule: "evenodd",
621
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",
622
+ clipRule: "evenodd"
623
+ }
624
+ )
625
+ }
626
+ ),
627
+ warning: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
628
+ "svg",
629
+ {
630
+ className: "w-5 h-5",
631
+ fill: "currentColor",
632
+ viewBox: "0 0 20 20",
633
+ "aria-hidden": "true",
634
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
635
+ "path",
636
+ {
637
+ fillRule: "evenodd",
638
+ d: "M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z",
639
+ clipRule: "evenodd"
640
+ }
641
+ )
642
+ }
643
+ ),
644
+ error: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
645
+ "svg",
646
+ {
647
+ className: "w-5 h-5",
648
+ fill: "currentColor",
649
+ viewBox: "0 0 20 20",
650
+ "aria-hidden": "true",
651
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
652
+ "path",
653
+ {
654
+ fillRule: "evenodd",
655
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z",
656
+ clipRule: "evenodd"
657
+ }
658
+ )
659
+ }
660
+ )
661
+ };
662
+ function Alert({
663
+ children,
664
+ variant = "info",
665
+ title,
666
+ onClose,
667
+ className = ""
668
+ }) {
669
+ const styles = ALERT_STYLES[variant];
670
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
671
+ "div",
672
+ {
673
+ className: `relative p-4 rounded-xl border ${styles.container} ${className}`,
674
+ role: "alert",
675
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex gap-3", children: [
676
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: `flex-shrink-0 ${styles.icon}`, children: ICONS[variant] }),
677
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex-1 min-w-0", children: [
678
+ title && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
679
+ Heading,
680
+ {
681
+ level: 3,
682
+ className: `text-sm font-semibold mb-1 ${styles.title}`,
683
+ children: title
684
+ }
685
+ ),
686
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: `text-sm ${styles.text}`, children })
687
+ ] }),
688
+ onClose && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
689
+ Button,
690
+ {
691
+ variant: "ghost",
692
+ size: "sm",
693
+ onClick: onClose,
694
+ className: `flex-shrink-0 ml-3 rounded-lg p-1.5 min-h-0 ${styles.icon} ${ALERT_CLOSE_HOVER}`,
695
+ "aria-label": "Close",
696
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
697
+ "svg",
698
+ {
699
+ className: "w-5 h-5",
700
+ fill: "currentColor",
701
+ viewBox: "0 0 20 20",
702
+ "aria-hidden": "true",
703
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
704
+ "path",
705
+ {
706
+ fillRule: "evenodd",
707
+ d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",
708
+ clipRule: "evenodd"
709
+ }
710
+ )
711
+ }
712
+ )
713
+ }
714
+ )
715
+ ] })
716
+ }
717
+ );
718
+ }
719
+
720
+ // src/components/Divider.tsx
721
+ var import_jsx_runtime8 = require("react/jsx-runtime");
722
+ var BORDER_LIGHT = "border-zinc-100 dark:border-slate-700/60";
723
+ var TEXT_MUTED = "text-zinc-400 dark:text-zinc-500";
724
+ function Divider({
725
+ label,
726
+ orientation = "horizontal",
727
+ className = ""
728
+ }) {
729
+ if (orientation === "vertical") {
730
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
731
+ "div",
732
+ {
733
+ className: `w-px h-full border-l ${BORDER_LIGHT} ${className}`,
734
+ role: "separator",
735
+ "aria-orientation": "vertical"
736
+ }
737
+ );
738
+ }
739
+ if (label) {
740
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: `flex items-center gap-4 ${className}`, role: "separator", children: [
741
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `flex-1 h-px border-t ${BORDER_LIGHT}` }),
742
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Span, { className: `text-sm font-medium ${TEXT_MUTED}`, children: label }),
743
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `flex-1 h-px border-t ${BORDER_LIGHT}` })
744
+ ] });
745
+ }
746
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
747
+ "div",
748
+ {
749
+ className: `w-full h-px border-t ${BORDER_LIGHT} ${className}`,
750
+ role: "separator",
751
+ "aria-orientation": "horizontal"
752
+ }
753
+ );
754
+ }
755
+
756
+ // src/components/Progress.tsx
757
+ var import_jsx_runtime9 = require("react/jsx-runtime");
758
+ var TEXT_PRIMARY = "text-zinc-900 dark:text-zinc-50";
759
+ var TEXT_SECONDARY = "text-zinc-500 dark:text-zinc-400";
760
+ var BG_SECONDARY = "bg-zinc-50 dark:bg-slate-900";
761
+ var FLEX_BETWEEN = "flex items-center justify-between";
762
+ var INDETERMINATE_CSS = `
763
+ @keyframes lir-progress-indeterminate {
764
+ 0% { transform: translateX(-100%); }
765
+ 100% { transform: translateX(350%); }
766
+ }
767
+ .lir-progress-indeterminate {
768
+ animation: lir-progress-indeterminate 1.5s ease-in-out infinite;
769
+ }
770
+ `;
771
+ function Progress({
772
+ value,
773
+ max = 100,
774
+ variant = "primary",
775
+ size = "md",
776
+ label,
777
+ showValue = false,
778
+ className = ""
779
+ }) {
780
+ const percentage = Math.min(Math.max(value / max * 100, 0), 100);
781
+ const sizeClasses = {
782
+ sm: "h-1",
783
+ md: "h-2",
784
+ lg: "h-3"
785
+ };
786
+ const variantClasses = {
787
+ primary: "bg-primary",
788
+ success: "bg-green-600 dark:bg-green-500",
789
+ warning: "bg-yellow-600 dark:bg-yellow-500",
790
+ error: "bg-red-600 dark:bg-red-500"
791
+ };
792
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className, children: [
793
+ (label || showValue) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: `${FLEX_BETWEEN} mb-2`, children: [
794
+ label && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Span, { className: `text-sm font-medium ${TEXT_PRIMARY}`, children: label }),
795
+ showValue && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Span, { className: `text-sm font-medium ${TEXT_SECONDARY}`, children: [
796
+ Math.round(percentage),
797
+ "%"
798
+ ] })
799
+ ] }),
800
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
801
+ "div",
802
+ {
803
+ className: `w-full ${sizeClasses[size]} rounded-full overflow-hidden ${BG_SECONDARY}`,
804
+ role: "progressbar",
805
+ "aria-valuenow": value,
806
+ "aria-valuemin": 0,
807
+ "aria-valuemax": max,
808
+ "aria-label": label || `Progress: ${Math.round(percentage)}%`,
809
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
810
+ "div",
811
+ {
812
+ className: `h-full ${variantClasses[variant]} transition-all duration-300 ease-in-out rounded-full`,
813
+ style: { width: `${percentage}%` }
814
+ }
815
+ )
816
+ }
817
+ )
818
+ ] });
819
+ }
820
+ function IndeterminateProgress({
821
+ variant = "primary",
822
+ size = "md",
823
+ label,
824
+ className = ""
825
+ }) {
826
+ const sizeClasses = {
827
+ sm: "h-1",
828
+ md: "h-2",
829
+ lg: "h-3"
830
+ };
831
+ const variantClasses = {
832
+ primary: "bg-primary",
833
+ success: "bg-green-600 dark:bg-green-500",
834
+ warning: "bg-yellow-600 dark:bg-yellow-500",
835
+ error: "bg-red-600 dark:bg-red-500"
836
+ };
837
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className, children: [
838
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("style", { dangerouslySetInnerHTML: { __html: INDETERMINATE_CSS } }),
839
+ label && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Span, { className: `block text-sm font-medium mb-2 ${TEXT_PRIMARY}`, children: label }),
840
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
841
+ "div",
842
+ {
843
+ className: `w-full ${sizeClasses[size]} rounded-full overflow-hidden ${BG_SECONDARY} relative`,
844
+ role: "progressbar",
845
+ "aria-label": label || "Loading...",
846
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
847
+ "div",
848
+ {
849
+ className: `absolute inset-0 ${variantClasses[variant]} lir-progress-indeterminate rounded-full`,
850
+ style: { width: "40%" }
851
+ }
852
+ )
853
+ }
854
+ )
855
+ ] });
856
+ }
857
+
858
+ // src/components/Pagination.tsx
859
+ var import_contracts = require("@mohasinac/contracts");
860
+ var import_jsx_runtime10 = require("react/jsx-runtime");
861
+ function getPageNumbers(currentPage, totalPages, maxVisible) {
862
+ if (totalPages <= maxVisible) {
863
+ return Array.from({ length: totalPages }, (_, i) => i + 1);
864
+ }
865
+ const pages = [];
866
+ const halfVisible = Math.floor(maxVisible / 2);
867
+ let startPage = Math.max(1, currentPage - halfVisible);
868
+ let endPage = Math.min(totalPages, currentPage + halfVisible);
869
+ if (currentPage <= halfVisible) endPage = maxVisible;
870
+ if (currentPage >= totalPages - halfVisible)
871
+ startPage = totalPages - maxVisible + 1;
872
+ if (startPage > 1) {
873
+ pages.push(1);
874
+ if (startPage > 2) pages.push("...");
875
+ }
876
+ for (let i = startPage; i <= endPage; i++) pages.push(i);
877
+ if (endPage < totalPages) {
878
+ if (endPage < totalPages - 1) pages.push("...");
879
+ pages.push(totalPages);
880
+ }
881
+ return pages;
882
+ }
883
+ var SIZE_CLASSES = {
884
+ sm: "text-xs px-2 py-1 min-w-[28px]",
885
+ md: "text-sm px-3 py-1.5 min-w-[36px]",
886
+ lg: "text-base px-4 py-2 min-w-[44px]"
887
+ };
888
+ function Pagination({
889
+ currentPage,
890
+ totalPages,
891
+ onPageChange,
892
+ paginationConfig,
893
+ maxVisible: maxVisibleProp,
894
+ showFirstLast: showFirstLastProp,
895
+ showPrevNext: showPrevNextProp,
896
+ disabled = false,
897
+ size: sizeProp,
898
+ className = ""
899
+ }) {
900
+ const resolved = __spreadValues(__spreadValues({}, import_contracts.DEFAULT_PAGINATION_CONFIG), paginationConfig);
901
+ const maxVisible = maxVisibleProp != null ? maxVisibleProp : resolved.maxVisible;
902
+ const showFirstLast = showFirstLastProp != null ? showFirstLastProp : resolved.showFirstLast;
903
+ const showPrevNext = showPrevNextProp != null ? showPrevNextProp : resolved.showPrevNext;
904
+ const size = sizeProp != null ? sizeProp : resolved.size;
905
+ const handle = (page) => {
906
+ if (disabled || page < 1 || page > totalPages || page === currentPage)
907
+ return;
908
+ onPageChange(page);
909
+ };
910
+ const btnClass = (active, off) => {
911
+ const base = `${SIZE_CLASSES[size]} rounded border font-medium transition-colors`;
912
+ if (off)
913
+ return `${base} bg-zinc-100 dark:bg-slate-800 opacity-50 text-zinc-400 dark:text-zinc-500 border-zinc-200 dark:border-slate-700 cursor-not-allowed`;
914
+ if (active)
915
+ return `${base} bg-primary-600 text-white border-primary-600 cursor-default`;
916
+ return `${base} bg-white dark:bg-slate-900 text-zinc-700 dark:text-zinc-300 border-zinc-200 dark:border-slate-700 hover:bg-zinc-50 dark:hover:bg-slate-800 hover:border-zinc-300 dark:hover:border-slate-600 cursor-pointer`;
917
+ };
918
+ const pages = getPageNumbers(currentPage, totalPages, maxVisible);
919
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
920
+ "nav",
921
+ {
922
+ className: `flex items-center gap-1 ${className}`,
923
+ "aria-label": "Pagination",
924
+ children: [
925
+ showFirstLast && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
926
+ "button",
927
+ {
928
+ type: "button",
929
+ className: btnClass(false, disabled || currentPage === 1),
930
+ onClick: () => handle(1),
931
+ disabled: disabled || currentPage === 1,
932
+ "aria-label": "First page",
933
+ children: "\xAB"
934
+ }
935
+ ),
936
+ showPrevNext && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
937
+ "button",
938
+ {
939
+ type: "button",
940
+ className: btnClass(false, disabled || currentPage === 1),
941
+ onClick: () => handle(currentPage - 1),
942
+ disabled: disabled || currentPage === 1,
943
+ "aria-label": "Previous page",
944
+ children: "\u2039"
945
+ }
946
+ ),
947
+ pages.map(
948
+ (page, i) => page === "..." ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
949
+ "span",
950
+ {
951
+ className: `${SIZE_CLASSES[size]} text-zinc-400 dark:text-zinc-500 text-center`,
952
+ "aria-hidden": "true",
953
+ children: "\u2026"
954
+ },
955
+ `ellipsis-${i}`
956
+ ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
957
+ "button",
958
+ {
959
+ type: "button",
960
+ className: btnClass(
961
+ page === currentPage,
962
+ disabled && page !== currentPage
963
+ ),
964
+ onClick: () => handle(page),
965
+ disabled,
966
+ "aria-label": `Page ${page}`,
967
+ "aria-current": page === currentPage ? "page" : void 0,
968
+ children: page
969
+ },
970
+ page
971
+ )
972
+ ),
973
+ showPrevNext && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
974
+ "button",
975
+ {
976
+ type: "button",
977
+ className: btnClass(false, disabled || currentPage === totalPages),
978
+ onClick: () => handle(currentPage + 1),
979
+ disabled: disabled || currentPage === totalPages,
980
+ "aria-label": "Next page",
981
+ children: "\u203A"
982
+ }
983
+ ),
984
+ showFirstLast && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
985
+ "button",
986
+ {
987
+ type: "button",
988
+ className: btnClass(false, disabled || currentPage === totalPages),
989
+ onClick: () => handle(totalPages),
990
+ disabled: disabled || currentPage === totalPages,
991
+ "aria-label": "Last page",
992
+ children: "\xBB"
993
+ }
994
+ )
995
+ ]
996
+ }
997
+ );
998
+ }
999
+
1000
+ // src/components/StatusBadge.tsx
1001
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1002
+ var STATUS_TO_VARIANT = {
1003
+ // Generic
1004
+ active: "active",
1005
+ inactive: "inactive",
1006
+ pending: "pending",
1007
+ approved: "approved",
1008
+ rejected: "rejected",
1009
+ success: "success",
1010
+ warning: "warning",
1011
+ danger: "danger",
1012
+ info: "info",
1013
+ // Order
1014
+ confirmed: "success",
1015
+ processing: "info",
1016
+ shipped: "info",
1017
+ delivered: "success",
1018
+ cancelled: "danger",
1019
+ refunded: "warning",
1020
+ failed: "danger",
1021
+ // Payment
1022
+ paid: "success",
1023
+ partially_refunded: "warning",
1024
+ // Review (pending/approved/rejected already covered)
1025
+ // Ticket
1026
+ open: "warning",
1027
+ in_progress: "info",
1028
+ resolved: "success",
1029
+ closed: "inactive"
1030
+ };
1031
+ var STATUS_LABELS = {
1032
+ active: "Active",
1033
+ inactive: "Inactive",
1034
+ pending: "Pending",
1035
+ approved: "Approved",
1036
+ rejected: "Rejected",
1037
+ success: "Success",
1038
+ warning: "Warning",
1039
+ danger: "Danger",
1040
+ info: "Info",
1041
+ confirmed: "Confirmed",
1042
+ processing: "Processing",
1043
+ shipped: "Shipped",
1044
+ delivered: "Delivered",
1045
+ cancelled: "Cancelled",
1046
+ refunded: "Refunded",
1047
+ failed: "Failed",
1048
+ paid: "Paid",
1049
+ partially_refunded: "Partially Refunded",
1050
+ open: "Open",
1051
+ in_progress: "In Progress",
1052
+ resolved: "Resolved",
1053
+ closed: "Closed"
1054
+ };
1055
+ function StatusBadge({ status, label, className }) {
1056
+ var _a, _b;
1057
+ const variant = (_a = STATUS_TO_VARIANT[status]) != null ? _a : "default";
1058
+ const displayLabel = (_b = label != null ? label : STATUS_LABELS[status]) != null ? _b : status;
1059
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Badge, { variant, className, children: displayLabel });
1060
+ }
1061
+
1062
+ // src/components/Modal.tsx
1063
+ var import_react2 = require("react");
1064
+ var import_react_dom = require("react-dom");
1065
+ var import_lucide_react2 = require("lucide-react");
1066
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1067
+ var SIZE_CLASSES2 = {
1068
+ sm: "max-w-sm",
1069
+ md: "max-w-lg",
1070
+ lg: "max-w-2xl",
1071
+ xl: "max-w-4xl",
1072
+ full: "max-w-[95vw] max-h-[95vh]"
1073
+ };
1074
+ function Modal({
1075
+ isOpen,
1076
+ onClose,
1077
+ title,
1078
+ children,
1079
+ size = "md",
1080
+ showCloseButton = true,
1081
+ className = ""
1082
+ }) {
1083
+ const titleId = (0, import_react2.useId)();
1084
+ const panelRef = (0, import_react2.useRef)(null);
1085
+ const prevFocusRef = (0, import_react2.useRef)(null);
1086
+ (0, import_react2.useEffect)(() => {
1087
+ if (!isOpen) return;
1088
+ const prev = document.body.style.overflow;
1089
+ document.body.style.overflow = "hidden";
1090
+ return () => {
1091
+ document.body.style.overflow = prev;
1092
+ };
1093
+ }, [isOpen]);
1094
+ (0, import_react2.useEffect)(() => {
1095
+ var _a;
1096
+ if (isOpen) {
1097
+ prevFocusRef.current = document.activeElement;
1098
+ requestAnimationFrame(() => {
1099
+ var _a2;
1100
+ return (_a2 = panelRef.current) == null ? void 0 : _a2.focus();
1101
+ });
1102
+ } else {
1103
+ (_a = prevFocusRef.current) == null ? void 0 : _a.focus();
1104
+ }
1105
+ }, [isOpen]);
1106
+ const handleKeyDown = (0, import_react2.useCallback)(
1107
+ (e) => {
1108
+ if (e.key === "Escape") {
1109
+ onClose();
1110
+ return;
1111
+ }
1112
+ if (e.key !== "Tab") return;
1113
+ const panel = panelRef.current;
1114
+ if (!panel) return;
1115
+ const focusable = Array.from(
1116
+ panel.querySelectorAll(
1117
+ 'a[href],button:not([disabled]),textarea,input,select,[tabindex]:not([tabindex="-1"])'
1118
+ )
1119
+ );
1120
+ if (!focusable.length) return;
1121
+ const first = focusable[0];
1122
+ const last = focusable[focusable.length - 1];
1123
+ if (e.shiftKey && document.activeElement === first) {
1124
+ e.preventDefault();
1125
+ last.focus();
1126
+ } else if (!e.shiftKey && document.activeElement === last) {
1127
+ e.preventDefault();
1128
+ first.focus();
1129
+ }
1130
+ },
1131
+ [onClose]
1132
+ );
1133
+ if (!isOpen) return null;
1134
+ if (typeof document === "undefined") return null;
1135
+ return (0, import_react_dom.createPortal)(
1136
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1137
+ "div",
1138
+ {
1139
+ className: "fixed inset-0 z-50 flex items-center justify-center p-4",
1140
+ role: "dialog",
1141
+ "aria-modal": "true",
1142
+ "aria-labelledby": title ? titleId : void 0,
1143
+ onKeyDown: handleKeyDown,
1144
+ children: [
1145
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1146
+ "div",
1147
+ {
1148
+ className: "absolute inset-0 bg-black/60 backdrop-blur-sm",
1149
+ "aria-hidden": "true",
1150
+ onClick: onClose
1151
+ }
1152
+ ),
1153
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1154
+ "div",
1155
+ {
1156
+ ref: panelRef,
1157
+ tabIndex: -1,
1158
+ className: [
1159
+ "relative w-full rounded-2xl bg-white dark:bg-slate-900",
1160
+ "shadow-2xl ring-1 ring-zinc-200 dark:ring-slate-700",
1161
+ "flex flex-col max-h-[90vh] overflow-hidden",
1162
+ "animate-[fadeInUp_0.15s_ease_forwards]",
1163
+ SIZE_CLASSES2[size],
1164
+ className
1165
+ ].join(" "),
1166
+ children: [
1167
+ (title || showCloseButton) && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center justify-between px-6 py-4 border-b border-zinc-100 dark:border-slate-800 flex-shrink-0", children: [
1168
+ title && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1169
+ Heading,
1170
+ {
1171
+ level: 2,
1172
+ id: titleId,
1173
+ className: "!text-lg !font-semibold !font-sans tracking-tight",
1174
+ children: title
1175
+ }
1176
+ ),
1177
+ showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1178
+ Button,
1179
+ {
1180
+ variant: "ghost",
1181
+ size: "sm",
1182
+ type: "button",
1183
+ onClick: onClose,
1184
+ className: "ml-auto p-1.5 !min-h-0 rounded-lg text-zinc-400 hover:text-zinc-600 dark:text-zinc-500 dark:hover:text-zinc-300",
1185
+ "aria-label": "Close",
1186
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react2.X, { className: "w-5 h-5" })
1187
+ }
1188
+ )
1189
+ ] }),
1190
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "overflow-y-auto flex-1 px-6 py-4", children })
1191
+ ]
1192
+ }
1193
+ )
1194
+ ]
1195
+ }
1196
+ ),
1197
+ document.body
1198
+ );
1199
+ }
1200
+
1201
+ // src/components/Drawer.tsx
1202
+ var import_react3 = require("react");
1203
+ var import_react_dom2 = require("react-dom");
1204
+ var import_lucide_react3 = require("lucide-react");
1205
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1206
+ var SIDE_TRANSLATE = {
1207
+ left: {
1208
+ closed: "-translate-x-full",
1209
+ open: "translate-x-0",
1210
+ base: "left-0 top-0 bottom-0"
1211
+ },
1212
+ right: {
1213
+ closed: "translate-x-full",
1214
+ open: "translate-x-0",
1215
+ base: "right-0 top-0 bottom-0"
1216
+ },
1217
+ bottom: {
1218
+ closed: "translate-y-full",
1219
+ open: "translate-y-0",
1220
+ base: "bottom-0 left-0 right-0"
1221
+ }
1222
+ };
1223
+ var SIDE_SIZE = {
1224
+ sm: "w-72",
1225
+ md: "w-80 sm:w-96",
1226
+ lg: "w-full sm:w-[480px]",
1227
+ full: "w-full"
1228
+ };
1229
+ function Drawer({
1230
+ isOpen,
1231
+ onClose,
1232
+ title,
1233
+ children,
1234
+ footer,
1235
+ side = "right",
1236
+ size = "md",
1237
+ showCloseButton = true,
1238
+ className = ""
1239
+ }) {
1240
+ const panelRef = (0, import_react3.useRef)(null);
1241
+ const prevFocusRef = (0, import_react3.useRef)(null);
1242
+ (0, import_react3.useEffect)(() => {
1243
+ if (!isOpen) return;
1244
+ const prev = document.body.style.overflow;
1245
+ document.body.style.overflow = "hidden";
1246
+ return () => {
1247
+ document.body.style.overflow = prev;
1248
+ };
1249
+ }, [isOpen]);
1250
+ (0, import_react3.useEffect)(() => {
1251
+ var _a;
1252
+ if (isOpen) {
1253
+ prevFocusRef.current = document.activeElement;
1254
+ requestAnimationFrame(() => {
1255
+ var _a2;
1256
+ return (_a2 = panelRef.current) == null ? void 0 : _a2.focus();
1257
+ });
1258
+ } else {
1259
+ (_a = prevFocusRef.current) == null ? void 0 : _a.focus();
1260
+ }
1261
+ }, [isOpen]);
1262
+ const handleKeyDown = (0, import_react3.useCallback)(
1263
+ (e) => {
1264
+ if (e.key === "Escape") onClose();
1265
+ },
1266
+ [onClose]
1267
+ );
1268
+ const { closed, open, base } = SIDE_TRANSLATE[side];
1269
+ const isBottom = side === "bottom";
1270
+ if (typeof document === "undefined") return null;
1271
+ return (0, import_react_dom2.createPortal)(
1272
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1273
+ "div",
1274
+ {
1275
+ className: `fixed inset-0 z-50 ${isOpen ? "pointer-events-auto" : "pointer-events-none"}`,
1276
+ onKeyDown: handleKeyDown,
1277
+ children: [
1278
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1279
+ "div",
1280
+ {
1281
+ className: `absolute inset-0 bg-black/50 backdrop-blur-sm transition-opacity duration-300 ${isOpen ? "opacity-100" : "opacity-0"}`,
1282
+ "aria-hidden": "true",
1283
+ onClick: onClose
1284
+ }
1285
+ ),
1286
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1287
+ "div",
1288
+ {
1289
+ ref: panelRef,
1290
+ tabIndex: -1,
1291
+ role: "dialog",
1292
+ "aria-modal": "true",
1293
+ className: [
1294
+ "absolute bg-white dark:bg-slate-900",
1295
+ "shadow-2xl ring-1 ring-zinc-200 dark:ring-slate-700",
1296
+ "flex flex-col",
1297
+ "transition-transform duration-300 ease-out",
1298
+ base,
1299
+ isBottom ? "rounded-t-2xl max-h-[90vh]" : `${SIDE_SIZE[size]} h-full`,
1300
+ isOpen ? open : closed,
1301
+ className
1302
+ ].join(" "),
1303
+ children: [
1304
+ isBottom && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex justify-center pt-3 pb-1 flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1305
+ "div",
1306
+ {
1307
+ className: "w-10 h-1 rounded-full bg-zinc-300 dark:bg-slate-600",
1308
+ "aria-hidden": "true"
1309
+ }
1310
+ ) }),
1311
+ (title || showCloseButton) && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between px-5 py-4 border-b border-zinc-100 dark:border-slate-800 flex-shrink-0", children: [
1312
+ title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1313
+ Heading,
1314
+ {
1315
+ level: 2,
1316
+ className: "!text-base !font-semibold !font-sans",
1317
+ children: title
1318
+ }
1319
+ ),
1320
+ showCloseButton && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1321
+ Button,
1322
+ {
1323
+ variant: "ghost",
1324
+ size: "sm",
1325
+ type: "button",
1326
+ onClick: onClose,
1327
+ className: "ml-auto p-1.5 !min-h-0 rounded-lg text-zinc-400 hover:text-zinc-700 dark:text-zinc-500 dark:hover:text-zinc-300",
1328
+ "aria-label": "Close",
1329
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react3.X, { className: "w-5 h-5" })
1330
+ }
1331
+ )
1332
+ ] }),
1333
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex-1 overflow-y-auto px-5 py-4", children }),
1334
+ footer && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex-shrink-0 border-t border-zinc-100 dark:border-slate-800 px-5 py-4", children: footer })
1335
+ ]
1336
+ }
1337
+ )
1338
+ ]
1339
+ }
1340
+ ),
1341
+ document.body
1342
+ );
1343
+ }
1344
+
1345
+ // src/components/Select.tsx
1346
+ var import_react4 = require("react");
1347
+ var import_lucide_react4 = require("lucide-react");
1348
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1349
+ function Select({
1350
+ options,
1351
+ value,
1352
+ onChange,
1353
+ placeholder = "Select\u2026",
1354
+ label,
1355
+ error,
1356
+ disabled = false,
1357
+ required,
1358
+ className = "",
1359
+ id: externalId
1360
+ }) {
1361
+ var _a;
1362
+ const generatedId = (0, import_react4.useId)();
1363
+ const id = externalId != null ? externalId : generatedId;
1364
+ const [open, setOpen] = (0, import_react4.useState)(false);
1365
+ const [openUp, setOpenUp] = (0, import_react4.useState)(false);
1366
+ const ref = (0, import_react4.useRef)(null);
1367
+ const selected = options.find((o) => o.value === value);
1368
+ const toggle = (0, import_react4.useCallback)(() => {
1369
+ if (!disabled) {
1370
+ if (!open && ref.current) {
1371
+ const rect = ref.current.getBoundingClientRect();
1372
+ const spaceBelow = window.innerHeight - rect.bottom;
1373
+ const spaceAbove = rect.top;
1374
+ setOpenUp(spaceBelow < 160 && spaceAbove > spaceBelow);
1375
+ }
1376
+ setOpen((v) => !v);
1377
+ }
1378
+ }, [disabled, open]);
1379
+ const handleSelect = (0, import_react4.useCallback)(
1380
+ (val) => {
1381
+ onChange == null ? void 0 : onChange(val);
1382
+ setOpen(false);
1383
+ },
1384
+ [onChange]
1385
+ );
1386
+ (0, import_react4.useEffect)(() => {
1387
+ const handler = (e) => {
1388
+ if (ref.current && !ref.current.contains(e.target)) {
1389
+ setOpen(false);
1390
+ }
1391
+ };
1392
+ if (open) document.addEventListener("mousedown", handler);
1393
+ return () => document.removeEventListener("mousedown", handler);
1394
+ }, [open]);
1395
+ const handleKeyDown = (0, import_react4.useCallback)(
1396
+ (e) => {
1397
+ if (e.key === "Escape") {
1398
+ setOpen(false);
1399
+ return;
1400
+ }
1401
+ if (e.key === "Enter" || e.key === " ") {
1402
+ toggle();
1403
+ e.preventDefault();
1404
+ return;
1405
+ }
1406
+ if (e.key === "ArrowDown" && !open) {
1407
+ setOpen(true);
1408
+ e.preventDefault();
1409
+ return;
1410
+ }
1411
+ if (e.key === "ArrowDown") {
1412
+ e.preventDefault();
1413
+ const idx = options.findIndex((o) => o.value === value);
1414
+ const next = options.slice(idx < 0 ? 0 : idx + 1).find((o) => !o.disabled);
1415
+ if (next) onChange == null ? void 0 : onChange(next.value);
1416
+ }
1417
+ if (e.key === "ArrowUp") {
1418
+ e.preventDefault();
1419
+ const idx = options.findIndex((o) => o.value === value);
1420
+ if (idx < 0) return;
1421
+ const prev = [...options].slice(0, idx).reverse().find((o) => !o.disabled);
1422
+ if (prev) onChange == null ? void 0 : onChange(prev.value);
1423
+ }
1424
+ },
1425
+ [open, options, value, onChange, toggle]
1426
+ );
1427
+ const triggerClass = [
1428
+ "flex h-10 w-full items-center justify-between rounded-lg border px-3 py-2 text-sm",
1429
+ "transition-colors bg-white dark:bg-slate-800/60",
1430
+ "focus:outline-none focus:ring-2 focus:ring-offset-0",
1431
+ error ? "border-red-400 dark:border-red-500 focus:ring-red-500/20" : "border-zinc-200 dark:border-slate-700 focus:ring-primary-500/20 dark:focus:ring-secondary-400/20 focus:border-primary-500 dark:focus:border-secondary-400",
1432
+ disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
1433
+ className
1434
+ ].join(" ");
1435
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { ref, className: "relative w-full", children: [
1436
+ label && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1437
+ Label,
1438
+ {
1439
+ htmlFor: id,
1440
+ className: "!text-zinc-700 dark:!text-zinc-300",
1441
+ required,
1442
+ children: label
1443
+ }
1444
+ ),
1445
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1446
+ Button,
1447
+ {
1448
+ id,
1449
+ type: "button",
1450
+ role: "combobox",
1451
+ "aria-expanded": open,
1452
+ "aria-haspopup": "listbox",
1453
+ "aria-disabled": disabled,
1454
+ disabled,
1455
+ variant: "ghost",
1456
+ className: triggerClass,
1457
+ onClick: toggle,
1458
+ onKeyDown: handleKeyDown,
1459
+ children: [
1460
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1461
+ Span,
1462
+ {
1463
+ className: selected ? "text-zinc-900 dark:text-zinc-50" : "text-zinc-400 dark:text-zinc-500",
1464
+ children: (_a = selected == null ? void 0 : selected.label) != null ? _a : placeholder
1465
+ }
1466
+ ),
1467
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1468
+ import_lucide_react4.ChevronDown,
1469
+ {
1470
+ className: `h-4 w-4 flex-shrink-0 text-zinc-400 transition-transform duration-200 ${open ? "rotate-180" : ""}`,
1471
+ "aria-hidden": "true"
1472
+ }
1473
+ )
1474
+ ]
1475
+ }
1476
+ ),
1477
+ open && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1478
+ Ul,
1479
+ {
1480
+ role: "listbox",
1481
+ className: [
1482
+ "absolute z-50 w-full overflow-auto rounded-lg border border-zinc-200 dark:border-slate-700 bg-white dark:bg-slate-800 shadow-lg max-h-60 py-1",
1483
+ openUp ? "bottom-full mb-1" : "top-full mt-1"
1484
+ ].join(" "),
1485
+ children: options.map((option) => {
1486
+ const isSelected = option.value === value;
1487
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1488
+ Li,
1489
+ {
1490
+ role: "option",
1491
+ "aria-selected": isSelected,
1492
+ "aria-disabled": option.disabled,
1493
+ className: [
1494
+ "relative flex cursor-pointer items-center px-3 py-2 text-sm select-none",
1495
+ option.disabled ? "opacity-40 cursor-not-allowed" : isSelected ? "bg-primary-50 dark:bg-primary-900/20 text-primary-700 dark:text-primary-300" : "text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-700"
1496
+ ].join(" "),
1497
+ onClick: () => !option.disabled && handleSelect(option.value),
1498
+ children: [
1499
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Span, { className: "flex-1", children: option.label }),
1500
+ isSelected && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1501
+ import_lucide_react4.Check,
1502
+ {
1503
+ className: "h-4 w-4 ml-2 flex-shrink-0",
1504
+ "aria-hidden": "true"
1505
+ }
1506
+ )
1507
+ ]
1508
+ },
1509
+ option.value
1510
+ );
1511
+ })
1512
+ }
1513
+ ),
1514
+ error && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { size: "xs", variant: "error", className: "mt-1.5", role: "alert", children: error })
1515
+ ] });
1516
+ }
1517
+
1518
+ // src/components/StarRating.tsx
1519
+ var import_react5 = require("react");
1520
+ var import_lucide_react5 = require("lucide-react");
1521
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1522
+ var SIZE_PX = { sm: "w-4 h-4", md: "w-5 h-5", lg: "w-6 h-6" };
1523
+ function StarRating({
1524
+ value = 0,
1525
+ onChange,
1526
+ max = 5,
1527
+ size = "md",
1528
+ readOnly = false,
1529
+ className = "",
1530
+ label
1531
+ }) {
1532
+ const [hovered, setHovered] = (0, import_react5.useState)(null);
1533
+ const displayed = hovered != null ? hovered : value;
1534
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1535
+ Span,
1536
+ {
1537
+ className: `inline-flex items-center gap-0.5 ${className}`,
1538
+ role: readOnly ? "img" : "group",
1539
+ "aria-label": label != null ? label : `${value} out of ${max} stars`,
1540
+ children: [
1541
+ Array.from({ length: max }, (_, i) => {
1542
+ const starValue = i + 1;
1543
+ const filled = starValue <= displayed;
1544
+ const half = !filled && starValue - 0.5 <= displayed;
1545
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1546
+ Span,
1547
+ {
1548
+ className: readOnly ? void 0 : "cursor-pointer",
1549
+ onClick: () => !readOnly && (onChange == null ? void 0 : onChange(starValue)),
1550
+ onMouseEnter: () => !readOnly && setHovered(starValue),
1551
+ onMouseLeave: () => !readOnly && setHovered(null),
1552
+ "aria-hidden": !readOnly ? "true" : void 0,
1553
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1554
+ import_lucide_react5.Star,
1555
+ {
1556
+ className: [
1557
+ SIZE_PX[size],
1558
+ "transition-colors duration-100",
1559
+ filled || half ? "fill-amber-400 text-amber-400" : "fill-transparent text-zinc-300 dark:text-slate-600",
1560
+ !readOnly && !filled ? "hover:fill-amber-300 hover:text-amber-300" : ""
1561
+ ].join(" "),
1562
+ "aria-hidden": "true"
1563
+ }
1564
+ )
1565
+ },
1566
+ starValue
1567
+ );
1568
+ }),
1569
+ !readOnly && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Span, { className: "sr-only", children: [
1570
+ value,
1571
+ " out of ",
1572
+ max
1573
+ ] })
1574
+ ]
1575
+ }
1576
+ );
1577
+ }
1578
+
1579
+ // src/components/Breadcrumb.tsx
1580
+ var import_lucide_react6 = require("lucide-react");
1581
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1582
+ function Breadcrumb({ items, className = "" }) {
1583
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Nav, { "aria-label": "Breadcrumb", className, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Ol, { className: "flex items-center gap-1 flex-wrap text-sm text-zinc-500 dark:text-zinc-400", children: items.map((item, i) => {
1584
+ const isLast = i === items.length - 1;
1585
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Li, { className: "flex items-center gap-1", children: [
1586
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1587
+ import_lucide_react6.ChevronRight,
1588
+ {
1589
+ className: "w-3.5 h-3.5 flex-shrink-0 text-zinc-400 dark:text-zinc-600",
1590
+ "aria-hidden": "true"
1591
+ }
1592
+ ),
1593
+ isLast || !item.href ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1594
+ Span,
1595
+ {
1596
+ className: isLast ? "font-medium text-zinc-900 dark:text-zinc-50" : "text-zinc-500 dark:text-zinc-400",
1597
+ "aria-current": isLast ? "page" : void 0,
1598
+ children: item.label
1599
+ }
1600
+ ) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1601
+ "a",
1602
+ {
1603
+ href: item.href,
1604
+ className: "hover:text-primary-600 dark:hover:text-primary-400 transition-colors",
1605
+ children: item.label
1606
+ }
1607
+ )
1608
+ ] }, i);
1609
+ }) }) });
1610
+ }
1611
+
1612
+ // src/components/ImageLightbox.tsx
1613
+ var import_react6 = require("react");
1614
+ var import_react_dom3 = require("react-dom");
1615
+ var import_lucide_react7 = require("lucide-react");
1616
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1617
+ function ImageLightbox({
1618
+ images,
1619
+ activeIndex,
1620
+ onClose,
1621
+ onNavigate
1622
+ }) {
1623
+ var _a;
1624
+ const [currentIndex, setCurrentIndex] = (0, import_react6.useState)(activeIndex != null ? activeIndex : 0);
1625
+ const overlayRef = (0, import_react6.useRef)(null);
1626
+ (0, import_react6.useEffect)(() => {
1627
+ if (activeIndex !== null && activeIndex >= 0) {
1628
+ setCurrentIndex(activeIndex);
1629
+ }
1630
+ }, [activeIndex]);
1631
+ const isOpen = activeIndex !== null && activeIndex >= 0 && images.length > 0;
1632
+ (0, import_react6.useEffect)(() => {
1633
+ if (!isOpen) return;
1634
+ const prev = document.body.style.overflow;
1635
+ document.body.style.overflow = "hidden";
1636
+ return () => {
1637
+ document.body.style.overflow = prev;
1638
+ };
1639
+ }, [isOpen]);
1640
+ const navigate = (0, import_react6.useCallback)(
1641
+ (dir) => {
1642
+ setCurrentIndex((prev) => {
1643
+ const next = (prev + dir + images.length) % images.length;
1644
+ onNavigate == null ? void 0 : onNavigate(next);
1645
+ return next;
1646
+ });
1647
+ },
1648
+ [images.length, onNavigate]
1649
+ );
1650
+ const handleKeyDown = (0, import_react6.useCallback)(
1651
+ (e) => {
1652
+ if (e.key === "Escape") {
1653
+ onClose();
1654
+ return;
1655
+ }
1656
+ if (e.key === "ArrowLeft") {
1657
+ navigate(-1);
1658
+ return;
1659
+ }
1660
+ if (e.key === "ArrowRight") {
1661
+ navigate(1);
1662
+ return;
1663
+ }
1664
+ },
1665
+ [onClose, navigate]
1666
+ );
1667
+ (0, import_react6.useEffect)(() => {
1668
+ if (isOpen) {
1669
+ requestAnimationFrame(() => {
1670
+ var _a2;
1671
+ return (_a2 = overlayRef.current) == null ? void 0 : _a2.focus();
1672
+ });
1673
+ }
1674
+ }, [isOpen]);
1675
+ if (!isOpen || typeof document === "undefined") return null;
1676
+ const image = images[currentIndex];
1677
+ const hasMultiple = images.length > 1;
1678
+ return (0, import_react_dom3.createPortal)(
1679
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1680
+ "div",
1681
+ {
1682
+ ref: overlayRef,
1683
+ tabIndex: -1,
1684
+ className: "fixed inset-0 z-[9999] bg-black/95 flex flex-col items-center justify-center outline-none",
1685
+ role: "dialog",
1686
+ "aria-modal": "true",
1687
+ "aria-label": "Image lightbox",
1688
+ onKeyDown: handleKeyDown,
1689
+ children: [
1690
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1691
+ Button,
1692
+ {
1693
+ variant: "ghost",
1694
+ size: "sm",
1695
+ type: "button",
1696
+ onClick: onClose,
1697
+ className: "absolute top-4 right-4 z-10 w-12 h-12 p-0 !min-h-0 rounded-full bg-white/15 hover:bg-red-500/50 text-white flex items-center justify-center",
1698
+ "aria-label": "Close lightbox",
1699
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.X, { className: "w-7 h-7" })
1700
+ }
1701
+ ),
1702
+ hasMultiple && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "absolute top-4 left-1/2 -translate-x-1/2 text-white/70 text-sm font-medium", children: [
1703
+ currentIndex + 1,
1704
+ " / ",
1705
+ images.length
1706
+ ] }),
1707
+ hasMultiple && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1708
+ Button,
1709
+ {
1710
+ variant: "ghost",
1711
+ size: "sm",
1712
+ type: "button",
1713
+ onClick: () => navigate(-1),
1714
+ className: "absolute left-4 top-1/2 -translate-y-1/2 w-12 h-12 p-0 !min-h-0 rounded-full bg-white/15 hover:bg-white/30 text-white z-10 flex items-center justify-center",
1715
+ "aria-label": "Previous image",
1716
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.ChevronLeft, { className: "w-7 h-7" })
1717
+ }
1718
+ ),
1719
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex-1 flex items-center justify-center p-16 w-full h-full relative", children: [
1720
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1721
+ "img",
1722
+ {
1723
+ src: image.src,
1724
+ alt: (_a = image.alt) != null ? _a : "",
1725
+ className: "max-h-full max-w-full object-contain select-none",
1726
+ draggable: false
1727
+ }
1728
+ ),
1729
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "absolute bottom-4 right-4 text-white/40 flex items-center gap-1 text-xs", children: [
1730
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.ZoomIn, { className: "w-4 h-4" }),
1731
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Span, { className: "text-xs", children: "Scroll to zoom" })
1732
+ ] })
1733
+ ] }),
1734
+ image.caption && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1735
+ Text,
1736
+ {
1737
+ size: "sm",
1738
+ variant: "secondary",
1739
+ className: "flex-shrink-0 !text-white/70 text-center px-8 pb-4",
1740
+ children: image.caption
1741
+ }
1742
+ ),
1743
+ hasMultiple && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1744
+ Button,
1745
+ {
1746
+ variant: "ghost",
1747
+ size: "sm",
1748
+ type: "button",
1749
+ onClick: () => navigate(1),
1750
+ className: "absolute right-4 top-1/2 -translate-y-1/2 w-12 h-12 p-0 !min-h-0 rounded-full bg-white/15 hover:bg-white/30 text-white z-10 flex items-center justify-center",
1751
+ "aria-label": "Next image",
1752
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.ChevronRight, { className: "w-7 h-7" })
1753
+ }
1754
+ )
1755
+ ]
1756
+ }
1757
+ ),
1758
+ document.body
1759
+ );
1760
+ }
1761
+
1762
+ // src/DataTable.tsx
1763
+ var import_react7 = require("react");
1764
+
1765
+ // src/components/Layout.tsx
1766
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1767
+ var GAP_MAP = {
1768
+ none: "",
1769
+ px: "gap-px",
1770
+ xs: "gap-1",
1771
+ sm: "gap-2",
1772
+ "2.5": "gap-2.5",
1773
+ "3": "gap-3",
1774
+ md: "gap-4",
1775
+ lg: "gap-6",
1776
+ xl: "gap-8",
1777
+ "2xl": "gap-12"
1778
+ };
1779
+ var CONTAINER_MAP = {
1780
+ /** `max-w-3xl` — blog posts, legal / policy pages */
1781
+ sm: "max-w-3xl mx-auto px-4 sm:px-6 lg:px-8",
1782
+ /** `max-w-4xl` — narrow content, contact, about */
1783
+ md: "max-w-4xl mx-auto px-4 sm:px-6 lg:px-8",
1784
+ /** `max-w-5xl` — medium content, checkout, help */
1785
+ lg: "max-w-5xl mx-auto px-4 sm:px-6 lg:px-8",
1786
+ /** `max-w-6xl` — product detail, cart */
1787
+ xl: "max-w-6xl mx-auto px-4 sm:px-6 lg:px-8",
1788
+ /** `max-w-7xl` — main content grids (default) */
1789
+ "2xl": "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8",
1790
+ /** `max-w-screen-2xl` — full-bleed wide content */
1791
+ full: "max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-8",
1792
+ /** `max-w-screen-2xl` — wide store/seller layouts (no lg:px-8) */
1793
+ wide: "max-w-screen-2xl mx-auto px-4 sm:px-6"
1794
+ };
1795
+ var GRID_MAP = {
1796
+ 1: "grid grid-cols-1",
1797
+ 2: "grid grid-cols-1 sm:grid-cols-2",
1798
+ 3: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-3",
1799
+ 4: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-4",
1800
+ 5: "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5",
1801
+ 6: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6",
1802
+ /** Card grid — starts at 2 on mobile, max 5 on 2xl */
1803
+ cards: "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-4 2xl:grid-cols-5",
1804
+ /** Equal halves on md+ */
1805
+ halves: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-2",
1806
+ /** 2fr / 1fr split on md+ */
1807
+ twoThird: "grid grid-cols-1 md:grid-cols-[2fr_1fr]",
1808
+ /** 1fr / 2fr split on md+ */
1809
+ oneThird: "grid grid-cols-1 md:grid-cols-[1fr_2fr]",
1810
+ /** Fixed 280px left sidebar + 1fr on lg+ */
1811
+ sidebar: "grid grid-cols-1 lg:grid-cols-[280px_1fr]",
1812
+ /** 1fr + fixed 280px right sidebar on lg+ */
1813
+ sidebarRight: "grid grid-cols-1 lg:grid-cols-[1fr_280px]",
1814
+ /** Fixed 320px left sidebar + 1fr on lg+ (admin layout) */
1815
+ sidebarWide: "grid grid-cols-1 lg:grid-cols-[320px_1fr]",
1816
+ /** CSS auto-fill, min 200px columns */
1817
+ autoSm: "grid grid-cols-[repeat(auto-fill,minmax(200px,1fr))]",
1818
+ /** CSS auto-fill, min 280px columns */
1819
+ autoMd: "grid grid-cols-[repeat(auto-fill,minmax(280px,1fr))]",
1820
+ /** CSS auto-fill, min 360px columns */
1821
+ autoLg: "grid grid-cols-[repeat(auto-fill,minmax(360px,1fr))]"
1822
+ };
1823
+ var ITEMS_MAP = {
1824
+ start: "items-start",
1825
+ center: "items-center",
1826
+ end: "items-end",
1827
+ stretch: "items-stretch",
1828
+ baseline: "items-baseline"
1829
+ };
1830
+ var JUSTIFY_MAP = {
1831
+ start: "justify-start",
1832
+ center: "justify-center",
1833
+ end: "justify-end",
1834
+ between: "justify-between",
1835
+ around: "justify-around",
1836
+ evenly: "justify-evenly"
1837
+ };
1838
+ function Container(_a) {
1839
+ var _b = _a, {
1840
+ size = "2xl",
1841
+ as,
1842
+ className = "",
1843
+ children
1844
+ } = _b, props = __objRest(_b, [
1845
+ "size",
1846
+ "as",
1847
+ "className",
1848
+ "children"
1849
+ ]);
1850
+ const Tag = as != null ? as : "div";
1851
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1852
+ Tag,
1853
+ __spreadProps(__spreadValues({
1854
+ className: [CONTAINER_MAP[size], className].filter(Boolean).join(" ")
1855
+ }, props), {
1856
+ children
1857
+ })
1858
+ );
1859
+ }
1860
+ function Stack(_a) {
1861
+ var _b = _a, {
1862
+ gap = "md",
1863
+ align = "stretch",
1864
+ as,
1865
+ className = "",
1866
+ children
1867
+ } = _b, props = __objRest(_b, [
1868
+ "gap",
1869
+ "align",
1870
+ "as",
1871
+ "className",
1872
+ "children"
1873
+ ]);
1874
+ const Tag = as != null ? as : "div";
1875
+ const classes = [
1876
+ "flex flex-col",
1877
+ GAP_MAP[gap],
1878
+ align !== "stretch" ? ITEMS_MAP[align] : "",
1879
+ className
1880
+ ].filter(Boolean).join(" ");
1881
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Tag, __spreadProps(__spreadValues({ className: classes }, props), { children }));
1882
+ }
1883
+ function Row(_a) {
1884
+ var _b = _a, {
1885
+ gap = "md",
1886
+ align = "center",
1887
+ justify = "start",
1888
+ wrap = false,
1889
+ as,
1890
+ className = "",
1891
+ children
1892
+ } = _b, props = __objRest(_b, [
1893
+ "gap",
1894
+ "align",
1895
+ "justify",
1896
+ "wrap",
1897
+ "as",
1898
+ "className",
1899
+ "children"
1900
+ ]);
1901
+ const Tag = as != null ? as : "div";
1902
+ const classes = [
1903
+ "flex flex-row",
1904
+ ITEMS_MAP[align],
1905
+ justify !== "start" ? JUSTIFY_MAP[justify] : "",
1906
+ GAP_MAP[gap],
1907
+ wrap ? "flex-wrap" : "",
1908
+ className
1909
+ ].filter(Boolean).join(" ");
1910
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Tag, __spreadProps(__spreadValues({ className: classes }, props), { children }));
1911
+ }
1912
+ function Grid(_a) {
1913
+ var _b = _a, {
1914
+ cols,
1915
+ gap = "md",
1916
+ as,
1917
+ className = "",
1918
+ children
1919
+ } = _b, props = __objRest(_b, [
1920
+ "cols",
1921
+ "gap",
1922
+ "as",
1923
+ "className",
1924
+ "children"
1925
+ ]);
1926
+ const Tag = as != null ? as : "div";
1927
+ const baseClass = cols !== void 0 ? GRID_MAP[cols] : "grid";
1928
+ const classes = [baseClass, GAP_MAP[gap], className].filter(Boolean).join(" ");
1929
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Tag, __spreadProps(__spreadValues({ className: classes }, props), { children }));
1930
+ }
1931
+
1932
+ // src/DataTable.tsx
1933
+ var import_contracts2 = require("@mohasinac/contracts");
1934
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1935
+ function DataTable({
1936
+ data,
1937
+ columns,
1938
+ keyExtractor,
1939
+ onRowClick,
1940
+ loading = false,
1941
+ emptyMessage,
1942
+ actions,
1943
+ mobileCardRender,
1944
+ emptyState,
1945
+ emptyIcon,
1946
+ emptyTitle,
1947
+ tableConfig,
1948
+ paginationConfig,
1949
+ externalPagination = false,
1950
+ // Explicit flat props — override tableConfig when provided
1951
+ pageSize: pageSizeProp,
1952
+ stickyHeader: stickyHeaderProp,
1953
+ striped: stripedProp,
1954
+ showViewToggle: showViewToggleProp,
1955
+ showTableView = true,
1956
+ viewMode: controlledViewMode,
1957
+ defaultViewMode: defaultViewModeProp,
1958
+ onViewModeChange,
1959
+ selectable: selectableProp,
1960
+ selectedIds = [],
1961
+ onSelectionChange,
1962
+ gridCols = "cards",
1963
+ labels = {}
1964
+ }) {
1965
+ const resolvedTable = (0, import_contracts2.mergeTableConfig)(tableConfig);
1966
+ const resolvedPag = __spreadValues(__spreadValues(__spreadValues({}, import_contracts2.DEFAULT_PAGINATION_CONFIG), tableConfig == null ? void 0 : tableConfig.pagination), paginationConfig);
1967
+ const pageSize = pageSizeProp != null ? pageSizeProp : resolvedTable.pageSize;
1968
+ const stickyHeader = stickyHeaderProp != null ? stickyHeaderProp : resolvedTable.sticky.enabled;
1969
+ const striped = stripedProp != null ? stripedProp : resolvedTable.striped;
1970
+ const showViewToggle = showViewToggleProp != null ? showViewToggleProp : resolvedTable.showViewToggle;
1971
+ const selectable = selectableProp != null ? selectableProp : resolvedTable.selectable;
1972
+ const defaultViewMode = defaultViewModeProp != null ? defaultViewModeProp : resolvedTable.defaultViewMode;
1973
+ const [sortKey, setSortKey] = (0, import_react7.useState)(null);
1974
+ const [sortDirection, setSortDirection] = (0, import_react7.useState)(null);
1975
+ const [currentPage, setCurrentPage] = (0, import_react7.useState)(1);
1976
+ const [internalViewMode, setInternalViewMode] = (0, import_react7.useState)(defaultViewMode);
1977
+ const activeViewMode = controlledViewMode != null ? controlledViewMode : internalViewMode;
1978
+ const {
1979
+ loading: labelLoading = "Loading\u2026",
1980
+ noDataTitle = "No data found",
1981
+ noDataDescription = "There are no items to display.",
1982
+ actions: labelActions = "Actions",
1983
+ tableView = "Table view",
1984
+ gridView = "Grid view",
1985
+ listView = "List view"
1986
+ } = labels;
1987
+ const handleViewModeChange = (mode) => {
1988
+ if (controlledViewMode === void 0) setInternalViewMode(mode);
1989
+ onViewModeChange == null ? void 0 : onViewModeChange(mode);
1990
+ };
1991
+ const handleSort = (key) => {
1992
+ const col = columns.find((c) => c.key === key);
1993
+ if (!(col == null ? void 0 : col.sortable)) return;
1994
+ if (sortKey === key) {
1995
+ if (sortDirection === "asc") setSortDirection("desc");
1996
+ else {
1997
+ setSortKey(null);
1998
+ setSortDirection(null);
1999
+ }
2000
+ } else {
2001
+ setSortKey(key);
2002
+ setSortDirection("asc");
2003
+ }
2004
+ };
2005
+ const sortedData = (0, import_react7.useMemo)(() => {
2006
+ const sorted = [...data];
2007
+ if (sortKey && sortDirection) {
2008
+ sorted.sort((a, b) => {
2009
+ const aVal = a[sortKey];
2010
+ const bVal = b[sortKey];
2011
+ if (aVal == null) return 1;
2012
+ if (bVal == null) return -1;
2013
+ if (typeof aVal === "string" && typeof bVal === "string") {
2014
+ return sortDirection === "asc" ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
2015
+ }
2016
+ if (aVal < bVal) return sortDirection === "asc" ? -1 : 1;
2017
+ if (aVal > bVal) return sortDirection === "asc" ? 1 : -1;
2018
+ return 0;
2019
+ });
2020
+ }
2021
+ return sorted;
2022
+ }, [data, sortKey, sortDirection]);
2023
+ const paginatedData = (0, import_react7.useMemo)(() => {
2024
+ if (externalPagination) return sortedData;
2025
+ const start = (currentPage - 1) * pageSize;
2026
+ return sortedData.slice(start, start + pageSize);
2027
+ }, [sortedData, currentPage, externalPagination, pageSize]);
2028
+ const totalPages = Math.ceil(sortedData.length / pageSize);
2029
+ if (loading) {
2030
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "rounded-2xl border border-zinc-200 dark:border-slate-700 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex items-center justify-center h-64", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Spinner, { size: "lg", label: labelLoading }) }) });
2031
+ }
2032
+ if (data.length === 0) {
2033
+ if (emptyState) return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children: emptyState });
2034
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "rounded-2xl border border-zinc-200 dark:border-slate-700 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex items-center justify-center h-64", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "text-center px-4", children: [
2035
+ emptyIcon != null ? emptyIcon : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2036
+ "svg",
2037
+ {
2038
+ className: "mx-auto h-12 w-12 text-zinc-400",
2039
+ fill: "none",
2040
+ viewBox: "0 0 24 24",
2041
+ stroke: "currentColor",
2042
+ "aria-hidden": "true",
2043
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2044
+ "path",
2045
+ {
2046
+ strokeLinecap: "round",
2047
+ strokeLinejoin: "round",
2048
+ strokeWidth: 1.5,
2049
+ d: "M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"
2050
+ }
2051
+ )
2052
+ }
2053
+ ),
2054
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Text, { size: "sm", weight: "semibold", className: "mt-4", children: emptyTitle != null ? emptyTitle : noDataTitle }),
2055
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Text, { size: "sm", variant: "secondary", className: "mt-1", children: emptyMessage != null ? emptyMessage : noDataDescription })
2056
+ ] }) }) });
2057
+ }
2058
+ const renderViewToggle = () => {
2059
+ if (!showViewToggle) return null;
2060
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2061
+ "div",
2062
+ {
2063
+ className: "flex justify-end gap-1",
2064
+ role: "toolbar",
2065
+ "aria-label": "View mode",
2066
+ children: [
2067
+ showTableView && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2068
+ Button,
2069
+ {
2070
+ type: "button",
2071
+ variant: "ghost",
2072
+ size: "sm",
2073
+ onClick: () => handleViewModeChange("table"),
2074
+ "aria-label": tableView,
2075
+ "aria-pressed": activeViewMode === "table",
2076
+ className: `hidden sm:flex items-center justify-center p-2 rounded-lg ring-1 transition-colors ${activeViewMode === "table" ? "bg-primary/5 text-primary dark:bg-primary/10 ring-primary/30" : "text-zinc-500 dark:text-zinc-400 ring-zinc-200 dark:ring-slate-700 hover:bg-zinc-100 dark:hover:bg-slate-800"}`,
2077
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2078
+ "svg",
2079
+ {
2080
+ className: "w-4 h-4",
2081
+ fill: "none",
2082
+ viewBox: "0 0 24 24",
2083
+ stroke: "currentColor",
2084
+ strokeWidth: 1.5,
2085
+ "aria-hidden": "true",
2086
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2087
+ "path",
2088
+ {
2089
+ strokeLinecap: "round",
2090
+ strokeLinejoin: "round",
2091
+ d: "M3 10h18M3 6h18M3 14h18M3 18h18"
2092
+ }
2093
+ )
2094
+ }
2095
+ )
2096
+ }
2097
+ ),
2098
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2099
+ Button,
2100
+ {
2101
+ type: "button",
2102
+ variant: "ghost",
2103
+ size: "sm",
2104
+ onClick: () => handleViewModeChange("grid"),
2105
+ "aria-label": gridView,
2106
+ "aria-pressed": activeViewMode === "grid",
2107
+ className: `flex items-center justify-center p-2 rounded-lg ring-1 transition-colors ${activeViewMode === "grid" ? "bg-primary/5 text-primary dark:bg-primary/10 ring-primary/30" : "text-zinc-500 dark:text-zinc-400 ring-zinc-200 dark:ring-slate-700 hover:bg-zinc-100 dark:hover:bg-slate-800"}`,
2108
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2109
+ "svg",
2110
+ {
2111
+ className: "w-4 h-4",
2112
+ fill: "none",
2113
+ viewBox: "0 0 24 24",
2114
+ stroke: "currentColor",
2115
+ strokeWidth: 1.5,
2116
+ "aria-hidden": "true",
2117
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2118
+ "path",
2119
+ {
2120
+ strokeLinecap: "round",
2121
+ strokeLinejoin: "round",
2122
+ d: "M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zM13.5 15.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z"
2123
+ }
2124
+ )
2125
+ }
2126
+ )
2127
+ }
2128
+ ),
2129
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2130
+ Button,
2131
+ {
2132
+ type: "button",
2133
+ variant: "ghost",
2134
+ size: "sm",
2135
+ onClick: () => handleViewModeChange("list"),
2136
+ "aria-label": listView,
2137
+ "aria-pressed": activeViewMode === "list",
2138
+ className: `flex items-center justify-center p-2 rounded-lg ring-1 transition-colors ${activeViewMode === "list" ? "bg-primary/5 text-primary dark:bg-primary/10 ring-primary/30" : "text-zinc-500 dark:text-zinc-400 ring-zinc-200 dark:ring-slate-700 hover:bg-zinc-100 dark:hover:bg-slate-800"}`,
2139
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2140
+ "svg",
2141
+ {
2142
+ className: "w-4 h-4",
2143
+ fill: "none",
2144
+ viewBox: "0 0 24 24",
2145
+ stroke: "currentColor",
2146
+ strokeWidth: 1.5,
2147
+ "aria-hidden": "true",
2148
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2149
+ "path",
2150
+ {
2151
+ strokeLinecap: "round",
2152
+ strokeLinejoin: "round",
2153
+ d: "M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zM3.75 12h.007v.008H3.75V12zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm-.375 5.25h.007v.008H3.75v-.008zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
2154
+ }
2155
+ )
2156
+ }
2157
+ )
2158
+ }
2159
+ )
2160
+ ]
2161
+ }
2162
+ );
2163
+ };
2164
+ const renderCardGrid = (mode) => {
2165
+ if (!mobileCardRender) return null;
2166
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2167
+ "div",
2168
+ {
2169
+ className: mode === "grid" ? `${GRID_MAP[gridCols]} gap-6` : "flex flex-col gap-4",
2170
+ children: paginatedData.map((item) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2171
+ SelectableCard,
2172
+ {
2173
+ id: keyExtractor(item),
2174
+ selectable,
2175
+ selected: selectedIds.includes(keyExtractor(item)),
2176
+ listMode: mode === "list",
2177
+ onToggle: (id, checked) => onSelectionChange == null ? void 0 : onSelectionChange(
2178
+ checked ? [...selectedIds, id] : selectedIds.filter((s) => s !== id)
2179
+ ),
2180
+ children: mobileCardRender(item)
2181
+ },
2182
+ keyExtractor(item)
2183
+ ))
2184
+ }
2185
+ );
2186
+ };
2187
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "space-y-4", children: [
2188
+ renderViewToggle(),
2189
+ activeViewMode !== "table" && mobileCardRender && renderCardGrid(activeViewMode),
2190
+ activeViewMode === "table" && mobileCardRender && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "md:hidden space-y-6", children: paginatedData.map((item) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2191
+ SelectableCard,
2192
+ {
2193
+ id: keyExtractor(item),
2194
+ selectable,
2195
+ selected: selectedIds.includes(keyExtractor(item)),
2196
+ onToggle: (id, checked) => onSelectionChange == null ? void 0 : onSelectionChange(
2197
+ checked ? [...selectedIds, id] : selectedIds.filter((s) => s !== id)
2198
+ ),
2199
+ children: mobileCardRender(item)
2200
+ },
2201
+ keyExtractor(item)
2202
+ )) }),
2203
+ activeViewMode === "table" && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "rounded-2xl border border-zinc-200 dark:border-slate-700 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2204
+ "div",
2205
+ {
2206
+ className: `overflow-x-auto ${stickyHeader ? "max-h-[600px] overflow-y-auto" : ""}`,
2207
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("table", { className: "min-w-full divide-y divide-zinc-200 dark:divide-slate-700", children: [
2208
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2209
+ "thead",
2210
+ {
2211
+ className: `bg-zinc-50 dark:bg-slate-800 ${stickyHeader ? "sticky top-0 z-10" : ""}`,
2212
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("tr", { children: [
2213
+ selectable && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { scope: "col", className: "px-4 py-3 w-8", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2214
+ "input",
2215
+ {
2216
+ type: "checkbox",
2217
+ className: "rounded border-zinc-300",
2218
+ "aria-label": "Select all on page",
2219
+ checked: paginatedData.length > 0 && paginatedData.every(
2220
+ (item) => selectedIds.includes(keyExtractor(item))
2221
+ ),
2222
+ onChange: (e) => {
2223
+ const pageIds = paginatedData.map(keyExtractor);
2224
+ onSelectionChange == null ? void 0 : onSelectionChange(
2225
+ e.target.checked ? [.../* @__PURE__ */ new Set([...selectedIds, ...pageIds])] : selectedIds.filter(
2226
+ (id) => !pageIds.includes(id)
2227
+ )
2228
+ );
2229
+ }
2230
+ }
2231
+ ) }),
2232
+ columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2233
+ "th",
2234
+ {
2235
+ scope: "col",
2236
+ "aria-sort": col.sortable ? sortKey === col.key ? sortDirection === "asc" ? "ascending" : "descending" : "none" : void 0,
2237
+ className: `px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider ${col.sortable ? "cursor-pointer select-none hover:bg-zinc-100 dark:hover:bg-slate-700" : ""}`,
2238
+ style: { width: col.width },
2239
+ onClick: () => col.sortable && handleSort(col.key),
2240
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", children: [
2241
+ col.header,
2242
+ col.sortable && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-zinc-400", "aria-hidden": "true", children: sortKey === col.key ? sortDirection === "asc" ? "\u2191" : "\u2193" : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "opacity-30", children: "\u2195" }) })
2243
+ ] })
2244
+ },
2245
+ col.key
2246
+ )),
2247
+ actions && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2248
+ "th",
2249
+ {
2250
+ scope: "col",
2251
+ className: "px-6 py-3 text-right text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider",
2252
+ children: labelActions
2253
+ }
2254
+ )
2255
+ ] })
2256
+ }
2257
+ ),
2258
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("tbody", { className: "bg-white dark:bg-slate-900 divide-y divide-zinc-200 dark:divide-slate-700", children: paginatedData.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2259
+ "tr",
2260
+ {
2261
+ className: [
2262
+ striped && index % 2 === 1 ? "bg-zinc-50 dark:bg-slate-800" : "",
2263
+ onRowClick ? "cursor-pointer hover:bg-zinc-50 dark:hover:bg-slate-800/60" : "",
2264
+ "transition-colors duration-150"
2265
+ ].join(" "),
2266
+ onClick: () => onRowClick == null ? void 0 : onRowClick(item),
2267
+ children: [
2268
+ selectable && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2269
+ "td",
2270
+ {
2271
+ className: "px-4 py-4 w-8",
2272
+ onClick: (e) => e.stopPropagation(),
2273
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2274
+ "input",
2275
+ {
2276
+ type: "checkbox",
2277
+ className: "rounded border-zinc-300",
2278
+ "aria-label": "Select row",
2279
+ checked: selectedIds.includes(keyExtractor(item)),
2280
+ onChange: (e) => {
2281
+ const id = keyExtractor(item);
2282
+ onSelectionChange == null ? void 0 : onSelectionChange(
2283
+ e.target.checked ? [...selectedIds, id] : selectedIds.filter((s) => s !== id)
2284
+ );
2285
+ }
2286
+ }
2287
+ )
2288
+ }
2289
+ ),
2290
+ columns.map((col) => {
2291
+ var _a;
2292
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2293
+ "td",
2294
+ {
2295
+ className: "px-6 py-4 whitespace-nowrap text-sm text-zinc-900 dark:text-zinc-100",
2296
+ children: col.render ? col.render(item) : (_a = item[col.key]) != null ? _a : "-"
2297
+ },
2298
+ col.key
2299
+ );
2300
+ }),
2301
+ actions && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2302
+ "td",
2303
+ {
2304
+ className: "px-6 py-4 whitespace-nowrap text-right text-sm font-medium",
2305
+ onClick: (e) => e.stopPropagation(),
2306
+ children: actions(item)
2307
+ }
2308
+ )
2309
+ ]
2310
+ },
2311
+ keyExtractor(item)
2312
+ )) })
2313
+ ] })
2314
+ }
2315
+ ) }),
2316
+ !externalPagination && totalPages > 1 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2317
+ Pagination,
2318
+ {
2319
+ currentPage,
2320
+ totalPages,
2321
+ onPageChange: setCurrentPage,
2322
+ maxVisible: resolvedPag.maxVisible,
2323
+ showFirstLast: resolvedPag.showFirstLast,
2324
+ showPrevNext: resolvedPag.showPrevNext,
2325
+ size: resolvedPag.size
2326
+ }
2327
+ ) })
2328
+ ] });
2329
+ }
2330
+ function SelectableCard({
2331
+ id,
2332
+ selectable,
2333
+ selected,
2334
+ onToggle,
2335
+ children,
2336
+ listMode = false
2337
+ }) {
2338
+ if (!selectable) return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "h-full", children });
2339
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "relative group h-full", children: [
2340
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2341
+ "div",
2342
+ {
2343
+ className: [
2344
+ "absolute z-10",
2345
+ listMode ? "left-2 top-1/2 -translate-y-1/2" : "top-2 left-2"
2346
+ ].join(" "),
2347
+ onClick: (e) => e.stopPropagation(),
2348
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "w-6 h-6 rounded-md bg-white/95 dark:bg-slate-800/95 shadow-md flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "relative flex items-center justify-center", children: [
2349
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2350
+ "input",
2351
+ {
2352
+ type: "checkbox",
2353
+ className: [
2354
+ "w-4 h-4 rounded cursor-pointer transition-all appearance-none",
2355
+ selected ? "border-2 border-primary bg-primary" : "border-2 border-zinc-500 dark:border-slate-400 bg-transparent group-hover:border-primary"
2356
+ ].join(" "),
2357
+ checked: selected,
2358
+ onChange: (e) => onToggle(id, e.target.checked),
2359
+ "aria-label": "Select item"
2360
+ }
2361
+ ),
2362
+ selected && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2363
+ "svg",
2364
+ {
2365
+ className: "absolute inset-0 m-auto w-2.5 h-2.5 text-white pointer-events-none",
2366
+ fill: "none",
2367
+ stroke: "currentColor",
2368
+ viewBox: "0 0 24 24",
2369
+ "aria-hidden": "true",
2370
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2371
+ "path",
2372
+ {
2373
+ strokeLinecap: "round",
2374
+ strokeLinejoin: "round",
2375
+ strokeWidth: 3,
2376
+ d: "M5 13l4 4L19 7"
2377
+ }
2378
+ )
2379
+ }
2380
+ )
2381
+ ] }) })
2382
+ }
2383
+ ),
2384
+ selected && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2385
+ "div",
2386
+ {
2387
+ className: "absolute inset-0 z-[5] rounded-xl ring-2 ring-primary ring-offset-0 pointer-events-none",
2388
+ "aria-hidden": "true"
2389
+ }
2390
+ ),
2391
+ children
2392
+ ] });
2393
+ }
2394
+
2395
+ // src/index.ts
2396
+ var import_contracts3 = require("@mohasinac/contracts");
2397
+ // Annotate the CommonJS export names for ESM import in node:
2398
+ 0 && (module.exports = {
2399
+ Alert,
2400
+ Article,
2401
+ Aside,
2402
+ Badge,
2403
+ BlockFooter,
2404
+ BlockHeader,
2405
+ Breadcrumb,
2406
+ Button,
2407
+ Caption,
2408
+ Container,
2409
+ DEFAULT_PAGINATION_CONFIG,
2410
+ DEFAULT_STICKY_CONFIG,
2411
+ DEFAULT_TABLE_CONFIG,
2412
+ DataTable,
2413
+ Divider,
2414
+ Drawer,
2415
+ GRID_MAP,
2416
+ Grid,
2417
+ Heading,
2418
+ ImageLightbox,
2419
+ IndeterminateProgress,
2420
+ Label,
2421
+ Li,
2422
+ Main,
2423
+ Modal,
2424
+ Nav,
2425
+ Ol,
2426
+ Pagination,
2427
+ Progress,
2428
+ Row,
2429
+ Section,
2430
+ Select,
2431
+ Skeleton,
2432
+ Span,
2433
+ Spinner,
2434
+ Stack,
2435
+ StarRating,
2436
+ StatusBadge,
2437
+ Text,
2438
+ Ul,
2439
+ mergeTableConfig
2440
+ });