@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 +2440 -0
- package/dist/index.d.cts +829 -0
- package/dist/index.d.ts +829 -0
- package/dist/index.js +2371 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +42 -0
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
|
+
});
|