shru-design-system 0.2.0 → 0.3.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
@@ -143,7 +143,8 @@ var badgeVariantsConfig = {
143
143
  default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
144
144
  secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
145
145
  destructive: "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
146
- outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
146
+ outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
147
+ disabled: "border-transparent bg-muted text-muted-foreground opacity-50 cursor-not-allowed"
147
148
  }
148
149
  },
149
150
  defaultVariants: {
@@ -154,14 +155,15 @@ var badgeVariants = classVarianceAuthority.cva(
154
155
  "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium font-sans w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-component-xs [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] duration-normal overflow-hidden",
155
156
  badgeVariantsConfig
156
157
  );
157
- var Badge = React14__namespace.forwardRef(({ className, variant, asChild = false, ...props }, ref) => {
158
+ var Badge = React14__namespace.forwardRef(({ className, variant, asChild = false, onClick, ...props }, ref) => {
158
159
  const Comp = asChild ? reactSlot.Slot : "span";
159
160
  return /* @__PURE__ */ jsxRuntime.jsx(
160
161
  Comp,
161
162
  {
162
163
  ref,
163
164
  "data-slot": "badge",
164
- className: cn(badgeVariants({ variant }), className),
165
+ className: cn(badgeVariants({ variant }), onClick && "cursor-pointer", className),
166
+ onClick,
165
167
  ...props
166
168
  }
167
169
  );
@@ -4004,10 +4006,12 @@ var variantMap3 = {
4004
4006
  function InfoBanner({
4005
4007
  message,
4006
4008
  variant = "info",
4007
- className
4009
+ className,
4010
+ tooltip = false,
4011
+ children
4008
4012
  }) {
4009
4013
  const { icon: Icon2 } = variantMap3[variant];
4010
- return /* @__PURE__ */ jsxRuntime.jsxs(
4014
+ const content = /* @__PURE__ */ jsxRuntime.jsxs(
4011
4015
  Alert,
4012
4016
  {
4013
4017
  "data-slot": "info-banner",
@@ -4023,6 +4027,13 @@ function InfoBanner({
4023
4027
  ]
4024
4028
  }
4025
4029
  );
4030
+ if (tooltip) {
4031
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
4032
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: children || /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: "size-4" }) }),
4033
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: message }) })
4034
+ ] }) });
4035
+ }
4036
+ return content;
4026
4037
  }
