@jameskabz/nextcraft-ui 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1421 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +223 -1
- package/dist/index.d.ts +223 -1
- package/dist/index.js +1418 -65
- package/dist/index.js.map +1 -1
- package/dist/styles.css +235 -4
- package/package.json +3 -1
package/dist/index.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-
|
|
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/
|
|
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
|
|
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__ */
|
|
1051
|
-
/* @__PURE__ */
|
|
1052
|
-
topNav,
|
|
1053
|
-
/* @__PURE__ */
|
|
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
|
|
2405
|
+
import { jsx as jsx30, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1062
2406
|
function Sidebar({ className, title, items, footer, ...props }) {
|
|
1063
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
1073
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
2429
|
+
/* @__PURE__ */ jsx30("span", { children: item.label })
|
|
1086
2430
|
]
|
|
1087
2431
|
},
|
|
1088
2432
|
`${item.label}-${index}`
|
|
1089
2433
|
);
|
|
1090
2434
|
}) }),
|
|
1091
|
-
footer && /* @__PURE__ */
|
|
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
|
|
2442
|
+
import { jsx as jsx31, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1099
2443
|
function TopNav({ className, title, actions, breadcrumb, ...props }) {
|
|
1100
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
2453
|
+
/* @__PURE__ */ jsxs24("div", { className: "space-y-1", children: [
|
|
1110
2454
|
breadcrumb,
|
|
1111
|
-
title && /* @__PURE__ */
|
|
2455
|
+
title && /* @__PURE__ */ jsx31("div", { className: "text-xl font-semibold", children: title })
|
|
1112
2456
|
] }),
|
|
1113
|
-
actions && /* @__PURE__ */
|
|
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
|
|
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__ */
|
|
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__ */
|
|
1135
|
-
/* @__PURE__ */
|
|
1136
|
-
description && /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
2489
|
+
import { jsx as jsx33, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
1146
2490
|
function Breadcrumbs({ className, items, ...props }) {
|
|
1147
|
-
return /* @__PURE__ */
|
|
1148
|
-
const content = item.href ? /* @__PURE__ */
|
|
1149
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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__ */
|
|
1178
|
-
(title || description) && /* @__PURE__ */
|
|
1179
|
-
title && /* @__PURE__ */
|
|
1180
|
-
description && /* @__PURE__ */
|
|
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__ */
|
|
2527
|
+
footer && /* @__PURE__ */ jsx34("div", { className: "text-sm text-[rgb(var(--nc-fg-muted))]", children: footer })
|
|
1184
2528
|
] }) }),
|
|
1185
|
-
/* @__PURE__ */
|
|
1186
|
-
/* @__PURE__ */
|
|
1187
|
-
/* @__PURE__ */
|
|
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
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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
|
|
1234
|
-
import { jsx as
|
|
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 =
|
|
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] =
|
|
1253
|
-
const [mode, setMode] =
|
|
1254
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
2636
|
+
const value = React19.useMemo(
|
|
1293
2637
|
() => ({ theme, mode, setTheme, setMode }),
|
|
1294
2638
|
[theme, mode]
|
|
1295
2639
|
);
|
|
1296
|
-
return /* @__PURE__ */
|
|
2640
|
+
return /* @__PURE__ */ jsx37(ThemeContext.Provider, { value, children });
|
|
1297
2641
|
}
|
|
1298
2642
|
function useTheme() {
|
|
1299
|
-
const context =
|
|
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
|
|
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__ */
|
|
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__ */
|
|
1321
|
-
showLabels && /* @__PURE__ */
|
|
1322
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1333
|
-
showLabels && /* @__PURE__ */
|
|
1334
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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,
|