@jameskabz/nextcraft-ui 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1421 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +223 -1
- package/dist/index.d.ts +223 -1
- package/dist/index.js +1418 -65
- package/dist/index.js.map +1 -1
- package/dist/styles.css +235 -4
- package/package.json +3 -1
package/dist/index.cjs
CHANGED
|
@@ -38,15 +38,24 @@ __export(index_exports, {
|
|
|
38
38
|
CraftButton: () => CraftButton,
|
|
39
39
|
CraftCard: () => CraftCard,
|
|
40
40
|
CraftCheckbox: () => CraftCheckbox,
|
|
41
|
+
CraftConfirmDialog: () => CraftConfirmDialog,
|
|
42
|
+
CraftCreateEditDrawer: () => CraftCreateEditDrawer,
|
|
41
43
|
CraftCurrencyInput: () => CraftCurrencyInput,
|
|
44
|
+
CraftDataTable: () => CraftDataTable,
|
|
42
45
|
CraftDatePicker: () => CraftDatePicker,
|
|
43
46
|
CraftDrawer: () => CraftDrawer,
|
|
44
47
|
CraftEmptyState: () => CraftEmptyState,
|
|
48
|
+
CraftFilterBar: () => CraftFilterBar,
|
|
49
|
+
CraftForm: () => CraftForm,
|
|
50
|
+
CraftFormBuilder: () => CraftFormBuilder,
|
|
51
|
+
CraftFormField: () => CraftFormField,
|
|
45
52
|
CraftInput: () => CraftInput,
|
|
46
53
|
CraftModal: () => CraftModal,
|
|
47
54
|
CraftNumberInput: () => CraftNumberInput,
|
|
55
|
+
CraftPagination: () => CraftPagination,
|
|
48
56
|
CraftSelect: () => CraftSelect,
|
|
49
57
|
CraftSkeleton: () => CraftSkeleton,
|
|
58
|
+
CraftSubmitButton: () => CraftSubmitButton,
|
|
50
59
|
CraftSwitch: () => CraftSwitch,
|
|
51
60
|
CraftTabs: () => CraftTabs,
|
|
52
61
|
CraftTextarea: () => CraftTextarea,
|
|
@@ -512,7 +521,8 @@ function CraftModal({
|
|
|
512
521
|
ref,
|
|
513
522
|
tabIndex: -1,
|
|
514
523
|
className: cn(
|
|
515
|
-
"relative z-10 w-full max-w-
|
|
524
|
+
"relative z-10 w-full max-w-7xl rounded-3xl border border-[rgb(var(--nc-border)/0.45)] p-6 text-[rgb(var(--nc-fg))] shadow-[0_20px_60px_rgba(0,0,0,0.45)] backdrop-blur-2xl",
|
|
525
|
+
"max-h-[calc(100vh-1rem)] overflow-y-auto",
|
|
516
526
|
className
|
|
517
527
|
),
|
|
518
528
|
"data-nc-theme": tone,
|
|
@@ -1101,10 +1111,1347 @@ var CraftCurrencyInput = React13.forwardRef(({ className, tone, currencySymbol =
|
|
|
1101
1111
|
});
|
|
1102
1112
|
CraftCurrencyInput.displayName = "CraftCurrencyInput";
|
|
1103
1113
|
|
|
1104
|
-
// src/components/
|
|
1114
|
+
// src/components/craft-form.tsx
|
|
1115
|
+
var React14 = __toESM(require("react"), 1);
|
|
1116
|
+
var import_react_hook_form2 = require("react-hook-form");
|
|
1117
|
+
|
|
1118
|
+
// src/components/craft-submit-button.tsx
|
|
1119
|
+
var import_react_hook_form = require("react-hook-form");
|
|
1105
1120
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1106
|
-
function
|
|
1121
|
+
function CraftSubmitButton({
|
|
1122
|
+
className,
|
|
1123
|
+
tone,
|
|
1124
|
+
loading,
|
|
1125
|
+
loadingLabel = "Submitting...",
|
|
1126
|
+
disableWhenInvalid = true,
|
|
1127
|
+
disabled,
|
|
1128
|
+
children,
|
|
1129
|
+
...props
|
|
1130
|
+
}) {
|
|
1131
|
+
var _a, _b, _c, _d;
|
|
1132
|
+
const form = (0, import_react_hook_form.useFormContext)();
|
|
1133
|
+
const isSubmitting = (_b = loading != null ? loading : (_a = form == null ? void 0 : form.formState) == null ? void 0 : _a.isSubmitting) != null ? _b : false;
|
|
1134
|
+
const isValid = (_d = (_c = form == null ? void 0 : form.formState) == null ? void 0 : _c.isValid) != null ? _d : true;
|
|
1135
|
+
const isDisabled = disabled || isSubmitting || disableWhenInvalid && !isValid;
|
|
1107
1136
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1137
|
+
"button",
|
|
1138
|
+
{
|
|
1139
|
+
type: "submit",
|
|
1140
|
+
className: cn(
|
|
1141
|
+
"relative inline-flex items-center justify-center gap-2 rounded-xl px-6 py-2 text-sm font-semibold",
|
|
1142
|
+
"bg-linear-to-br from-[rgb(var(--nc-accent-1))] via-[rgb(var(--nc-accent-2))] to-[rgb(var(--nc-accent-3))]",
|
|
1143
|
+
"text-white shadow-[0_12px_30px_rgb(var(--nc-accent-1)/0.35)]",
|
|
1144
|
+
"transition-all duration-200",
|
|
1145
|
+
"hover:shadow-[0_16px_36px_rgb(var(--nc-accent-1)/0.5)] hover:scale-[1.02] active:scale-[0.98]",
|
|
1146
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[rgb(var(--nc-accent-1)/0.6)]",
|
|
1147
|
+
"disabled:opacity-60 disabled:cursor-not-allowed disabled:hover:scale-100",
|
|
1148
|
+
className
|
|
1149
|
+
),
|
|
1150
|
+
"data-nc-theme": tone,
|
|
1151
|
+
disabled: isDisabled,
|
|
1152
|
+
...props,
|
|
1153
|
+
children: [
|
|
1154
|
+
isSubmitting && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "inline-flex h-4 w-4 animate-spin rounded-full border-2 border-white/60 border-t-white" }),
|
|
1155
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: isSubmitting ? loadingLabel : children })
|
|
1156
|
+
]
|
|
1157
|
+
}
|
|
1158
|
+
);
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
// src/components/craft-form.tsx
|
|
1162
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1163
|
+
function CraftForm({
|
|
1164
|
+
form,
|
|
1165
|
+
onSubmit,
|
|
1166
|
+
open,
|
|
1167
|
+
defaultOpen = false,
|
|
1168
|
+
onOpenChange,
|
|
1169
|
+
trigger,
|
|
1170
|
+
title,
|
|
1171
|
+
description,
|
|
1172
|
+
submitLabel = "Save",
|
|
1173
|
+
cancelLabel = "Cancel",
|
|
1174
|
+
tone,
|
|
1175
|
+
className,
|
|
1176
|
+
children,
|
|
1177
|
+
footer,
|
|
1178
|
+
disableSubmitWhenInvalid = true,
|
|
1179
|
+
closeOnSubmit = true,
|
|
1180
|
+
formClassName
|
|
1181
|
+
}) {
|
|
1182
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React14.useState(defaultOpen);
|
|
1183
|
+
const isControlled = typeof open === "boolean";
|
|
1184
|
+
const isOpen = isControlled ? open : uncontrolledOpen;
|
|
1185
|
+
const setOpen = React14.useCallback(
|
|
1186
|
+
(next) => {
|
|
1187
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
1188
|
+
onOpenChange == null ? void 0 : onOpenChange(next);
|
|
1189
|
+
},
|
|
1190
|
+
[isControlled, onOpenChange]
|
|
1191
|
+
);
|
|
1192
|
+
const formId = React14.useId();
|
|
1193
|
+
const handleSubmit = form.handleSubmit(async (values) => {
|
|
1194
|
+
await onSubmit(values);
|
|
1195
|
+
if (closeOnSubmit) setOpen(false);
|
|
1196
|
+
});
|
|
1197
|
+
const footerContent = footer != null ? footer : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-wrap items-center justify-end gap-3", children: [
|
|
1198
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CraftButton, { type: "button", variant: "ghost", onClick: () => setOpen(false), children: cancelLabel }),
|
|
1199
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1200
|
+
CraftSubmitButton,
|
|
1201
|
+
{
|
|
1202
|
+
form: formId,
|
|
1203
|
+
disableWhenInvalid: disableSubmitWhenInvalid,
|
|
1204
|
+
children: submitLabel
|
|
1205
|
+
}
|
|
1206
|
+
)
|
|
1207
|
+
] });
|
|
1208
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_hook_form2.FormProvider, { ...form, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1209
|
+
CraftModal,
|
|
1210
|
+
{
|
|
1211
|
+
open: isOpen,
|
|
1212
|
+
onOpenChange: setOpen,
|
|
1213
|
+
trigger,
|
|
1214
|
+
title,
|
|
1215
|
+
description,
|
|
1216
|
+
tone,
|
|
1217
|
+
className,
|
|
1218
|
+
footer: footerContent,
|
|
1219
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1220
|
+
"form",
|
|
1221
|
+
{
|
|
1222
|
+
id: formId,
|
|
1223
|
+
onSubmit: handleSubmit,
|
|
1224
|
+
className: cn("space-y-5", formClassName),
|
|
1225
|
+
children
|
|
1226
|
+
}
|
|
1227
|
+
)
|
|
1228
|
+
}
|
|
1229
|
+
) });
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
// src/components/craft-form-builder.tsx
|
|
1233
|
+
var React15 = __toESM(require("react"), 1);
|
|
1234
|
+
var import_react_hook_form4 = require("react-hook-form");
|
|
1235
|
+
|
|
1236
|
+
// src/components/craft-form-field.tsx
|
|
1237
|
+
var import_react_hook_form3 = require("react-hook-form");
|
|
1238
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1239
|
+
function getFieldError(errors, name) {
|
|
1240
|
+
if (!errors || typeof errors !== "object") return void 0;
|
|
1241
|
+
const segments = name.split(".");
|
|
1242
|
+
let current = errors;
|
|
1243
|
+
for (const segment of segments) {
|
|
1244
|
+
if (!current || typeof current !== "object") return void 0;
|
|
1245
|
+
current = current[segment];
|
|
1246
|
+
}
|
|
1247
|
+
return current;
|
|
1248
|
+
}
|
|
1249
|
+
var baseInputClass = "w-full rounded-2xl border-2 bg-[rgb(var(--nc-surface)/0.08)] text-[rgb(var(--nc-fg))] backdrop-blur-xl shadow-[inset_0_2px_8px_rgba(0,0,0,0.3)] focus:outline-none focus:ring-4 transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed border-[rgb(var(--nc-border)/0.35)] focus:border-[rgb(var(--nc-accent-1)/0.8)] focus:ring-[rgb(var(--nc-accent-1)/0.3)] px-5 py-3 text-base placeholder:text-[rgb(var(--nc-fg-soft))]";
|
|
1250
|
+
function CraftFormField({
|
|
1251
|
+
name,
|
|
1252
|
+
label,
|
|
1253
|
+
description,
|
|
1254
|
+
type = "text",
|
|
1255
|
+
options = [],
|
|
1256
|
+
placeholder,
|
|
1257
|
+
tone,
|
|
1258
|
+
className,
|
|
1259
|
+
inputClassName,
|
|
1260
|
+
labelClassName,
|
|
1261
|
+
descriptionClassName,
|
|
1262
|
+
rules,
|
|
1263
|
+
disabled,
|
|
1264
|
+
fieldProps
|
|
1265
|
+
}) {
|
|
1266
|
+
const { register, control, formState } = (0, import_react_hook_form3.useFormContext)();
|
|
1267
|
+
const error = getFieldError(formState.errors, name);
|
|
1268
|
+
const errorMessage = typeof (error == null ? void 0 : error.message) === "string" ? error.message : void 0;
|
|
1269
|
+
if (type === "hidden") {
|
|
1270
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("input", { type: "hidden", ...register(name, rules) });
|
|
1271
|
+
}
|
|
1272
|
+
const labelNode = label ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1273
|
+
"label",
|
|
1274
|
+
{
|
|
1275
|
+
htmlFor: name,
|
|
1276
|
+
className: cn(
|
|
1277
|
+
"text-sm font-semibold text-[rgb(var(--nc-fg))]",
|
|
1278
|
+
labelClassName
|
|
1279
|
+
),
|
|
1280
|
+
children: label
|
|
1281
|
+
}
|
|
1282
|
+
) : null;
|
|
1283
|
+
const descriptionNode = description ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1284
|
+
"p",
|
|
1285
|
+
{
|
|
1286
|
+
className: cn(
|
|
1287
|
+
"text-xs text-[rgb(var(--nc-fg-muted))]",
|
|
1288
|
+
descriptionClassName
|
|
1289
|
+
),
|
|
1290
|
+
children: description
|
|
1291
|
+
}
|
|
1292
|
+
) : null;
|
|
1293
|
+
const errorNode = errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-xs text-[rgb(var(--nc-accent-3))]", children: errorMessage }) : null;
|
|
1294
|
+
const renderInput = () => {
|
|
1295
|
+
if (type === "textarea") {
|
|
1296
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1297
|
+
CraftTextarea,
|
|
1298
|
+
{
|
|
1299
|
+
id: name,
|
|
1300
|
+
placeholder,
|
|
1301
|
+
tone,
|
|
1302
|
+
className: inputClassName,
|
|
1303
|
+
disabled,
|
|
1304
|
+
...fieldProps,
|
|
1305
|
+
...register(name, rules)
|
|
1306
|
+
}
|
|
1307
|
+
);
|
|
1308
|
+
}
|
|
1309
|
+
if (type === "select" || type === "multiselect") {
|
|
1310
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1311
|
+
CraftSelect,
|
|
1312
|
+
{
|
|
1313
|
+
id: name,
|
|
1314
|
+
tone,
|
|
1315
|
+
className: inputClassName,
|
|
1316
|
+
multiple: type === "multiselect",
|
|
1317
|
+
disabled,
|
|
1318
|
+
...fieldProps,
|
|
1319
|
+
...register(name, rules),
|
|
1320
|
+
children: [
|
|
1321
|
+
placeholder && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: "", disabled: true, children: placeholder }),
|
|
1322
|
+
options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1323
|
+
"option",
|
|
1324
|
+
{
|
|
1325
|
+
value: option.value,
|
|
1326
|
+
disabled: option.disabled,
|
|
1327
|
+
children: option.label
|
|
1328
|
+
},
|
|
1329
|
+
option.value
|
|
1330
|
+
))
|
|
1331
|
+
]
|
|
1332
|
+
}
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
if (type === "checkbox") {
|
|
1336
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1337
|
+
CraftCheckbox,
|
|
1338
|
+
{
|
|
1339
|
+
tone,
|
|
1340
|
+
label,
|
|
1341
|
+
description,
|
|
1342
|
+
disabled,
|
|
1343
|
+
...fieldProps,
|
|
1344
|
+
...register(name, rules)
|
|
1345
|
+
}
|
|
1346
|
+
);
|
|
1347
|
+
}
|
|
1348
|
+
if (type === "switch") {
|
|
1349
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1350
|
+
CraftSwitch,
|
|
1351
|
+
{
|
|
1352
|
+
tone,
|
|
1353
|
+
label,
|
|
1354
|
+
disabled,
|
|
1355
|
+
...fieldProps,
|
|
1356
|
+
...register(name, rules)
|
|
1357
|
+
}
|
|
1358
|
+
);
|
|
1359
|
+
}
|
|
1360
|
+
if (type === "date") {
|
|
1361
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1362
|
+
import_react_hook_form3.Controller,
|
|
1363
|
+
{
|
|
1364
|
+
control,
|
|
1365
|
+
name,
|
|
1366
|
+
rules,
|
|
1367
|
+
render: ({ field }) => {
|
|
1368
|
+
var _a;
|
|
1369
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1370
|
+
CraftDatePicker,
|
|
1371
|
+
{
|
|
1372
|
+
value: (_a = field.value) != null ? _a : "",
|
|
1373
|
+
onChange: field.onChange,
|
|
1374
|
+
tone,
|
|
1375
|
+
placeholder,
|
|
1376
|
+
...fieldProps
|
|
1377
|
+
}
|
|
1378
|
+
);
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
);
|
|
1382
|
+
}
|
|
1383
|
+
if (type === "number") {
|
|
1384
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1385
|
+
CraftNumberInput,
|
|
1386
|
+
{
|
|
1387
|
+
id: name,
|
|
1388
|
+
tone,
|
|
1389
|
+
placeholder,
|
|
1390
|
+
className: inputClassName,
|
|
1391
|
+
disabled,
|
|
1392
|
+
...fieldProps,
|
|
1393
|
+
...register(name, rules)
|
|
1394
|
+
}
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1397
|
+
if (type === "currency") {
|
|
1398
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1399
|
+
CraftCurrencyInput,
|
|
1400
|
+
{
|
|
1401
|
+
id: name,
|
|
1402
|
+
tone,
|
|
1403
|
+
placeholder,
|
|
1404
|
+
className: inputClassName,
|
|
1405
|
+
disabled,
|
|
1406
|
+
...fieldProps,
|
|
1407
|
+
...register(name, rules)
|
|
1408
|
+
}
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
if (type === "radio") {
|
|
1412
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "grid gap-3", children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1413
|
+
"label",
|
|
1414
|
+
{
|
|
1415
|
+
className: cn(
|
|
1416
|
+
"flex items-center gap-3 rounded-2xl border border-[rgb(var(--nc-border)/0.35)] bg-[rgb(var(--nc-surface)/0.08)] px-4 py-3 text-sm text-[rgb(var(--nc-fg))]",
|
|
1417
|
+
"transition-all duration-200",
|
|
1418
|
+
"focus-within:ring-2 focus-within:ring-[rgb(var(--nc-accent-1)/0.5)]",
|
|
1419
|
+
option.disabled ? "opacity-60" : "cursor-pointer"
|
|
1420
|
+
),
|
|
1421
|
+
"data-nc-theme": tone,
|
|
1422
|
+
children: [
|
|
1423
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1424
|
+
"input",
|
|
1425
|
+
{
|
|
1426
|
+
type: "radio",
|
|
1427
|
+
value: option.value,
|
|
1428
|
+
disabled: option.disabled || disabled,
|
|
1429
|
+
className: "h-4 w-4 accent-[rgb(var(--nc-accent-1))]",
|
|
1430
|
+
...fieldProps,
|
|
1431
|
+
...register(name, rules)
|
|
1432
|
+
}
|
|
1433
|
+
),
|
|
1434
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: option.label })
|
|
1435
|
+
]
|
|
1436
|
+
},
|
|
1437
|
+
option.value
|
|
1438
|
+
)) });
|
|
1439
|
+
}
|
|
1440
|
+
if (type === "range" || type === "slider") {
|
|
1441
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1442
|
+
"input",
|
|
1443
|
+
{
|
|
1444
|
+
id: name,
|
|
1445
|
+
type: "range",
|
|
1446
|
+
className: cn(
|
|
1447
|
+
"w-full accent-[rgb(var(--nc-accent-1))]",
|
|
1448
|
+
inputClassName
|
|
1449
|
+
),
|
|
1450
|
+
disabled,
|
|
1451
|
+
...fieldProps,
|
|
1452
|
+
...register(name, rules)
|
|
1453
|
+
}
|
|
1454
|
+
);
|
|
1455
|
+
}
|
|
1456
|
+
if (type === "file" || type === "multifile") {
|
|
1457
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1458
|
+
"input",
|
|
1459
|
+
{
|
|
1460
|
+
id: name,
|
|
1461
|
+
type: "file",
|
|
1462
|
+
multiple: type === "multifile",
|
|
1463
|
+
className: cn(
|
|
1464
|
+
baseInputClass,
|
|
1465
|
+
"file:mr-4 file:rounded-xl file:border-0 file:bg-[rgb(var(--nc-surface)/0.35)] file:px-4 file:py-2 file:text-sm file:font-semibold file:text-[rgb(var(--nc-fg))]",
|
|
1466
|
+
inputClassName
|
|
1467
|
+
),
|
|
1468
|
+
disabled,
|
|
1469
|
+
...fieldProps,
|
|
1470
|
+
...register(name, rules)
|
|
1471
|
+
}
|
|
1472
|
+
);
|
|
1473
|
+
}
|
|
1474
|
+
const inputType = type === "search" || type === "password" || type === "email" || type === "tel" || type === "url" || type === "time" || type === "datetime-local" || type === "month" || type === "week" || type === "color" ? type : "text";
|
|
1475
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1476
|
+
CraftInput,
|
|
1477
|
+
{
|
|
1478
|
+
id: name,
|
|
1479
|
+
type: inputType,
|
|
1480
|
+
placeholder,
|
|
1481
|
+
tone,
|
|
1482
|
+
className: inputClassName,
|
|
1483
|
+
disabled,
|
|
1484
|
+
...fieldProps,
|
|
1485
|
+
...register(name, rules)
|
|
1486
|
+
}
|
|
1487
|
+
);
|
|
1488
|
+
};
|
|
1489
|
+
const showLabel = type !== "checkbox" && type !== "switch";
|
|
1490
|
+
const showDescriptionAbove = type !== "checkbox" && type !== "switch";
|
|
1491
|
+
const showDescriptionBelow = type === "switch";
|
|
1492
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: cn("space-y-2", className), "data-nc-theme": tone, children: [
|
|
1493
|
+
showLabel ? labelNode : null,
|
|
1494
|
+
showDescriptionAbove ? descriptionNode : null,
|
|
1495
|
+
renderInput(),
|
|
1496
|
+
showDescriptionBelow ? descriptionNode : null,
|
|
1497
|
+
errorNode
|
|
1498
|
+
] });
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
// src/components/craft-form-builder.tsx
|
|
1502
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1503
|
+
function defaultValueForField(field) {
|
|
1504
|
+
var _a, _b, _c, _d;
|
|
1505
|
+
if (field.defaultValue !== void 0) return field.defaultValue;
|
|
1506
|
+
switch (field.type) {
|
|
1507
|
+
case "checkbox":
|
|
1508
|
+
case "switch":
|
|
1509
|
+
return false;
|
|
1510
|
+
case "number":
|
|
1511
|
+
case "slider":
|
|
1512
|
+
case "range":
|
|
1513
|
+
return (_a = field.min) != null ? _a : 0;
|
|
1514
|
+
case "multifile":
|
|
1515
|
+
return [];
|
|
1516
|
+
case "file":
|
|
1517
|
+
return null;
|
|
1518
|
+
case "multiselect":
|
|
1519
|
+
return [];
|
|
1520
|
+
case "radio":
|
|
1521
|
+
return (_d = (_c = (_b = field.options) == null ? void 0 : _b[0]) == null ? void 0 : _c.value) != null ? _d : "";
|
|
1522
|
+
default:
|
|
1523
|
+
return "";
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
function buildDefaultValues(fields, initialData) {
|
|
1527
|
+
const values = {};
|
|
1528
|
+
fields.forEach((field) => {
|
|
1529
|
+
const initialValue = initialData == null ? void 0 : initialData[field.name];
|
|
1530
|
+
if (initialValue !== void 0 && initialValue !== null) {
|
|
1531
|
+
values[field.name] = initialValue;
|
|
1532
|
+
} else {
|
|
1533
|
+
values[field.name] = defaultValueForField(field);
|
|
1534
|
+
}
|
|
1535
|
+
});
|
|
1536
|
+
return values;
|
|
1537
|
+
}
|
|
1538
|
+
function buildRules(field, getValues) {
|
|
1539
|
+
var _a;
|
|
1540
|
+
const rules = { ...field.rules };
|
|
1541
|
+
const mergeValidate = (current, next) => {
|
|
1542
|
+
if (!current) return next;
|
|
1543
|
+
if (typeof current === "function") {
|
|
1544
|
+
return (value) => {
|
|
1545
|
+
const result = current(
|
|
1546
|
+
value,
|
|
1547
|
+
getValues()
|
|
1548
|
+
);
|
|
1549
|
+
if (result !== true) return result;
|
|
1550
|
+
return next(value);
|
|
1551
|
+
};
|
|
1552
|
+
}
|
|
1553
|
+
if (typeof current === "object") {
|
|
1554
|
+
return (value) => {
|
|
1555
|
+
const entries = Object.entries(current);
|
|
1556
|
+
for (const [, validator] of entries) {
|
|
1557
|
+
const result = validator(
|
|
1558
|
+
value,
|
|
1559
|
+
getValues()
|
|
1560
|
+
);
|
|
1561
|
+
if (result !== true) return result;
|
|
1562
|
+
}
|
|
1563
|
+
return next(value);
|
|
1564
|
+
};
|
|
1565
|
+
}
|
|
1566
|
+
return next;
|
|
1567
|
+
};
|
|
1568
|
+
if (field.required && field.type !== "hidden") {
|
|
1569
|
+
if (field.type === "checkbox" || field.type === "switch") {
|
|
1570
|
+
rules.validate = mergeValidate(
|
|
1571
|
+
rules.validate,
|
|
1572
|
+
(value) => {
|
|
1573
|
+
var _a2;
|
|
1574
|
+
return value ? true : `${String((_a2 = field.label) != null ? _a2 : field.name)} is required`;
|
|
1575
|
+
}
|
|
1576
|
+
);
|
|
1577
|
+
} else if (field.type === "multiselect") {
|
|
1578
|
+
rules.validate = mergeValidate(
|
|
1579
|
+
rules.validate,
|
|
1580
|
+
(value) => {
|
|
1581
|
+
var _a2;
|
|
1582
|
+
return Array.isArray(value) && value.length > 0 ? true : `${String((_a2 = field.label) != null ? _a2 : field.name)} is required`;
|
|
1583
|
+
}
|
|
1584
|
+
);
|
|
1585
|
+
} else if (field.type === "file") {
|
|
1586
|
+
rules.validate = mergeValidate(
|
|
1587
|
+
rules.validate,
|
|
1588
|
+
(value) => {
|
|
1589
|
+
var _a2;
|
|
1590
|
+
return value instanceof FileList && value.length > 0 ? true : `${String((_a2 = field.label) != null ? _a2 : field.name)} is required`;
|
|
1591
|
+
}
|
|
1592
|
+
);
|
|
1593
|
+
} else if (field.type === "multifile") {
|
|
1594
|
+
rules.validate = mergeValidate(
|
|
1595
|
+
rules.validate,
|
|
1596
|
+
(value) => {
|
|
1597
|
+
var _a2;
|
|
1598
|
+
return Array.isArray(value) && value.length > 0 ? true : `${String((_a2 = field.label) != null ? _a2 : field.name)} is required`;
|
|
1599
|
+
}
|
|
1600
|
+
);
|
|
1601
|
+
} else {
|
|
1602
|
+
rules.required = `${String((_a = field.label) != null ? _a : field.name)} is required`;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
if (field.min !== void 0) {
|
|
1606
|
+
rules.min = { value: field.min, message: `Min ${field.min}` };
|
|
1607
|
+
}
|
|
1608
|
+
if (field.max !== void 0) {
|
|
1609
|
+
rules.max = { value: field.max, message: `Max ${field.max}` };
|
|
1610
|
+
}
|
|
1611
|
+
if (field.type === "email") {
|
|
1612
|
+
rules.pattern = {
|
|
1613
|
+
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
1614
|
+
message: "Please enter a valid email address"
|
|
1615
|
+
};
|
|
1616
|
+
}
|
|
1617
|
+
if (field.type === "url") {
|
|
1618
|
+
rules.pattern = {
|
|
1619
|
+
value: /^https?:\/\/.+/,
|
|
1620
|
+
message: "Please enter a valid URL"
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1623
|
+
if (field.validate) {
|
|
1624
|
+
rules.validate = mergeValidate(
|
|
1625
|
+
rules.validate,
|
|
1626
|
+
(value) => {
|
|
1627
|
+
var _a2;
|
|
1628
|
+
return (_a2 = field.validate) == null ? void 0 : _a2.call(field, value, getValues());
|
|
1629
|
+
}
|
|
1630
|
+
);
|
|
1631
|
+
}
|
|
1632
|
+
return rules;
|
|
1633
|
+
}
|
|
1634
|
+
function CraftFormBuilder({
|
|
1635
|
+
title = "Form",
|
|
1636
|
+
description,
|
|
1637
|
+
fields,
|
|
1638
|
+
initialData = null,
|
|
1639
|
+
open,
|
|
1640
|
+
defaultOpen = false,
|
|
1641
|
+
onOpenChange,
|
|
1642
|
+
trigger,
|
|
1643
|
+
submitLabel = "Submit",
|
|
1644
|
+
cancelLabel = "Cancel",
|
|
1645
|
+
resetLabel = "Reset",
|
|
1646
|
+
showReset = true,
|
|
1647
|
+
showCancel = true,
|
|
1648
|
+
tone,
|
|
1649
|
+
className,
|
|
1650
|
+
formClassName,
|
|
1651
|
+
loading = false,
|
|
1652
|
+
disableSubmitWhenInvalid = true,
|
|
1653
|
+
closeOnSubmit = true,
|
|
1654
|
+
closeOnCancel = true,
|
|
1655
|
+
onSubmit,
|
|
1656
|
+
onReset,
|
|
1657
|
+
onCancel,
|
|
1658
|
+
customValidation
|
|
1659
|
+
}) {
|
|
1660
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React15.useState(defaultOpen);
|
|
1661
|
+
const isControlled = typeof open === "boolean";
|
|
1662
|
+
const isOpen = isControlled ? open : uncontrolledOpen;
|
|
1663
|
+
const setOpen = React15.useCallback(
|
|
1664
|
+
(next) => {
|
|
1665
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
1666
|
+
onOpenChange == null ? void 0 : onOpenChange(next);
|
|
1667
|
+
},
|
|
1668
|
+
[isControlled, onOpenChange]
|
|
1669
|
+
);
|
|
1670
|
+
const defaultValues = React15.useMemo(
|
|
1671
|
+
() => buildDefaultValues(fields, initialData),
|
|
1672
|
+
[fields, initialData]
|
|
1673
|
+
);
|
|
1674
|
+
const form = (0, import_react_hook_form4.useForm)({
|
|
1675
|
+
mode: "onChange",
|
|
1676
|
+
defaultValues
|
|
1677
|
+
});
|
|
1678
|
+
const formId = React15.useId();
|
|
1679
|
+
React15.useEffect(() => {
|
|
1680
|
+
form.reset(defaultValues);
|
|
1681
|
+
}, [defaultValues, form]);
|
|
1682
|
+
const handleSubmit = form.handleSubmit(async (values) => {
|
|
1683
|
+
if (customValidation) {
|
|
1684
|
+
const customErrors = customValidation(values);
|
|
1685
|
+
if (customErrors && Object.keys(customErrors).length > 0) {
|
|
1686
|
+
Object.entries(customErrors).forEach(([key, message]) => {
|
|
1687
|
+
if (message) {
|
|
1688
|
+
form.setError(key, {
|
|
1689
|
+
type: "custom",
|
|
1690
|
+
message: String(message)
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
});
|
|
1694
|
+
return;
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
await onSubmit(values);
|
|
1698
|
+
if (closeOnSubmit) setOpen(false);
|
|
1699
|
+
});
|
|
1700
|
+
const handleReset = () => {
|
|
1701
|
+
form.reset(defaultValues);
|
|
1702
|
+
onReset == null ? void 0 : onReset();
|
|
1703
|
+
};
|
|
1704
|
+
const handleCancel = () => {
|
|
1705
|
+
onCancel == null ? void 0 : onCancel();
|
|
1706
|
+
if (closeOnCancel) setOpen(false);
|
|
1707
|
+
};
|
|
1708
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_hook_form4.FormProvider, { ...form, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1709
|
+
CraftModal,
|
|
1710
|
+
{
|
|
1711
|
+
open: isOpen,
|
|
1712
|
+
onOpenChange: setOpen,
|
|
1713
|
+
trigger,
|
|
1714
|
+
title,
|
|
1715
|
+
description,
|
|
1716
|
+
tone,
|
|
1717
|
+
className,
|
|
1718
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-wrap items-center justify-end gap-3", children: [
|
|
1719
|
+
showReset && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1720
|
+
CraftButton,
|
|
1721
|
+
{
|
|
1722
|
+
type: "button",
|
|
1723
|
+
variant: "outline",
|
|
1724
|
+
onClick: handleReset,
|
|
1725
|
+
disabled: loading,
|
|
1726
|
+
children: resetLabel
|
|
1727
|
+
}
|
|
1728
|
+
),
|
|
1729
|
+
showCancel && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1730
|
+
CraftButton,
|
|
1731
|
+
{
|
|
1732
|
+
type: "button",
|
|
1733
|
+
variant: "ghost",
|
|
1734
|
+
onClick: handleCancel,
|
|
1735
|
+
disabled: loading,
|
|
1736
|
+
children: cancelLabel
|
|
1737
|
+
}
|
|
1738
|
+
),
|
|
1739
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1740
|
+
CraftSubmitButton,
|
|
1741
|
+
{
|
|
1742
|
+
loading,
|
|
1743
|
+
disableWhenInvalid: disableSubmitWhenInvalid,
|
|
1744
|
+
form: formId,
|
|
1745
|
+
children: submitLabel
|
|
1746
|
+
}
|
|
1747
|
+
)
|
|
1748
|
+
] }),
|
|
1749
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1750
|
+
"form",
|
|
1751
|
+
{
|
|
1752
|
+
id: formId,
|
|
1753
|
+
onSubmit: handleSubmit,
|
|
1754
|
+
className: cn("space-y-5", formClassName),
|
|
1755
|
+
children: fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "space-y-2", children: [
|
|
1756
|
+
field.helpText && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-xs text-[rgb(var(--nc-fg-muted))]", children: field.helpText }),
|
|
1757
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1758
|
+
CraftFormField,
|
|
1759
|
+
{
|
|
1760
|
+
name: field.name,
|
|
1761
|
+
label: field.label,
|
|
1762
|
+
description: field.description,
|
|
1763
|
+
type: field.type,
|
|
1764
|
+
placeholder: field.placeholder,
|
|
1765
|
+
options: field.options,
|
|
1766
|
+
tone,
|
|
1767
|
+
disabled: field.disabled || loading,
|
|
1768
|
+
rules: buildRules(field, form.getValues),
|
|
1769
|
+
fieldProps: {
|
|
1770
|
+
min: field.min,
|
|
1771
|
+
max: field.max,
|
|
1772
|
+
step: field.step,
|
|
1773
|
+
rows: field.rows,
|
|
1774
|
+
accept: field.accept,
|
|
1775
|
+
multiple: field.type === "multifile",
|
|
1776
|
+
...field.fieldProps
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
)
|
|
1780
|
+
] }, field.name))
|
|
1781
|
+
}
|
|
1782
|
+
)
|
|
1783
|
+
}
|
|
1784
|
+
) });
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
// src/components/craft-confirm-dialog.tsx
|
|
1788
|
+
var React16 = __toESM(require("react"), 1);
|
|
1789
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1790
|
+
function CraftConfirmDialog({
|
|
1791
|
+
open,
|
|
1792
|
+
defaultOpen = false,
|
|
1793
|
+
onOpenChange,
|
|
1794
|
+
tone,
|
|
1795
|
+
title = "Confirm action",
|
|
1796
|
+
description,
|
|
1797
|
+
confirmLabel = "Confirm",
|
|
1798
|
+
cancelLabel = "Cancel",
|
|
1799
|
+
onConfirm,
|
|
1800
|
+
trigger,
|
|
1801
|
+
className,
|
|
1802
|
+
confirmVariant = "solid"
|
|
1803
|
+
}) {
|
|
1804
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React16.useState(defaultOpen);
|
|
1805
|
+
const isControlled = typeof open === "boolean";
|
|
1806
|
+
const isOpen = isControlled ? open : uncontrolledOpen;
|
|
1807
|
+
const setOpen = React16.useCallback(
|
|
1808
|
+
(next) => {
|
|
1809
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
1810
|
+
onOpenChange == null ? void 0 : onOpenChange(next);
|
|
1811
|
+
},
|
|
1812
|
+
[isControlled, onOpenChange]
|
|
1813
|
+
);
|
|
1814
|
+
const [isLoading, setIsLoading] = React16.useState(false);
|
|
1815
|
+
const handleConfirm = async () => {
|
|
1816
|
+
if (!onConfirm) {
|
|
1817
|
+
setOpen(false);
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1820
|
+
setIsLoading(true);
|
|
1821
|
+
await onConfirm();
|
|
1822
|
+
setIsLoading(false);
|
|
1823
|
+
setOpen(false);
|
|
1824
|
+
};
|
|
1825
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1826
|
+
CraftModal,
|
|
1827
|
+
{
|
|
1828
|
+
open: isOpen,
|
|
1829
|
+
onOpenChange: setOpen,
|
|
1830
|
+
trigger,
|
|
1831
|
+
title,
|
|
1832
|
+
description,
|
|
1833
|
+
tone,
|
|
1834
|
+
className: cn("max-w-md", className),
|
|
1835
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-wrap items-center justify-end gap-3", children: [
|
|
1836
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1837
|
+
CraftButton,
|
|
1838
|
+
{
|
|
1839
|
+
type: "button",
|
|
1840
|
+
variant: "ghost",
|
|
1841
|
+
onClick: () => setOpen(false),
|
|
1842
|
+
children: cancelLabel
|
|
1843
|
+
}
|
|
1844
|
+
),
|
|
1845
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1846
|
+
CraftButton,
|
|
1847
|
+
{
|
|
1848
|
+
type: "button",
|
|
1849
|
+
variant: confirmVariant,
|
|
1850
|
+
disabled: isLoading,
|
|
1851
|
+
onClick: handleConfirm,
|
|
1852
|
+
children: isLoading ? "Working..." : confirmLabel
|
|
1853
|
+
}
|
|
1854
|
+
)
|
|
1855
|
+
] }),
|
|
1856
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: description })
|
|
1857
|
+
}
|
|
1858
|
+
);
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
// src/components/craft-create-edit-drawer.tsx
|
|
1862
|
+
var React17 = __toESM(require("react"), 1);
|
|
1863
|
+
var import_react_hook_form5 = require("react-hook-form");
|
|
1864
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1865
|
+
function CraftCreateEditDrawer({
|
|
1866
|
+
mode = "create",
|
|
1867
|
+
form,
|
|
1868
|
+
onSubmit,
|
|
1869
|
+
open,
|
|
1870
|
+
defaultOpen = false,
|
|
1871
|
+
onOpenChange,
|
|
1872
|
+
trigger,
|
|
1873
|
+
title,
|
|
1874
|
+
description,
|
|
1875
|
+
submitLabel,
|
|
1876
|
+
cancelLabel = "Cancel",
|
|
1877
|
+
tone,
|
|
1878
|
+
className,
|
|
1879
|
+
children,
|
|
1880
|
+
footer,
|
|
1881
|
+
disableSubmitWhenInvalid = true,
|
|
1882
|
+
closeOnSubmit = true,
|
|
1883
|
+
side = "right"
|
|
1884
|
+
}) {
|
|
1885
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React17.useState(defaultOpen);
|
|
1886
|
+
const isControlled = typeof open === "boolean";
|
|
1887
|
+
const isOpen = isControlled ? open : uncontrolledOpen;
|
|
1888
|
+
const setOpen = React17.useCallback(
|
|
1889
|
+
(next) => {
|
|
1890
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
1891
|
+
onOpenChange == null ? void 0 : onOpenChange(next);
|
|
1892
|
+
},
|
|
1893
|
+
[isControlled, onOpenChange]
|
|
1894
|
+
);
|
|
1895
|
+
const formId = React17.useId();
|
|
1896
|
+
const handleSubmit = form.handleSubmit(async (values) => {
|
|
1897
|
+
await onSubmit(values);
|
|
1898
|
+
if (closeOnSubmit) setOpen(false);
|
|
1899
|
+
});
|
|
1900
|
+
const resolvedTitle = title != null ? title : mode === "create" ? "Create item" : "Edit item";
|
|
1901
|
+
const resolvedSubmitLabel = submitLabel != null ? submitLabel : mode === "create" ? "Create" : "Save changes";
|
|
1902
|
+
const footerContent = footer != null ? footer : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-wrap items-center justify-end gap-3", children: [
|
|
1903
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(CraftButton, { type: "button", variant: "ghost", onClick: () => setOpen(false), children: cancelLabel }),
|
|
1904
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1905
|
+
CraftSubmitButton,
|
|
1906
|
+
{
|
|
1907
|
+
form: formId,
|
|
1908
|
+
disableWhenInvalid: disableSubmitWhenInvalid,
|
|
1909
|
+
children: resolvedSubmitLabel
|
|
1910
|
+
}
|
|
1911
|
+
)
|
|
1912
|
+
] });
|
|
1913
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_hook_form5.FormProvider, { ...form, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1914
|
+
CraftDrawer,
|
|
1915
|
+
{
|
|
1916
|
+
open: isOpen,
|
|
1917
|
+
onOpenChange: setOpen,
|
|
1918
|
+
trigger,
|
|
1919
|
+
title: resolvedTitle,
|
|
1920
|
+
tone,
|
|
1921
|
+
side,
|
|
1922
|
+
className: cn("flex flex-col", className),
|
|
1923
|
+
footer: footerContent,
|
|
1924
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("form", { id: formId, onSubmit: handleSubmit, className: "space-y-5", children: [
|
|
1925
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: description }),
|
|
1926
|
+
children
|
|
1927
|
+
] })
|
|
1928
|
+
}
|
|
1929
|
+
) });
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
// src/components/craft-filter-bar.tsx
|
|
1933
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1934
|
+
function CraftFilterBar({
|
|
1935
|
+
title,
|
|
1936
|
+
description,
|
|
1937
|
+
searchValue,
|
|
1938
|
+
onSearchChange,
|
|
1939
|
+
searchPlaceholder = "Search...",
|
|
1940
|
+
actions,
|
|
1941
|
+
filters,
|
|
1942
|
+
tone,
|
|
1943
|
+
className
|
|
1944
|
+
}) {
|
|
1945
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
1946
|
+
"div",
|
|
1947
|
+
{
|
|
1948
|
+
className: cn(
|
|
1949
|
+
"rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] p-4 text-[rgb(var(--nc-fg))] shadow-[0_12px_36px_rgba(0,0,0,0.2)] backdrop-blur-2xl",
|
|
1950
|
+
className
|
|
1951
|
+
),
|
|
1952
|
+
"data-nc-theme": tone,
|
|
1953
|
+
children: [
|
|
1954
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [
|
|
1955
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { children: [
|
|
1956
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h3", { className: "text-lg font-semibold", children: title }),
|
|
1957
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: description })
|
|
1958
|
+
] }),
|
|
1959
|
+
actions && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex items-center gap-3", children: actions })
|
|
1960
|
+
] }),
|
|
1961
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "mt-4 grid gap-4 md:grid-cols-[minmax(0,1fr)_auto]", children: [
|
|
1962
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1963
|
+
CraftInput,
|
|
1964
|
+
{
|
|
1965
|
+
type: "search",
|
|
1966
|
+
placeholder: searchPlaceholder,
|
|
1967
|
+
value: searchValue != null ? searchValue : "",
|
|
1968
|
+
onChange: (event) => onSearchChange == null ? void 0 : onSearchChange(event.target.value),
|
|
1969
|
+
tone
|
|
1970
|
+
}
|
|
1971
|
+
),
|
|
1972
|
+
filters && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex flex-wrap items-center gap-3", children: filters })
|
|
1973
|
+
] })
|
|
1974
|
+
]
|
|
1975
|
+
}
|
|
1976
|
+
);
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
// src/components/craft-data-table.tsx
|
|
1980
|
+
var React18 = __toESM(require("react"), 1);
|
|
1981
|
+
|
|
1982
|
+
// src/components/craft-pagination.tsx
|
|
1983
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1984
|
+
function getPageNumbers(pageIndex, pageCount, maxButtons = 5) {
|
|
1985
|
+
if (pageCount <= maxButtons) {
|
|
1986
|
+
return Array.from({ length: pageCount }, (_, i) => i);
|
|
1987
|
+
}
|
|
1988
|
+
const pages = [];
|
|
1989
|
+
const start = Math.max(0, pageIndex - 1);
|
|
1990
|
+
const end = Math.min(pageCount - 1, pageIndex + 1);
|
|
1991
|
+
pages.push(0);
|
|
1992
|
+
if (start > 1) pages.push("ellipsis");
|
|
1993
|
+
for (let i = start; i <= end; i += 1) {
|
|
1994
|
+
if (i !== 0 && i !== pageCount - 1) pages.push(i);
|
|
1995
|
+
}
|
|
1996
|
+
if (end < pageCount - 2) pages.push("ellipsis");
|
|
1997
|
+
pages.push(pageCount - 1);
|
|
1998
|
+
return pages;
|
|
1999
|
+
}
|
|
2000
|
+
function CraftPagination({
|
|
2001
|
+
pageIndex,
|
|
2002
|
+
pageCount,
|
|
2003
|
+
onPageChange,
|
|
2004
|
+
canPrevious = pageIndex > 0,
|
|
2005
|
+
canNext = pageIndex < pageCount - 1,
|
|
2006
|
+
pageSize,
|
|
2007
|
+
pageSizeOptions = [10, 20, 50],
|
|
2008
|
+
onPageSizeChange,
|
|
2009
|
+
tone,
|
|
2010
|
+
className
|
|
2011
|
+
}) {
|
|
2012
|
+
const pages = getPageNumbers(pageIndex, pageCount);
|
|
2013
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
2014
|
+
"div",
|
|
2015
|
+
{
|
|
2016
|
+
className: cn(
|
|
2017
|
+
"flex flex-wrap items-center justify-between gap-4",
|
|
2018
|
+
className
|
|
2019
|
+
),
|
|
2020
|
+
"data-nc-theme": tone,
|
|
2021
|
+
children: [
|
|
2022
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2023
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2024
|
+
"button",
|
|
2025
|
+
{
|
|
2026
|
+
type: "button",
|
|
2027
|
+
className: cn(
|
|
2028
|
+
"rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-2 text-xs text-[rgb(var(--nc-fg))] transition",
|
|
2029
|
+
"hover:bg-[rgb(var(--nc-surface)/0.2)]",
|
|
2030
|
+
!canPrevious && "opacity-50 cursor-not-allowed"
|
|
2031
|
+
),
|
|
2032
|
+
onClick: () => onPageChange(Math.max(pageIndex - 1, 0)),
|
|
2033
|
+
disabled: !canPrevious,
|
|
2034
|
+
children: "Prev"
|
|
2035
|
+
}
|
|
2036
|
+
),
|
|
2037
|
+
pages.map(
|
|
2038
|
+
(page, index) => page === "ellipsis" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "px-2 text-[rgb(var(--nc-fg-muted))]", children: "..." }, `ellipsis-${index}`) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2039
|
+
"button",
|
|
2040
|
+
{
|
|
2041
|
+
type: "button",
|
|
2042
|
+
className: cn(
|
|
2043
|
+
"rounded-xl border px-3 py-2 text-xs transition",
|
|
2044
|
+
page === pageIndex ? "border-[rgb(var(--nc-accent-1)/0.6)] bg-[rgb(var(--nc-accent-1)/0.2)] text-[rgb(var(--nc-fg))]" : "border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] text-[rgb(var(--nc-fg-muted))] hover:text-[rgb(var(--nc-fg))] hover:bg-[rgb(var(--nc-surface)/0.2)]"
|
|
2045
|
+
),
|
|
2046
|
+
onClick: () => onPageChange(page),
|
|
2047
|
+
children: page + 1
|
|
2048
|
+
},
|
|
2049
|
+
page
|
|
2050
|
+
)
|
|
2051
|
+
),
|
|
2052
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2053
|
+
"button",
|
|
2054
|
+
{
|
|
2055
|
+
type: "button",
|
|
2056
|
+
className: cn(
|
|
2057
|
+
"rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-2 text-xs text-[rgb(var(--nc-fg))] transition",
|
|
2058
|
+
"hover:bg-[rgb(var(--nc-surface)/0.2)]",
|
|
2059
|
+
!canNext && "opacity-50 cursor-not-allowed"
|
|
2060
|
+
),
|
|
2061
|
+
onClick: () => onPageChange(Math.min(pageIndex + 1, pageCount - 1)),
|
|
2062
|
+
disabled: !canNext,
|
|
2063
|
+
children: "Next"
|
|
2064
|
+
}
|
|
2065
|
+
)
|
|
2066
|
+
] }),
|
|
2067
|
+
onPageSizeChange && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2 text-xs text-[rgb(var(--nc-fg-muted))]", children: [
|
|
2068
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: "Rows" }),
|
|
2069
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2070
|
+
"select",
|
|
2071
|
+
{
|
|
2072
|
+
className: "rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-2 py-1 text-xs text-[rgb(var(--nc-fg))]",
|
|
2073
|
+
value: pageSize,
|
|
2074
|
+
onChange: (event) => onPageSizeChange(Number(event.target.value)),
|
|
2075
|
+
children: pageSizeOptions.map((size) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("option", { value: size, children: size }, size))
|
|
2076
|
+
}
|
|
2077
|
+
)
|
|
2078
|
+
] })
|
|
2079
|
+
]
|
|
2080
|
+
}
|
|
2081
|
+
);
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
// src/components/craft-data-table.tsx
|
|
2085
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
2086
|
+
function getColumnValue(column, row) {
|
|
2087
|
+
if (typeof column.accessor === "function") return column.accessor(row);
|
|
2088
|
+
const record = row;
|
|
2089
|
+
if (typeof column.accessor === "string") return record[column.accessor];
|
|
2090
|
+
return record[column.id];
|
|
2091
|
+
}
|
|
2092
|
+
function normalizeValue(value) {
|
|
2093
|
+
if (value === null || value === void 0) return "";
|
|
2094
|
+
if (typeof value === "number") return value;
|
|
2095
|
+
if (typeof value === "string") return value.toLowerCase();
|
|
2096
|
+
if (value instanceof Date) return value.getTime();
|
|
2097
|
+
return String(value).toLowerCase();
|
|
2098
|
+
}
|
|
2099
|
+
function CraftDataTable({
|
|
2100
|
+
data,
|
|
2101
|
+
columns,
|
|
2102
|
+
tone,
|
|
2103
|
+
className,
|
|
2104
|
+
loading = false,
|
|
2105
|
+
emptyState,
|
|
2106
|
+
toolbar,
|
|
2107
|
+
enableSorting = true,
|
|
2108
|
+
enableFiltering = true,
|
|
2109
|
+
enableColumnVisibility = true,
|
|
2110
|
+
enableRowSelection = true,
|
|
2111
|
+
enablePagination = true,
|
|
2112
|
+
showGlobalFilter,
|
|
2113
|
+
manualSorting = false,
|
|
2114
|
+
manualFiltering = false,
|
|
2115
|
+
manualPagination = false,
|
|
2116
|
+
sortBy,
|
|
2117
|
+
onSortChange,
|
|
2118
|
+
filters,
|
|
2119
|
+
onFiltersChange,
|
|
2120
|
+
globalFilter,
|
|
2121
|
+
onGlobalFilterChange,
|
|
2122
|
+
columnVisibility,
|
|
2123
|
+
onColumnVisibilityChange,
|
|
2124
|
+
selectedRowIds,
|
|
2125
|
+
onRowSelectionChange,
|
|
2126
|
+
getRowId,
|
|
2127
|
+
pageIndex,
|
|
2128
|
+
pageSize = 10,
|
|
2129
|
+
pageCount,
|
|
2130
|
+
onPageChange,
|
|
2131
|
+
onPageSizeChange
|
|
2132
|
+
}) {
|
|
2133
|
+
const [internalSort, setInternalSort] = React18.useState(null);
|
|
2134
|
+
const [internalFilters, setInternalFilters] = React18.useState({});
|
|
2135
|
+
const [internalGlobalFilter, setInternalGlobalFilter] = React18.useState("");
|
|
2136
|
+
const [internalVisibility, setInternalVisibility] = React18.useState(
|
|
2137
|
+
() => columns.reduce((acc, column) => {
|
|
2138
|
+
acc[column.id] = !column.hidden;
|
|
2139
|
+
return acc;
|
|
2140
|
+
}, {})
|
|
2141
|
+
);
|
|
2142
|
+
const [internalSelection, setInternalSelection] = React18.useState({});
|
|
2143
|
+
const [internalPageIndex, setInternalPageIndex] = React18.useState(0);
|
|
2144
|
+
const [showColumns, setShowColumns] = React18.useState(false);
|
|
2145
|
+
const resolvedSort = sortBy != null ? sortBy : internalSort;
|
|
2146
|
+
const resolvedFilters = filters != null ? filters : internalFilters;
|
|
2147
|
+
const resolvedGlobalFilter = globalFilter != null ? globalFilter : internalGlobalFilter;
|
|
2148
|
+
const resolvedVisibility = columnVisibility != null ? columnVisibility : internalVisibility;
|
|
2149
|
+
const resolvedSelection = selectedRowIds != null ? selectedRowIds : internalSelection;
|
|
2150
|
+
const resolvedPageIndex = pageIndex != null ? pageIndex : internalPageIndex;
|
|
2151
|
+
const setSort = (next) => {
|
|
2152
|
+
if (sortBy === void 0) setInternalSort(next);
|
|
2153
|
+
onSortChange == null ? void 0 : onSortChange(next);
|
|
2154
|
+
};
|
|
2155
|
+
const setFilters = (next) => {
|
|
2156
|
+
if (filters === void 0) setInternalFilters(next);
|
|
2157
|
+
onFiltersChange == null ? void 0 : onFiltersChange(next);
|
|
2158
|
+
};
|
|
2159
|
+
const setVisibility = (next) => {
|
|
2160
|
+
if (columnVisibility === void 0) setInternalVisibility(next);
|
|
2161
|
+
onColumnVisibilityChange == null ? void 0 : onColumnVisibilityChange(next);
|
|
2162
|
+
};
|
|
2163
|
+
const setSelection = (next) => {
|
|
2164
|
+
if (selectedRowIds === void 0) setInternalSelection(next);
|
|
2165
|
+
onRowSelectionChange == null ? void 0 : onRowSelectionChange(next);
|
|
2166
|
+
};
|
|
2167
|
+
const setPageIndex = React18.useCallback(
|
|
2168
|
+
(next) => {
|
|
2169
|
+
if (pageIndex === void 0) setInternalPageIndex(next);
|
|
2170
|
+
onPageChange == null ? void 0 : onPageChange(next);
|
|
2171
|
+
},
|
|
2172
|
+
[pageIndex, onPageChange]
|
|
2173
|
+
);
|
|
2174
|
+
const visibleColumns = columns.filter(
|
|
2175
|
+
(column) => resolvedVisibility[column.id] !== false
|
|
2176
|
+
);
|
|
2177
|
+
const filteredData = React18.useMemo(() => {
|
|
2178
|
+
if (manualFiltering) return data;
|
|
2179
|
+
const globalValue = resolvedGlobalFilter.trim();
|
|
2180
|
+
return data.filter((row) => {
|
|
2181
|
+
if (globalValue) {
|
|
2182
|
+
const matchesGlobal = columns.some((column) => {
|
|
2183
|
+
const value = normalizeValue(getColumnValue(column, row));
|
|
2184
|
+
return String(value).includes(globalValue.toLowerCase());
|
|
2185
|
+
});
|
|
2186
|
+
if (!matchesGlobal) return false;
|
|
2187
|
+
}
|
|
2188
|
+
return Object.entries(resolvedFilters).every(([columnId, value]) => {
|
|
2189
|
+
if (!value) return true;
|
|
2190
|
+
const column = columns.find((col) => col.id === columnId);
|
|
2191
|
+
if (!column) return true;
|
|
2192
|
+
const cellValue = normalizeValue(getColumnValue(column, row));
|
|
2193
|
+
return String(cellValue).includes(value.toLowerCase());
|
|
2194
|
+
});
|
|
2195
|
+
});
|
|
2196
|
+
}, [columns, data, manualFiltering, resolvedFilters, resolvedGlobalFilter]);
|
|
2197
|
+
const sortedData = React18.useMemo(() => {
|
|
2198
|
+
if (manualSorting || !resolvedSort) return filteredData;
|
|
2199
|
+
const column = columns.find((col) => col.id === resolvedSort.id);
|
|
2200
|
+
if (!column) return filteredData;
|
|
2201
|
+
const sorted = [...filteredData].sort((a, b) => {
|
|
2202
|
+
const valueA = normalizeValue(getColumnValue(column, a));
|
|
2203
|
+
const valueB = normalizeValue(getColumnValue(column, b));
|
|
2204
|
+
if (typeof valueA === "number" && typeof valueB === "number") {
|
|
2205
|
+
return valueA - valueB;
|
|
2206
|
+
}
|
|
2207
|
+
return String(valueA).localeCompare(String(valueB));
|
|
2208
|
+
});
|
|
2209
|
+
return resolvedSort.desc ? sorted.reverse() : sorted;
|
|
2210
|
+
}, [columns, filteredData, manualSorting, resolvedSort]);
|
|
2211
|
+
const resolvedPageCount = manualPagination ? Math.max(pageCount != null ? pageCount : 1, 1) : Math.max(Math.ceil(sortedData.length / pageSize), 1);
|
|
2212
|
+
React18.useEffect(() => {
|
|
2213
|
+
if (resolvedPageIndex > resolvedPageCount - 1) {
|
|
2214
|
+
setPageIndex(Math.max(resolvedPageCount - 1, 0));
|
|
2215
|
+
}
|
|
2216
|
+
}, [resolvedPageCount, resolvedPageIndex, setPageIndex]);
|
|
2217
|
+
const pagedData = React18.useMemo(() => {
|
|
2218
|
+
if (!enablePagination || manualPagination) return sortedData;
|
|
2219
|
+
const start = resolvedPageIndex * pageSize;
|
|
2220
|
+
return sortedData.slice(start, start + pageSize);
|
|
2221
|
+
}, [enablePagination, manualPagination, pageSize, resolvedPageIndex, sortedData]);
|
|
2222
|
+
const rowIdFor = React18.useCallback(
|
|
2223
|
+
(row, index) => {
|
|
2224
|
+
var _a;
|
|
2225
|
+
return (_a = getRowId == null ? void 0 : getRowId(row, index)) != null ? _a : String(index);
|
|
2226
|
+
},
|
|
2227
|
+
[getRowId]
|
|
2228
|
+
);
|
|
2229
|
+
const pageStartIndex = enablePagination && !manualPagination ? resolvedPageIndex * pageSize : 0;
|
|
2230
|
+
const pageRowIds = pagedData.map(
|
|
2231
|
+
(row, index) => rowIdFor(row, pageStartIndex + index)
|
|
2232
|
+
);
|
|
2233
|
+
const allSelected = pageRowIds.length > 0 && pageRowIds.every((id) => resolvedSelection[id]);
|
|
2234
|
+
const someSelected = pageRowIds.some((id) => resolvedSelection[id]);
|
|
2235
|
+
const headerCheckboxRef = React18.useRef(null);
|
|
2236
|
+
React18.useEffect(() => {
|
|
2237
|
+
if (headerCheckboxRef.current) {
|
|
2238
|
+
headerCheckboxRef.current.indeterminate = someSelected && !allSelected;
|
|
2239
|
+
}
|
|
2240
|
+
}, [someSelected, allSelected]);
|
|
2241
|
+
const toggleSort = (column) => {
|
|
2242
|
+
if (!enableSorting || column.sortable === false) return;
|
|
2243
|
+
const current = resolvedSort;
|
|
2244
|
+
if (!current || current.id !== column.id) {
|
|
2245
|
+
setSort({ id: column.id, desc: false });
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
2248
|
+
if (!current.desc) {
|
|
2249
|
+
setSort({ id: column.id, desc: true });
|
|
2250
|
+
return;
|
|
2251
|
+
}
|
|
2252
|
+
setSort(null);
|
|
2253
|
+
};
|
|
2254
|
+
const emptyContent = emptyState != null ? emptyState : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "text-center text-sm text-[rgb(var(--nc-fg-muted))]", children: "No results found." });
|
|
2255
|
+
const resolvedShowGlobalFilter = showGlobalFilter != null ? showGlobalFilter : enableFiltering && !toolbar;
|
|
2256
|
+
const setGlobalFilter = (next) => {
|
|
2257
|
+
if (globalFilter === void 0) setInternalGlobalFilter(next);
|
|
2258
|
+
onGlobalFilterChange == null ? void 0 : onGlobalFilterChange(next);
|
|
2259
|
+
};
|
|
2260
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: cn("space-y-4", className), "data-nc-theme": tone, children: [
|
|
2261
|
+
toolbar,
|
|
2262
|
+
resolvedShowGlobalFilter && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center justify-between gap-3 rounded-2xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-2 text-sm text-[rgb(var(--nc-fg))]", children: [
|
|
2263
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-xs text-[rgb(var(--nc-fg-muted))]", children: "Global filter" }),
|
|
2264
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2265
|
+
"input",
|
|
2266
|
+
{
|
|
2267
|
+
type: "search",
|
|
2268
|
+
value: resolvedGlobalFilter,
|
|
2269
|
+
onChange: (event) => setGlobalFilter(event.target.value),
|
|
2270
|
+
placeholder: "Search all columns...",
|
|
2271
|
+
className: "w-full max-w-xs rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.18)] px-3 py-2 text-xs text-[rgb(var(--nc-fg))]"
|
|
2272
|
+
}
|
|
2273
|
+
)
|
|
2274
|
+
] }),
|
|
2275
|
+
enableColumnVisibility && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "relative flex justify-end", children: [
|
|
2276
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2277
|
+
"button",
|
|
2278
|
+
{
|
|
2279
|
+
type: "button",
|
|
2280
|
+
className: "rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-2 text-xs text-[rgb(var(--nc-fg))] transition hover:bg-[rgb(var(--nc-surface)/0.2)]",
|
|
2281
|
+
onClick: () => setShowColumns((prev) => !prev),
|
|
2282
|
+
children: "Columns"
|
|
2283
|
+
}
|
|
2284
|
+
),
|
|
2285
|
+
showColumns && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "absolute right-0 top-10 z-20 w-48 rounded-2xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.2)] p-3 shadow-[0_12px_30px_rgba(0,0,0,0.35)] backdrop-blur-2xl", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "grid gap-2", children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
2286
|
+
"label",
|
|
2287
|
+
{
|
|
2288
|
+
className: "flex items-center gap-2 text-xs text-[rgb(var(--nc-fg))]",
|
|
2289
|
+
children: [
|
|
2290
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2291
|
+
"input",
|
|
2292
|
+
{
|
|
2293
|
+
type: "checkbox",
|
|
2294
|
+
className: "h-4 w-4 accent-[rgb(var(--nc-accent-1))]",
|
|
2295
|
+
checked: resolvedVisibility[column.id] !== false,
|
|
2296
|
+
onChange: (event) => setVisibility({
|
|
2297
|
+
...resolvedVisibility,
|
|
2298
|
+
[column.id]: event.target.checked
|
|
2299
|
+
})
|
|
2300
|
+
}
|
|
2301
|
+
),
|
|
2302
|
+
column.header
|
|
2303
|
+
]
|
|
2304
|
+
},
|
|
2305
|
+
column.id
|
|
2306
|
+
)) }) })
|
|
2307
|
+
] }),
|
|
2308
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "overflow-hidden rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] shadow-[0_18px_50px_rgba(0,0,0,0.35)] backdrop-blur-2xl", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("table", { className: "w-full border-collapse text-left text-sm", children: [
|
|
2309
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("thead", { className: "bg-[rgb(var(--nc-surface)/0.12)] text-[rgb(var(--nc-fg-muted))]", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("tr", { children: [
|
|
2310
|
+
enableRowSelection && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { className: "w-12 px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2311
|
+
"input",
|
|
2312
|
+
{
|
|
2313
|
+
ref: headerCheckboxRef,
|
|
2314
|
+
type: "checkbox",
|
|
2315
|
+
className: "h-4 w-4 accent-[rgb(var(--nc-accent-1))]",
|
|
2316
|
+
checked: allSelected,
|
|
2317
|
+
onChange: (event) => {
|
|
2318
|
+
const next = { ...resolvedSelection };
|
|
2319
|
+
pageRowIds.forEach((id) => {
|
|
2320
|
+
next[id] = event.target.checked;
|
|
2321
|
+
});
|
|
2322
|
+
setSelection(next);
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
) }),
|
|
2326
|
+
visibleColumns.map((column) => {
|
|
2327
|
+
var _a;
|
|
2328
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
2329
|
+
"th",
|
|
2330
|
+
{
|
|
2331
|
+
className: cn(
|
|
2332
|
+
"px-4 py-3 text-xs font-semibold uppercase tracking-[0.2em]",
|
|
2333
|
+
column.headerClassName
|
|
2334
|
+
),
|
|
2335
|
+
style: { width: column.width },
|
|
2336
|
+
children: [
|
|
2337
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
2338
|
+
"button",
|
|
2339
|
+
{
|
|
2340
|
+
type: "button",
|
|
2341
|
+
className: cn(
|
|
2342
|
+
"flex items-center gap-2",
|
|
2343
|
+
enableSorting && column.sortable !== false ? "cursor-pointer" : "cursor-default"
|
|
2344
|
+
),
|
|
2345
|
+
onClick: () => toggleSort(column),
|
|
2346
|
+
children: [
|
|
2347
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { children: column.header }),
|
|
2348
|
+
(resolvedSort == null ? void 0 : resolvedSort.id) === column.id && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-[rgb(var(--nc-accent-1))]", children: resolvedSort.desc ? "\u2193" : "\u2191" })
|
|
2349
|
+
]
|
|
2350
|
+
}
|
|
2351
|
+
),
|
|
2352
|
+
enableFiltering && column.filterable !== false && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2353
|
+
"input",
|
|
2354
|
+
{
|
|
2355
|
+
type: "text",
|
|
2356
|
+
value: (_a = resolvedFilters[column.id]) != null ? _a : "",
|
|
2357
|
+
onChange: (event) => setFilters({
|
|
2358
|
+
...resolvedFilters,
|
|
2359
|
+
[column.id]: event.target.value
|
|
2360
|
+
}),
|
|
2361
|
+
placeholder: "Filter",
|
|
2362
|
+
className: "mt-2 w-full rounded-xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.18)] px-2 py-1 text-xs text-[rgb(var(--nc-fg))]"
|
|
2363
|
+
}
|
|
2364
|
+
)
|
|
2365
|
+
]
|
|
2366
|
+
},
|
|
2367
|
+
column.id
|
|
2368
|
+
);
|
|
2369
|
+
})
|
|
2370
|
+
] }) }),
|
|
2371
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("tbody", { className: "text-[rgb(var(--nc-fg))]", children: [
|
|
2372
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2373
|
+
"td",
|
|
2374
|
+
{
|
|
2375
|
+
colSpan: visibleColumns.length + (enableRowSelection ? 1 : 0),
|
|
2376
|
+
className: "px-4 py-10 text-center text-sm text-[rgb(var(--nc-fg-muted))]",
|
|
2377
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "inline-flex items-center gap-2", children: [
|
|
2378
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "h-4 w-4 animate-spin rounded-full border-2 border-[rgb(var(--nc-fg-muted))] border-t-transparent" }),
|
|
2379
|
+
"Loading data..."
|
|
2380
|
+
] })
|
|
2381
|
+
}
|
|
2382
|
+
) }),
|
|
2383
|
+
!loading && pagedData.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2384
|
+
"td",
|
|
2385
|
+
{
|
|
2386
|
+
colSpan: visibleColumns.length + (enableRowSelection ? 1 : 0),
|
|
2387
|
+
className: "px-4 py-10",
|
|
2388
|
+
children: emptyContent
|
|
2389
|
+
}
|
|
2390
|
+
) }),
|
|
2391
|
+
!loading && pagedData.map((row, rowIndex) => {
|
|
2392
|
+
const rowId = rowIdFor(row, pageStartIndex + rowIndex);
|
|
2393
|
+
const isSelected = resolvedSelection[rowId];
|
|
2394
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
2395
|
+
"tr",
|
|
2396
|
+
{
|
|
2397
|
+
className: cn(
|
|
2398
|
+
"border-t border-[rgb(var(--nc-border)/0.15)]",
|
|
2399
|
+
isSelected && "bg-[rgb(var(--nc-accent-1)/0.08)]"
|
|
2400
|
+
),
|
|
2401
|
+
children: [
|
|
2402
|
+
enableRowSelection && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "px-4 py-4", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2403
|
+
"input",
|
|
2404
|
+
{
|
|
2405
|
+
type: "checkbox",
|
|
2406
|
+
className: "h-4 w-4 accent-[rgb(var(--nc-accent-1))]",
|
|
2407
|
+
checked: isSelected,
|
|
2408
|
+
onChange: (event) => setSelection({
|
|
2409
|
+
...resolvedSelection,
|
|
2410
|
+
[rowId]: event.target.checked
|
|
2411
|
+
})
|
|
2412
|
+
}
|
|
2413
|
+
) }),
|
|
2414
|
+
visibleColumns.map((column) => {
|
|
2415
|
+
var _a;
|
|
2416
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2417
|
+
"td",
|
|
2418
|
+
{
|
|
2419
|
+
className: cn(
|
|
2420
|
+
"px-4 py-4",
|
|
2421
|
+
column.align === "center" && "text-center",
|
|
2422
|
+
column.align === "right" && "text-right",
|
|
2423
|
+
column.cellClassName
|
|
2424
|
+
),
|
|
2425
|
+
children: column.cell ? column.cell(row) : String((_a = getColumnValue(column, row)) != null ? _a : "")
|
|
2426
|
+
},
|
|
2427
|
+
column.id
|
|
2428
|
+
);
|
|
2429
|
+
})
|
|
2430
|
+
]
|
|
2431
|
+
},
|
|
2432
|
+
rowId
|
|
2433
|
+
);
|
|
2434
|
+
})
|
|
2435
|
+
] })
|
|
2436
|
+
] }) }),
|
|
2437
|
+
enablePagination && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2438
|
+
CraftPagination,
|
|
2439
|
+
{
|
|
2440
|
+
pageIndex: resolvedPageIndex,
|
|
2441
|
+
pageCount: resolvedPageCount,
|
|
2442
|
+
onPageChange: setPageIndex,
|
|
2443
|
+
pageSize,
|
|
2444
|
+
onPageSizeChange,
|
|
2445
|
+
tone
|
|
2446
|
+
}
|
|
2447
|
+
)
|
|
2448
|
+
] });
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2451
|
+
// src/components/layout/app-shell.tsx
|
|
2452
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
2453
|
+
function AppShell({ className, sidebar, topNav, children, ...props }) {
|
|
2454
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
1108
2455
|
"div",
|
|
1109
2456
|
{
|
|
1110
2457
|
className: cn(
|
|
@@ -1113,10 +2460,10 @@ function AppShell({ className, sidebar, topNav, children, ...props }) {
|
|
|
1113
2460
|
),
|
|
1114
2461
|
...props,
|
|
1115
2462
|
children: [
|
|
1116
|
-
sidebar && /* @__PURE__ */ (0,
|
|
1117
|
-
/* @__PURE__ */ (0,
|
|
1118
|
-
topNav,
|
|
1119
|
-
/* @__PURE__ */ (0,
|
|
2463
|
+
sidebar && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "h-full lg:sticky lg:top-6 lg:self-start lg:max-h-[calc(100vh-3rem)] lg:overflow-y-auto", children: sidebar }),
|
|
2464
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-6", children: [
|
|
2465
|
+
topNav && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "lg:sticky lg:top-6 lg:z-20", children: topNav }),
|
|
2466
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("main", { className: "flex-1", children })
|
|
1120
2467
|
] })
|
|
1121
2468
|
]
|
|
1122
2469
|
}
|
|
@@ -1124,9 +2471,9 @@ function AppShell({ className, sidebar, topNav, children, ...props }) {
|
|
|
1124
2471
|
}
|
|
1125
2472
|
|
|
1126
2473
|
// src/components/layout/sidebar.tsx
|
|
1127
|
-
var
|
|
2474
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1128
2475
|
function Sidebar({ className, title, items, footer, ...props }) {
|
|
1129
|
-
return /* @__PURE__ */ (0,
|
|
2476
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
1130
2477
|
"aside",
|
|
1131
2478
|
{
|
|
1132
2479
|
className: cn(
|
|
@@ -1135,10 +2482,10 @@ function Sidebar({ className, title, items, footer, ...props }) {
|
|
|
1135
2482
|
),
|
|
1136
2483
|
...props,
|
|
1137
2484
|
children: [
|
|
1138
|
-
title && /* @__PURE__ */ (0,
|
|
1139
|
-
/* @__PURE__ */ (0,
|
|
2485
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "text-lg font-semibold", children: title }),
|
|
2486
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("nav", { className: "flex flex-col gap-2", children: items.map((item, index) => {
|
|
1140
2487
|
var _a;
|
|
1141
|
-
return /* @__PURE__ */ (0,
|
|
2488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
1142
2489
|
"a",
|
|
1143
2490
|
{
|
|
1144
2491
|
href: (_a = item.href) != null ? _a : "#",
|
|
@@ -1148,22 +2495,22 @@ function Sidebar({ className, title, items, footer, ...props }) {
|
|
|
1148
2495
|
),
|
|
1149
2496
|
children: [
|
|
1150
2497
|
item.icon,
|
|
1151
|
-
/* @__PURE__ */ (0,
|
|
2498
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { children: item.label })
|
|
1152
2499
|
]
|
|
1153
2500
|
},
|
|
1154
2501
|
`${item.label}-${index}`
|
|
1155
2502
|
);
|
|
1156
2503
|
}) }),
|
|
1157
|
-
footer && /* @__PURE__ */ (0,
|
|
2504
|
+
footer && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "mt-auto pt-4", children: footer })
|
|
1158
2505
|
]
|
|
1159
2506
|
}
|
|
1160
2507
|
);
|
|
1161
2508
|
}
|
|
1162
2509
|
|
|
1163
2510
|
// src/components/layout/top-nav.tsx
|
|
1164
|
-
var
|
|
2511
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1165
2512
|
function TopNav({ className, title, actions, breadcrumb, ...props }) {
|
|
1166
|
-
return /* @__PURE__ */ (0,
|
|
2513
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
1167
2514
|
"header",
|
|
1168
2515
|
{
|
|
1169
2516
|
className: cn(
|
|
@@ -1172,18 +2519,18 @@ function TopNav({ className, title, actions, breadcrumb, ...props }) {
|
|
|
1172
2519
|
),
|
|
1173
2520
|
...props,
|
|
1174
2521
|
children: [
|
|
1175
|
-
/* @__PURE__ */ (0,
|
|
2522
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "space-y-1", children: [
|
|
1176
2523
|
breadcrumb,
|
|
1177
|
-
title && /* @__PURE__ */ (0,
|
|
2524
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "text-xl font-semibold", children: title })
|
|
1178
2525
|
] }),
|
|
1179
|
-
actions && /* @__PURE__ */ (0,
|
|
2526
|
+
actions && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "flex flex-wrap gap-3", children: actions })
|
|
1180
2527
|
]
|
|
1181
2528
|
}
|
|
1182
2529
|
);
|
|
1183
2530
|
}
|
|
1184
2531
|
|
|
1185
2532
|
// src/components/layout/page-header.tsx
|
|
1186
|
-
var
|
|
2533
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1187
2534
|
function PageHeader({
|
|
1188
2535
|
className,
|
|
1189
2536
|
title,
|
|
@@ -1191,36 +2538,36 @@ function PageHeader({
|
|
|
1191
2538
|
actions,
|
|
1192
2539
|
...props
|
|
1193
2540
|
}) {
|
|
1194
|
-
return /* @__PURE__ */ (0,
|
|
2541
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
1195
2542
|
"div",
|
|
1196
2543
|
{
|
|
1197
2544
|
className: cn("flex flex-wrap items-start justify-between gap-6", className),
|
|
1198
2545
|
...props,
|
|
1199
2546
|
children: [
|
|
1200
|
-
/* @__PURE__ */ (0,
|
|
1201
|
-
/* @__PURE__ */ (0,
|
|
1202
|
-
description && /* @__PURE__ */ (0,
|
|
2547
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "space-y-2", children: [
|
|
2548
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("h1", { className: "text-3xl font-bold text-[rgb(var(--nc-fg))]", children: title }),
|
|
2549
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: description })
|
|
1203
2550
|
] }),
|
|
1204
|
-
actions && /* @__PURE__ */ (0,
|
|
2551
|
+
actions && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex flex-wrap gap-3", children: actions })
|
|
1205
2552
|
]
|
|
1206
2553
|
}
|
|
1207
2554
|
);
|
|
1208
2555
|
}
|
|
1209
2556
|
|
|
1210
2557
|
// src/components/layout/breadcrumbs.tsx
|
|
1211
|
-
var
|
|
2558
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1212
2559
|
function Breadcrumbs({ className, items, ...props }) {
|
|
1213
|
-
return /* @__PURE__ */ (0,
|
|
1214
|
-
const content = item.href ? /* @__PURE__ */ (0,
|
|
1215
|
-
return /* @__PURE__ */ (0,
|
|
2560
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("nav", { className: cn("flex items-center text-sm text-[rgb(var(--nc-fg-muted))]", className), ...props, children: items.map((item, index) => {
|
|
2561
|
+
const content = item.href ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("a", { href: item.href, className: "transition hover:text-[rgb(var(--nc-fg))]", children: item.label }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-[rgb(var(--nc-fg))]", children: item.label });
|
|
2562
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "flex items-center", children: [
|
|
1216
2563
|
content,
|
|
1217
|
-
index < items.length - 1 && /* @__PURE__ */ (0,
|
|
2564
|
+
index < items.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "mx-2 text-[rgb(var(--nc-fg-soft))]", children: "/" })
|
|
1218
2565
|
] }, `${item.label}-${index}`);
|
|
1219
2566
|
}) });
|
|
1220
2567
|
}
|
|
1221
2568
|
|
|
1222
2569
|
// src/components/layout/auth-layout.tsx
|
|
1223
|
-
var
|
|
2570
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1224
2571
|
function AuthLayout({
|
|
1225
2572
|
className,
|
|
1226
2573
|
title,
|
|
@@ -1230,7 +2577,7 @@ function AuthLayout({
|
|
|
1230
2577
|
children,
|
|
1231
2578
|
...props
|
|
1232
2579
|
}) {
|
|
1233
|
-
return /* @__PURE__ */ (0,
|
|
2580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
1234
2581
|
"div",
|
|
1235
2582
|
{
|
|
1236
2583
|
className: cn(
|
|
@@ -1240,17 +2587,17 @@ function AuthLayout({
|
|
|
1240
2587
|
),
|
|
1241
2588
|
...props,
|
|
1242
2589
|
children: [
|
|
1243
|
-
/* @__PURE__ */ (0,
|
|
1244
|
-
(title || description) && /* @__PURE__ */ (0,
|
|
1245
|
-
title && /* @__PURE__ */ (0,
|
|
1246
|
-
description && /* @__PURE__ */ (0,
|
|
2590
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex flex-col justify-center px-6 py-16 sm:px-12", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "mx-auto w-full max-w-md space-y-6", children: [
|
|
2591
|
+
(title || description) && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "space-y-2", children: [
|
|
2592
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h1", { className: "text-3xl font-bold text-[rgb(var(--nc-fg))]", children: title }),
|
|
2593
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: description })
|
|
1247
2594
|
] }),
|
|
1248
2595
|
children,
|
|
1249
|
-
footer && /* @__PURE__ */ (0,
|
|
2596
|
+
footer && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: footer })
|
|
1250
2597
|
] }) }),
|
|
1251
|
-
/* @__PURE__ */ (0,
|
|
1252
|
-
/* @__PURE__ */ (0,
|
|
1253
|
-
/* @__PURE__ */ (0,
|
|
2598
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "hidden items-center justify-center border-l border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.08)] p-12 text-[rgb(var(--nc-fg))] lg:flex", children: graphic != null ? graphic : /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "max-w-sm space-y-4 text-center", children: [
|
|
2599
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h2", { className: "text-2xl font-semibold", children: "Crafted experiences" }),
|
|
2600
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Build authentication flows that feel premium and cohesive." })
|
|
1254
2601
|
] }) })
|
|
1255
2602
|
]
|
|
1256
2603
|
}
|
|
@@ -1258,7 +2605,7 @@ function AuthLayout({
|
|
|
1258
2605
|
}
|
|
1259
2606
|
|
|
1260
2607
|
// src/components/layout/container.tsx
|
|
1261
|
-
var
|
|
2608
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1262
2609
|
var sizeClasses2 = {
|
|
1263
2610
|
sm: "max-w-3xl",
|
|
1264
2611
|
md: "max-w-5xl",
|
|
@@ -1266,7 +2613,7 @@ var sizeClasses2 = {
|
|
|
1266
2613
|
xl: "max-w-7xl"
|
|
1267
2614
|
};
|
|
1268
2615
|
function Container({ className, size = "lg", ...props }) {
|
|
1269
|
-
return /* @__PURE__ */ (0,
|
|
2616
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
1270
2617
|
"div",
|
|
1271
2618
|
{
|
|
1272
2619
|
className: cn("mx-auto w-full px-4 sm:px-6 lg:px-8", sizeClasses2[size], className),
|
|
@@ -1276,7 +2623,7 @@ function Container({ className, size = "lg", ...props }) {
|
|
|
1276
2623
|
}
|
|
1277
2624
|
|
|
1278
2625
|
// src/components/layout/grid.tsx
|
|
1279
|
-
var
|
|
2626
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
1280
2627
|
var colClasses = {
|
|
1281
2628
|
1: "grid-cols-1",
|
|
1282
2629
|
2: "grid-cols-1 md:grid-cols-2",
|
|
@@ -1292,12 +2639,12 @@ var gapClasses = {
|
|
|
1292
2639
|
xl: "gap-10"
|
|
1293
2640
|
};
|
|
1294
2641
|
function Grid({ className, columns = 3, gap = "md", ...props }) {
|
|
1295
|
-
return /* @__PURE__ */ (0,
|
|
2642
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: cn("grid", colClasses[columns], gapClasses[gap], className), ...props });
|
|
1296
2643
|
}
|
|
1297
2644
|
|
|
1298
2645
|
// src/theme/theme-context.tsx
|
|
1299
|
-
var
|
|
1300
|
-
var
|
|
2646
|
+
var React19 = __toESM(require("react"), 1);
|
|
2647
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
1301
2648
|
var THEME_NAMES = [
|
|
1302
2649
|
"aurora",
|
|
1303
2650
|
"ember",
|
|
@@ -1305,7 +2652,7 @@ var THEME_NAMES = [
|
|
|
1305
2652
|
"midnight",
|
|
1306
2653
|
"cosmic"
|
|
1307
2654
|
];
|
|
1308
|
-
var ThemeContext =
|
|
2655
|
+
var ThemeContext = React19.createContext(null);
|
|
1309
2656
|
var DEFAULT_THEME_KEY = "nextcraft-theme";
|
|
1310
2657
|
var DEFAULT_MODE_KEY = "nextcraft-mode";
|
|
1311
2658
|
function ThemeProvider({
|
|
@@ -1315,9 +2662,9 @@ function ThemeProvider({
|
|
|
1315
2662
|
storageKeyTheme = DEFAULT_THEME_KEY,
|
|
1316
2663
|
storageKeyMode = DEFAULT_MODE_KEY
|
|
1317
2664
|
}) {
|
|
1318
|
-
const [theme, setTheme] =
|
|
1319
|
-
const [mode, setMode] =
|
|
1320
|
-
|
|
2665
|
+
const [theme, setTheme] = React19.useState(defaultTheme);
|
|
2666
|
+
const [mode, setMode] = React19.useState(defaultMode);
|
|
2667
|
+
React19.useEffect(() => {
|
|
1321
2668
|
if (typeof window === "undefined") return;
|
|
1322
2669
|
try {
|
|
1323
2670
|
const storedTheme = window.localStorage.getItem(storageKeyTheme);
|
|
@@ -1327,7 +2674,7 @@ function ThemeProvider({
|
|
|
1327
2674
|
} catch {
|
|
1328
2675
|
}
|
|
1329
2676
|
}, [storageKeyTheme, storageKeyMode]);
|
|
1330
|
-
|
|
2677
|
+
React19.useEffect(() => {
|
|
1331
2678
|
if (typeof window === "undefined") return;
|
|
1332
2679
|
try {
|
|
1333
2680
|
window.localStorage.setItem(storageKeyTheme, theme);
|
|
@@ -1335,7 +2682,7 @@ function ThemeProvider({
|
|
|
1335
2682
|
} catch {
|
|
1336
2683
|
}
|
|
1337
2684
|
}, [theme, mode, storageKeyTheme, storageKeyMode]);
|
|
1338
|
-
|
|
2685
|
+
React19.useEffect(() => {
|
|
1339
2686
|
if (typeof document === "undefined") return;
|
|
1340
2687
|
const root = document.documentElement;
|
|
1341
2688
|
root.dataset.ncTheme = theme;
|
|
@@ -1355,14 +2702,14 @@ function ThemeProvider({
|
|
|
1355
2702
|
mediaQuery.addListener(applySystem);
|
|
1356
2703
|
return () => mediaQuery.removeListener(applySystem);
|
|
1357
2704
|
}, [theme, mode]);
|
|
1358
|
-
const value =
|
|
2705
|
+
const value = React19.useMemo(
|
|
1359
2706
|
() => ({ theme, mode, setTheme, setMode }),
|
|
1360
2707
|
[theme, mode]
|
|
1361
2708
|
);
|
|
1362
|
-
return /* @__PURE__ */ (0,
|
|
2709
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ThemeContext.Provider, { value, children });
|
|
1363
2710
|
}
|
|
1364
2711
|
function useTheme() {
|
|
1365
|
-
const context =
|
|
2712
|
+
const context = React19.useContext(ThemeContext);
|
|
1366
2713
|
if (!context) {
|
|
1367
2714
|
throw new Error("useTheme must be used within ThemeProvider");
|
|
1368
2715
|
}
|
|
@@ -1370,11 +2717,11 @@ function useTheme() {
|
|
|
1370
2717
|
}
|
|
1371
2718
|
|
|
1372
2719
|
// src/components/theme-switcher.tsx
|
|
1373
|
-
var
|
|
2720
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
1374
2721
|
var MODE_OPTIONS = ["system", "light", "dark"];
|
|
1375
2722
|
function ThemeSwitcher({ className, showLabels = true, ...props }) {
|
|
1376
2723
|
const { theme, mode, setTheme, setMode } = useTheme();
|
|
1377
|
-
return /* @__PURE__ */ (0,
|
|
2724
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
1378
2725
|
"div",
|
|
1379
2726
|
{
|
|
1380
2727
|
className: cn(
|
|
@@ -1383,27 +2730,27 @@ function ThemeSwitcher({ className, showLabels = true, ...props }) {
|
|
|
1383
2730
|
),
|
|
1384
2731
|
...props,
|
|
1385
2732
|
children: [
|
|
1386
|
-
/* @__PURE__ */ (0,
|
|
1387
|
-
showLabels && /* @__PURE__ */ (0,
|
|
1388
|
-
/* @__PURE__ */ (0,
|
|
2733
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("label", { className: "flex items-center gap-2", children: [
|
|
2734
|
+
showLabels && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Theme" }),
|
|
2735
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1389
2736
|
"select",
|
|
1390
2737
|
{
|
|
1391
2738
|
className: "rounded-lg border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-1 text-[rgb(var(--nc-fg))] outline-none focus:ring-2 focus:ring-[rgb(var(--nc-accent-1)/0.5)]",
|
|
1392
2739
|
value: theme,
|
|
1393
2740
|
onChange: (event) => setTheme(event.target.value),
|
|
1394
|
-
children: THEME_NAMES.map((name) => /* @__PURE__ */ (0,
|
|
2741
|
+
children: THEME_NAMES.map((name) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("option", { value: name, className: "text-slate-900", children: name }, name))
|
|
1395
2742
|
}
|
|
1396
2743
|
)
|
|
1397
2744
|
] }),
|
|
1398
|
-
/* @__PURE__ */ (0,
|
|
1399
|
-
showLabels && /* @__PURE__ */ (0,
|
|
1400
|
-
/* @__PURE__ */ (0,
|
|
2745
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("label", { className: "flex items-center gap-2", children: [
|
|
2746
|
+
showLabels && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Mode" }),
|
|
2747
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1401
2748
|
"select",
|
|
1402
2749
|
{
|
|
1403
2750
|
className: "rounded-lg border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] px-3 py-1 text-[rgb(var(--nc-fg))] outline-none focus:ring-2 focus:ring-[rgb(var(--nc-accent-1)/0.5)]",
|
|
1404
2751
|
value: mode,
|
|
1405
2752
|
onChange: (event) => setMode(event.target.value),
|
|
1406
|
-
children: MODE_OPTIONS.map((value) => /* @__PURE__ */ (0,
|
|
2753
|
+
children: MODE_OPTIONS.map((value) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("option", { value, className: "text-slate-900", children: value }, value))
|
|
1407
2754
|
}
|
|
1408
2755
|
)
|
|
1409
2756
|
] })
|
|
@@ -1421,15 +2768,24 @@ function ThemeSwitcher({ className, showLabels = true, ...props }) {
|
|
|
1421
2768
|
CraftButton,
|
|
1422
2769
|
CraftCard,
|
|
1423
2770
|
CraftCheckbox,
|
|
2771
|
+
CraftConfirmDialog,
|
|
2772
|
+
CraftCreateEditDrawer,
|
|
1424
2773
|
CraftCurrencyInput,
|
|
2774
|
+
CraftDataTable,
|
|
1425
2775
|
CraftDatePicker,
|
|
1426
2776
|
CraftDrawer,
|
|
1427
2777
|
CraftEmptyState,
|
|
2778
|
+
CraftFilterBar,
|
|
2779
|
+
CraftForm,
|
|
2780
|
+
CraftFormBuilder,
|
|
2781
|
+
CraftFormField,
|
|
1428
2782
|
CraftInput,
|
|
1429
2783
|
CraftModal,
|
|
1430
2784
|
CraftNumberInput,
|
|
2785
|
+
CraftPagination,
|
|
1431
2786
|
CraftSelect,
|
|
1432
2787
|
CraftSkeleton,
|
|
2788
|
+
CraftSubmitButton,
|
|
1433
2789
|
CraftSwitch,
|
|
1434
2790
|
CraftTabs,
|
|
1435
2791
|
CraftTextarea,
|