4027
4038
  function InlineEdit({
4028
4039
  value: initialValue,
@@ -4207,21 +4218,107 @@ function InputGroupTextarea({
4207
4218
  }
4208
4219
  function FormInput({
4209
4220
  className,
4221
+ type = "text",
4210
4222
  label,
4211
4223
  error,
4212
4224
  description,
4225
+ variant = "default",
4213
4226
  id,
4227
+ options,
4228
+ onValueChange,
4229
+ checked,
4230
+ onCheckedChange,
4214
4231
  ...props
4215
4232
  }) {
4216
4233
  const inputId = id || React14__namespace.useId();
4234
+ if (type === "checkbox") {
4235
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "form-input", className: cn("space-y-2", className), children: [
4236
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [
4237
+ /* @__PURE__ */ jsxRuntime.jsx(
4238
+ Checkbox,
4239
+ {
4240
+ id: inputId,
4241
+ checked,
4242
+ onCheckedChange,
4243
+ disabled: props.disabled
4244
+ }
4245
+ ),
4246
+ label && /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: inputId, className: cn("cursor-pointer", error && "text-destructive"), children: [
4247
+ label,
4248
+ props.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive ml-1", children: "*" })
4249
+ ] })
4250
+ ] }),
4251
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: description }),
4252
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", role: "alert", children: error })
4253
+ ] });
4254
+ }
4255
+ if (type === "select") {
4256
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "form-input", className: cn("space-y-2", className), children: [
4257
+ label && /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: inputId, className: error && "text-destructive", children: [
4258
+ label,
4259
+ props.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive ml-1", children: "*" })
4260
+ ] }),
4261
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: description }),
4262
+ /* @__PURE__ */ jsxRuntime.jsxs(
4263
+ Select,
4264
+ {
4265
+ value: props.value,
4266
+ onValueChange,
4267
+ children: [
4268
+ /* @__PURE__ */ jsxRuntime.jsx(
4269
+ SelectTrigger,
4270
+ {
4271
+ id: inputId,
4272
+ className: cn(
4273
+ error && "border-destructive",
4274
+ variant === "minimal" && "border-0 shadow-none bg-transparent"
4275
+ ),
4276
+ children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: props.placeholder || "Select..." })
4277
+ }
4278
+ ),
4279
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: options?.map((option) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
4280
+ ]
4281
+ }
4282
+ ),
4283
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", role: "alert", children: error })
4284
+ ] });
4285
+ }
4286
+ if (type === "textarea") {
4287
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "form-input", className: cn("space-y-2", className), children: [
4288
+ label && /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: inputId, className: error && "text-destructive", children: [
4289
+ label,
4290
+ props.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive ml-1", children: "*" })
4291
+ ] }),
4292
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: description }),
4293
+ /* @__PURE__ */ jsxRuntime.jsx(
4294
+ Textarea,
4295
+ {
4296
+ id: inputId,
4297
+ className: cn(
4298
+ error && "border-destructive",
4299
+ variant === "minimal" && "border-0 shadow-none bg-transparent"
4300
+ ),
4301
+ ...props
4302
+ }
4303
+ ),
4304
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", role: "alert", children: error })
4305
+ ] });
4306
+ }
4217
4307
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "form-input", className: cn("space-y-2", className), children: [
4218
- label && /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: inputId, className: error && "text-destructive", children: label }),
4308
+ label && /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: inputId, className: error && "text-destructive", children: [
4309
+ label,
4310
+ props.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive ml-1", children: "*" })
4311
+ ] }),
4219
4312
  description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: description }),
4220
4313
  /* @__PURE__ */ jsxRuntime.jsx(
4221
4314
  TextInput,
4222
4315
  {
4223
4316
  id: inputId,
4224
- className: error && "border-destructive",
4317
+ type,
4318
+ className: cn(
4319
+ error && "border-destructive",
4320
+ variant === "minimal" && "border-0 shadow-none bg-transparent"
4321
+ ),
4225
4322
  ...props
4226
4323
  }
4227
4324
  ),
@@ -4229,38 +4326,112 @@ function FormInput({
4229
4326
  ] });
4230
4327
  }
