@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 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-lg rounded-3xl border border-[rgb(var(--nc-border)/0.3)] bg-[rgb(var(--nc-surface)/0.12)] p-6 text-[rgb(var(--nc-fg))] shadow-[0_20px_60px_rgba(0,0,0,0.45)] backdrop-blur-2xl",
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/layout/app-shell.tsx
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 AppShell({ className, sidebar, topNav, children, ...props }) {
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, import_jsx_runtime20.jsx)("div", { className: "h-full", children: sidebar }),
1117
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col gap-6", children: [
1118
- topNav,
1119
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("main", { className: "flex-1", children })
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 import_jsx_runtime21 = require("react/jsx-runtime");
2474
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1128
2475
  function Sidebar({ className, title, items, footer, ...props }) {
1129
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
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, import_jsx_runtime21.jsx)("div", { className: "text-lg font-semibold", children: title }),
1139
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("nav", { className: "flex flex-col gap-2", children: items.map((item, index) => {
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, import_jsx_runtime21.jsxs)(
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, import_jsx_runtime21.jsx)("span", { children: item.label })
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, import_jsx_runtime21.jsx)("div", { className: "mt-auto pt-4", children: footer })
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 import_jsx_runtime22 = require("react/jsx-runtime");
2511
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1165
2512
  function TopNav({ className, title, actions, breadcrumb, ...props }) {
1166
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
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, import_jsx_runtime22.jsxs)("div", { className: "space-y-1", children: [
2522
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "space-y-1", children: [
1176
2523
  breadcrumb,
1177
- title && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "text-xl font-semibold", children: title })
2524
+ title && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "text-xl font-semibold", children: title })
1178
2525
  ] }),
1179
- actions && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex flex-wrap gap-3", children: actions })
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 import_jsx_runtime23 = require("react/jsx-runtime");
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, import_jsx_runtime23.jsxs)(
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, import_jsx_runtime23.jsxs)("div", { className: "space-y-2", children: [
1201
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { className: "text-3xl font-bold text-[rgb(var(--nc-fg))]", children: title }),
1202
- description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: description })
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, import_jsx_runtime23.jsx)("div", { className: "flex flex-wrap gap-3", children: actions })
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 import_jsx_runtime24 = require("react/jsx-runtime");
2558
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1212
2559
  function Breadcrumbs({ className, items, ...props }) {
1213
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("nav", { className: cn("flex items-center text-sm text-[rgb(var(--nc-fg-muted))]", className), ...props, children: items.map((item, index) => {
1214
- const content = item.href ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("a", { href: item.href, className: "transition hover:text-[rgb(var(--nc-fg))]", children: item.label }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-[rgb(var(--nc-fg))]", children: item.label });
1215
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { className: "flex items-center", children: [
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, import_jsx_runtime24.jsx)("span", { className: "mx-2 text-[rgb(var(--nc-fg-soft))]", children: "/" })
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 import_jsx_runtime25 = require("react/jsx-runtime");
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, import_jsx_runtime25.jsxs)(
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, import_jsx_runtime25.jsx)("div", { className: "flex flex-col justify-center px-6 py-16 sm:px-12", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "mx-auto w-full max-w-md space-y-6", children: [
1244
- (title || description) && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "space-y-2", children: [
1245
- title && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h1", { className: "text-3xl font-bold text-[rgb(var(--nc-fg))]", children: title }),
1246
- description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: description })
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, import_jsx_runtime25.jsx)("div", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: footer })
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, import_jsx_runtime25.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_runtime25.jsxs)("div", { className: "max-w-sm space-y-4 text-center", children: [
1252
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { className: "text-2xl font-semibold", children: "Crafted experiences" }),
1253
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Build authentication flows that feel premium and cohesive." })
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 import_jsx_runtime26 = require("react/jsx-runtime");
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, import_jsx_runtime26.jsx)(
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 import_jsx_runtime27 = require("react/jsx-runtime");
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, import_jsx_runtime27.jsx)("div", { className: cn("grid", colClasses[columns], gapClasses[gap], className), ...props });
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 React14 = __toESM(require("react"), 1);
1300
- var import_jsx_runtime28 = require("react/jsx-runtime");
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 = React14.createContext(null);
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] = React14.useState(defaultTheme);
1319
- const [mode, setMode] = React14.useState(defaultMode);
1320
- React14.useEffect(() => {
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
- React14.useEffect(() => {
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
- React14.useEffect(() => {
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 = React14.useMemo(
2705
+ const value = React19.useMemo(
1359
2706
  () => ({ theme, mode, setTheme, setMode }),
1360
2707
  [theme, mode]
1361
2708
  );
1362
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ThemeContext.Provider, { value, children });
2709
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ThemeContext.Provider, { value, children });
1363
2710
  }
1364
2711
  function useTheme() {
1365
- const context = React14.useContext(ThemeContext);
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 import_jsx_runtime29 = require("react/jsx-runtime");
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, import_jsx_runtime29.jsxs)(
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, import_jsx_runtime29.jsxs)("label", { className: "flex items-center gap-2", children: [
1387
- showLabels && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Theme" }),
1388
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
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, import_jsx_runtime29.jsx)("option", { value: name, className: "text-slate-900", children: name }, name))
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, import_jsx_runtime29.jsxs)("label", { className: "flex items-center gap-2", children: [
1399
- showLabels && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-[rgb(var(--nc-fg-muted))]", children: "Mode" }),
1400
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
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, import_jsx_runtime29.jsx)("option", { value, className: "text-slate-900", children: value }, value))
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,