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