4231
4328
  function ConfirmModal({
4232
- open,
4329
+ open: openProp,
4233
4330
  onOpenChange,
4234
- onConfirm,
4331
+ triggerLabel,
4332
+ triggerProps,
4333
+ text,
4235
4334
  title,
4236
4335
  description,
4237
- confirmLabel = "Confirm",
4336
+ onConfirm,
4337
+ confirmLabel,
4238
4338
  cancelLabel = "Cancel",
4239
- variant = "default"
4240
- }) {
4241
- const handleConfirm = () => {
4242
- onConfirm();
4243
- onOpenChange(false);
4339
+ variant = "default",
4340
+ loading = false,
4341
+ error,
4342
+ showModal = true
4343
+ }) {
4344
+ const [open, setOpen] = React14__namespace.useState(openProp ?? false);
4345
+ const [isSubmitting, setIsSubmitting] = React14__namespace.useState(false);
4346
+ const isControlled = openProp !== void 0;
4347
+ const isOpen = isControlled ? openProp : open;
4348
+ const setIsOpen = isControlled ? onOpenChange : setOpen;
4349
+ const handleConfirm = async () => {
4350
+ setIsSubmitting(true);
4351
+ try {
4352
+ await onConfirm();
4353
+ setIsOpen?.(false);
4354
+ } catch (err) {
4355
+ console.error("Confirm action error:", err);
4356
+ } finally {
4357
+ setIsSubmitting(false);
4358
+ }
4244
4359
  };
4245
- return /* @__PURE__ */ jsxRuntime.jsx(Modal, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { "data-slot": "confirm-modal", children: [
4360
+ const getVariantConfig = () => {
4361
+ switch (variant) {
4362
+ case "delete":
4363
+ case "destructive":
4364
+ return {
4365
+ buttonVariant: "destructive",
4366
+ defaultConfirmLabel: "Delete"
4367
+ };
4368
+ case "save":
4369
+ return {
4370
+ buttonVariant: "default",
4371
+ defaultConfirmLabel: "Save"
4372
+ };
4373
+ case "warning":
4374
+ return {
4375
+ buttonVariant: "default",
4376
+ defaultConfirmLabel: "Continue"
4377
+ };
4378
+ default:
4379
+ return {
4380
+ buttonVariant: "default",
4381
+ defaultConfirmLabel: "Confirm"
4382
+ };
4383
+ }
4384
+ };
4385
+ const { buttonVariant, defaultConfirmLabel } = getVariantConfig();
4386
+ const finalConfirmLabel = confirmLabel || defaultConfirmLabel;
4387
+ const isLoading = loading || isSubmitting;
4388
+ const modalContent = /* @__PURE__ */ jsxRuntime.jsx(Modal, { open: isOpen && showModal, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { "data-slot": "confirm-modal", children: [
4246
4389
  /* @__PURE__ */ jsxRuntime.jsxs(ModalHeader, { children: [
4247
4390
  /* @__PURE__ */ jsxRuntime.jsx(ModalTitle, { children: title }),
4248
- description && /* @__PURE__ */ jsxRuntime.jsx(ModalDescription, { children: description })
4391
+ description && /* @__PURE__ */ jsxRuntime.jsx(ModalDescription, { children: description }),
4392
+ text && /* @__PURE__ */ jsxRuntime.jsx(ModalDescription, { children: text })
4249
4393
  ] }),
4394
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: error }) }),
4250
4395
  /* @__PURE__ */ jsxRuntime.jsxs(ModalFooter, { children: [
4251
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: cancelLabel }),
4252
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: variant === "destructive" ? "destructive" : "default", onClick: handleConfirm, children: confirmLabel })
4396
+ /* @__PURE__ */ jsxRuntime.jsx(
4397
+ Button,
4398
+ {
4399
+ variant: "outline",
4400
+ onClick: () => setIsOpen?.(false),
4401
+ disabled: isLoading,
4402
+ children: cancelLabel
4403
+ }
4404
+ ),
4405
+ /* @__PURE__ */ jsxRuntime.jsx(
4406
+ Button,
4407
+ {
4408
+ variant: buttonVariant,
4409
+ onClick: handleConfirm,
4410
+ disabled: isLoading,
4411
+ children: isLoading ? "Loading..." : finalConfirmLabel
4412
+ }
4413
+ )
4253
4414
  ] })
4254
4415
  ] }) });
4416
+ if (triggerLabel) {
4417
+ return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { open: isOpen && showModal, onOpenChange: setIsOpen, children: [
4418
+ /* @__PURE__ */ jsxRuntime.jsx(ModalTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { ...triggerProps, children: triggerLabel }) }),
4419
+ modalContent
4420
+ ] });
4421
+ }
4422
+ return modalContent;
4255
4423
  }
4256
4424
  function CopyButton({
4257
4425
  text,
4426
+ getText,
4258
4427
  onCopy,
4259
4428
  ...props
4260
4429
  }) {
4261
4430
  const [copied, setCopied] = React14__namespace.useState(false);
4262
4431
  const handleCopy = async () => {
4263
- await navigator.clipboard.writeText(text);
4432
+ const textToCopy = getText ? getText() : text || "";
4433
+ if (!textToCopy) return;
4434
+ await navigator.clipboard.writeText(textToCopy);
4264
4435
  setCopied(true);
4265
4436
  onCopy?.();
4266
4437
  setTimeout(() => setCopied(false), 2e3);
@@ -4278,36 +4449,235 @@ function CopyButton({
4278
4449
  );
4279
4450
  }
4280
4451
  function FormModal({
4281
- open,
4452
+ open: openProp,
4282
4453
  onOpenChange,
4454
+ triggerLabel,
4455
+ triggerProps,
4283
4456
  title,
4284
4457
  onSubmit,
4285
- children,
4286
4458
  submitLabel = "Submit",
4287
- cancelLabel = "Cancel"
4288
- }) {
4289
- const handleSubmit = (e) => {
4459
+ cancelLabel = "Cancel",
4460
+ fields,
4461
+ children,
4462
+ beforeFields,
4463
+ afterFields
4464
+ }) {
4465
+ const [open, setOpen] = React14__namespace.useState(openProp ?? false);
4466
+ const [formData, setFormData] = React14__namespace.useState({});
4467
+ const [errors, setErrors] = React14__namespace.useState({});
4468
+ const [isSubmitting, setIsSubmitting] = React14__namespace.useState(false);
4469
+ const isControlled = openProp !== void 0;
4470
+ const isOpen = isControlled ? openProp : open;
4471
+ const setIsOpen = isControlled ? onOpenChange : setOpen;
4472
+ React14__namespace.useEffect(() => {
4473
+ if (fields) {
4474
+ const initialData = {};
4475
+ fields.forEach((field) => {
4476
+ if (field.defaultValue !== void 0) {
4477
+ initialData[field.name] = field.defaultValue;
4478
+ }
4479
+ });
4480
+ setFormData(initialData);
4481
+ }
4482
+ }, [fields]);
4483
+ const handleChange = (name, value) => {
4484
+ setFormData((prev) => ({ ...prev, [name]: value }));
4485
+ if (errors[name]) {
4486
+ setErrors((prev) => {
4487
+ const next = { ...prev };
4488
+ delete next[name];
4489
+ return next;
4490
+ });
4491
+ }
4492
+ };
4493
+ const validateField = (field, value) => {
4494
+ if (field.required && (value === void 0 || value === null || value === "")) {
4495
+ return `${field.label || field.name} is required`;
4496
+ }
4497
+ if (field.validation) {
4498
+ return field.validation(value);
4499
+ }
4500
+ return void 0;
4501
+ };
4502
+ const handleSubmit = async (e) => {
4290
4503
  e.preventDefault();
4291
- const formData = new FormData(e.target);
4292
- const data = Object.fromEntries(formData);
4293
- onSubmit(data);
4504
+ if (!fields) {
4505
+ return;
4506
+ }
4507
+ const newErrors = {};
4508
+ fields.forEach((field) => {
4509
+ const isActive = typeof field.active === "function" ? field.active(formData) : field.active !== false;
4510
+ if (isActive) {
4511
+ const error = validateField(field, formData[field.name]);
4512
+ if (error) {
4513
+ newErrors[field.name] = error;
4514
+ }
4515
+ }
4516
+ });
4517
+ if (Object.keys(newErrors).length > 0) {
4518
+ setErrors(newErrors);
4519
+ return;
4520
+ }
4521
+ setIsSubmitting(true);
4522
+ try {
4523
+ await onSubmit(formData);
4524
+ setIsOpen?.(false);
4525
+ setFormData({});
4526
+ setErrors({});
4527
+ } catch (error) {
4528
+ console.error("Form submission error:", error);
4529
+ } finally {
4530
+ setIsSubmitting(false);
4531
+ }
4532
+ };
4533
+ const renderField = (field) => {
4534
+ const isActive = typeof field.active === "function" ? field.active(formData) : field.active !== false;
4535
+ if (!isActive) return null;
4536
+ const value = formData[field.name] ?? field.defaultValue;
4537
+ const error = errors[field.name];
4538
+ switch (field.type) {
4539
+ case "text":
4540
+ case "email":
4541
+ case "url":
4542
+ return /* @__PURE__ */ jsxRuntime.jsx(
4543
+ FormInput,
4544
+ {
4545
+ label: field.label,
4546
+ description: field.description,
4547
+ error,
4548
+ type: field.type,
4549
+ placeholder: field.placeholder,
4550
+ value: value || "",
4551
+ onChange: (e) => handleChange(field.name, e.target.value),
4552
+ required: field.required
4553
+ },
4554
+ field.name
4555
+ );
4556
+ case "number":
4557
+ return /* @__PURE__ */ jsxRuntime.jsx(
4558
+ FormInput,
4559
+ {
4560
+ label: field.label,
4561
+ description: field.description,
4562
+ error,
4563
+ type: "number",
4564
+ placeholder: field.placeholder,
4565
+ value: value || "",
4566
+ onChange: (e) => handleChange(field.name, parseFloat(e.target.value) || 0),
4567
+ min: field.min,
4568
+ max: field.max,
4569
+ step: field.step,
4570
+ required: field.required
4571
+ },
4572
+ field.name
4573
+ );
4574
+ case "textarea":
4575
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
4576
+ field.label && /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: field.name, className: error && "text-destructive", children: [
4577
+ field.label,
4578
+ field.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive ml-1", children: "*" })
4579
+ ] }),
4580
+ field.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: field.description }),
4581
+ /* @__PURE__ */ jsxRuntime.jsx(
4582
+ Textarea,
4583
+ {
4584
+ id: field.name,
4585
+ placeholder: field.placeholder,
4586
+ value: value || "",
4587
+ onChange: (e) => handleChange(field.name, e.target.value),
4588
+ className: error && "border-destructive",
4589
+ required: field.required
4590
+ }
4591
+ ),
4592
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", role: "alert", children: error })
4593
+ ] }, field.name);
4594
+ case "select":
4595
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
4596
+ field.label && /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: field.name, className: error && "text-destructive", children: [
4597
+ field.label,
4598
+ field.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive ml-1", children: "*" })
4599
+ ] }),
4600
+ field.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: field.description }),
4601
+ /* @__PURE__ */ jsxRuntime.jsxs(
4602
+ Select,
4603
+ {
4604
+ value: value || "",
4605
+ onValueChange: (val) => handleChange(field.name, val),
4606
+ children: [
4607
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { id: field.name, className: error && "border-destructive", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: field.placeholder || "Select..." }) }),
4608
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: field.options?.map((option) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
4609
+ ]
4610
+ }
4611
+ ),
4612
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", role: "alert", children: error })
4613
+ ] }, field.name);
4614
+ case "checkbox":
4615
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [
4616
+ /* @__PURE__ */ jsxRuntime.jsx(
4617
+ Checkbox,
4618
+ {
4619
+ id: field.name,
4620
+ checked: value || false,
4621
+ onCheckedChange: (checked) => handleChange(field.name, checked)
4622
+ }
4623
+ ),
4624
+ field.label && /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: field.name, className: "cursor-pointer", children: [
4625
+ field.label,
4626
+ field.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive ml-1", children: "*" })
4627
+ ] }),
4628
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", role: "alert", children: error })
4629
+ ] }, field.name);
4630
+ case "upload":
4631
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
4632
+ field.label && /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: field.name, className: error && "text-destructive", children: [
4633
+ field.label,
4634
+ field.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive ml-1", children: "*" })
4635
+ ] }),
4636
+ field.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: field.description }),
4637
+ /* @__PURE__ */ jsxRuntime.jsx(
4638
+ Upload,
4639
+ {
4640
+ id: field.name,
4641
+ accept: field.accept,
4642
+ multiple: field.multiple,
4643
+ onChange: (e) => handleChange(field.name, e.target.files),
4644
+ className: error && "border-destructive"
4645
+ }
4646
+ ),
4647
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", role: "alert", children: error })
4648
+ ] }, field.name);
4649
+ default:
4650
+ return null;
4651
+ }
4294
4652
  };
4295
- return /* @__PURE__ */ jsxRuntime.jsx(Modal, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsx(ModalContent, { "data-slot": "form-modal", children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, children: [
4653
+ const modalContent = /* @__PURE__ */ jsxRuntime.jsx(Modal, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxRuntime.jsx(ModalContent, { "data-slot": "form-modal", children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, children: [
4296
4654
  /* @__PURE__ */ jsxRuntime.jsx(ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(ModalTitle, { children: title }) }),
4297
- children,
4655
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 px-6 py-4", children: [
4656
+ beforeFields,
4657
+ fields ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fields.map((field) => renderField(field)) }) : children,
4658
+ afterFields
4659
+ ] }),
4298
4660
  /* @__PURE__ */ jsxRuntime.jsxs(ModalFooter, { children: [
4299
4661
  /* @__PURE__ */ jsxRuntime.jsx(
4300
4662
  Button,
4301
4663
  {
4302
4664
  type: "button",
4303
4665
  variant: "outline",
4304
- onClick: () => onOpenChange(false),
4666
+ onClick: () => setIsOpen?.(false),
4667
+ disabled: isSubmitting,
4305
4668
  children: cancelLabel
4306
4669
  }
4307
4670
  ),
4308
- /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", children: submitLabel })
4671
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", disabled: isSubmitting, children: isSubmitting ? "Submitting..." : submitLabel })
4309
4672
  ] })
4310
4673
  ] }) }) });
4674
+ if (triggerLabel) {
4675
+ return /* @__PURE__ */ jsxRuntime.jsxs(Modal, { open: isOpen, onOpenChange: setIsOpen, children: [
4676
+ /* @__PURE__ */ jsxRuntime.jsx(ModalTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { ...triggerProps, children: triggerLabel }) }),
4677
+ modalContent
4678
+ ] });
4679
+ }
4680
+ return modalContent;
4311
4681
  }
4312
4682
  function TriggerModal({
4313
4683
  trigger,
@@ -4441,16 +4811,49 @@ function Grid({
4441
4811
  }
4442
4812
  );
4443
4813
  }
4444
- function Card({ className, ...props }) {
4445
- return /* @__PURE__ */ jsxRuntime.jsx(
4814
+ var cardVariants = classVarianceAuthority.cva(
4815
+ "bg-card text-card-foreground flex flex-col rounded-xl border shadow-sm",
4816
+ {
4817
+ variants: {
4818
+ variant: {
4819
+ minimal: "border-0 shadow-none bg-transparent",
4820
+ filled: "bg-muted border-0",
4821
+ subtle: "bg-muted/50 border-muted",
4822
+ outlined: "bg-transparent border-2"
4823
+ },
4824
+ size: {
4825
+ xs: "gap-3 py-3 text-xs",
4826
+ sm: "gap-4 py-4 text-sm",
4827
+ md: "gap-6 py-6 text-base",
4828
+ lg: "gap-8 py-8 text-lg"
4829
+ }
4830
+ },
4831
+ defaultVariants: {
4832
+ variant: "outlined",
4833
+ size: "md"
4834
+ }
4835
+ }
4836
+ );
4837
+ function Card({
4838
+ className,
4839
+ variant,
4840
+ size,
4841
+ header,
4842
+ footer,
4843
+ children,
4844
+ ...props
4845
+ }) {
4846
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4446
4847
  "div",
4447
4848
  {
4448
4849
  "data-slot": "card",
4449
- className: cn(
4450
- "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
4451
- className
4452
- ),
4453
- ...props
4850
+ className: cn(cardVariants({ variant, size }), className),
4851
+ ...props,
4852
+ children: [
4853
+ header && /* @__PURE__ */ jsxRuntime.jsx(CardHeader, { children: header }),
4854
+ children,
4855
+ footer && /* @__PURE__ */ jsxRuntime.jsx(CardFooter, { children: footer })
4856
+ ]
4454
4857
  }
4455
4858
  );
4456
4859
  }
@@ -4723,9 +5126,29 @@ function List3({
4723
5126
  }
4724
5127
  );
4725
5128
  }
5129
+ var headerVariants = classVarianceAuthority.cva(
5130
+ "w-full bg-background",
5131
+ {
5132
+ variants: {
5133
+ variant: {
5134
+ default: "border-b",
5135
+ bordered: "border-b-2"
5136
+ }
5137
+ },
5138
+ defaultVariants: {
5139
+ variant: "default"
5140
+ }
5141
+ }
5142
+ );
4726
5143
  function Header2({
4727
5144
  className,
4728
5145
  sticky = false,
5146
+ variant,
5147
+ heading,
5148
+ caption,
5149
+ left,
5150
+ right,
5151
+ children,
4729
5152
  ...props
4730
5153
  }) {
4731
5154
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -4734,11 +5157,21 @@ function Header2({
4734
5157
  as: "header",
4735
5158
  "data-slot": "header",
4736
5159
  className: cn(
4737
- "w-full border-b bg-background",
5160
+ headerVariants({ variant }),
4738
5161
  sticky && "sticky top-0 z-50",
4739
5162
  className
4740
5163
  ),
4741
- ...props
5164
+ ...props,
5165
+ children: heading || caption || left || right ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 sm:px-6 lg:px-8 py-4", children: [
5166
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
5167
+ left,
5168
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
5169
+ heading && /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold", children: heading }),
5170
+ caption && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: caption })
5171
+ ] })
5172
+ ] }),
5173
+ right
5174
+ ] }) : children
4742
5175
  }
4743
5176
  );
4744
5177
  }
@@ -4759,21 +5192,51 @@ function Footer({
4759
5192
  }
4760
5193
  );
4761
5194
  }
5195
+ var emptyScreenVariants = classVarianceAuthority.cva(
5196
+ "py-12",
5197
+ {
5198
+ variants: {
5199
+ variant: {
5200
+ default: "",
5201
+ minimal: "py-6",
5202
+ spacious: "py-16"
5203
+ },
5204
+ size: {
5205
+ sm: "text-sm",
5206
+ md: "text-base",
5207
+ lg: "text-lg"
5208
+ }
5209
+ },
5210
+ defaultVariants: {
5211
+ variant: "default",
5212
+ size: "md"
5213
+ }
5214
+ }
5215
+ );
4762
5216
  function EmptyScreen({
4763
5217
  title = "No items",
4764
5218
  description,
4765
5219
  icon,
4766
5220
  action,
5221
+ variant,
5222
+ size,
4767
5223
  className
4768
5224
  }) {
4769
- return /* @__PURE__ */ jsxRuntime.jsxs(Empty, { className: cn("py-12", className), "data-slot": "empty-screen", children: [
4770
- icon && /* @__PURE__ */ jsxRuntime.jsx(EmptyContent, { children: icon }),
4771
- /* @__PURE__ */ jsxRuntime.jsxs(EmptyHeader, { children: [
4772
- /* @__PURE__ */ jsxRuntime.jsx(EmptyTitle, { children: title }),
4773
- description && /* @__PURE__ */ jsxRuntime.jsx(EmptyDescription, { children: description })
4774
- ] }),
4775
- action && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4", children: action })
4776
- ] });
5225
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5226
+ Empty,
5227
+ {
5228
+ className: cn(emptyScreenVariants({ variant, size }), className),
5229
+ "data-slot": "empty-screen",
5230
+ children: [
5231
+ icon && /* @__PURE__ */ jsxRuntime.jsx(EmptyContent, { children: icon }),
5232
+ /* @__PURE__ */ jsxRuntime.jsxs(EmptyHeader, { children: [
5233
+ /* @__PURE__ */ jsxRuntime.jsx(EmptyTitle, { children: title }),
5234
+ description && /* @__PURE__ */ jsxRuntime.jsx(EmptyDescription, { children: description })
5235
+ ] }),
5236
+ action && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4", children: action })
5237
+ ]
5238
+ }
5239
+ );
4777
5240
  }
4778
5241
  function CollapsiblePanel({
4779
5242
  title,