@planetaexo/design-system 0.4.7 → 0.4.9

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.d.cts CHANGED
@@ -571,6 +571,15 @@ interface RegistrationFormProps {
571
571
  defaultValues?: RegistrationFormValues;
572
572
  onChange?: (values: RegistrationFormValues) => void;
573
573
  onSubmit?: (values: RegistrationFormValues) => void;
574
+ /**
575
+ * Synchronous format/business validator called inside handleSubmit.
576
+ * Return a record of fieldId → error message to block submit and show inline errors.
577
+ * Called after the required-empty check, so values are guaranteed non-empty for required fields.
578
+ * For validating optional fields or additional format checks, use this instead of onSubmit.
579
+ */
580
+ onValidate?: (values: RegistrationFormValues) => Record<string, string>;
581
+ /** @deprecated Use onValidate instead. Per-field errors injected by the parent. */
582
+ externalErrors?: Record<string, string>;
574
583
  terms?: RegistrationTerms;
575
584
  includeTerms?: boolean;
576
585
  loading?: boolean;
@@ -580,7 +589,7 @@ interface RegistrationFormProps {
580
589
  labels?: RegistrationFormLabels;
581
590
  className?: string;
582
591
  }
583
- declare function RegistrationForm({ logo, logoAlt, heroImage, heroImageAlt, title, subtitle, adventure, booking, traveller, fields, values, defaultValues, onChange, onSubmit, terms, includeTerms, loading, error, defaultPhoneCountry, dateFormatter, labels, className, }: RegistrationFormProps): react_jsx_runtime.JSX.Element;
592
+ declare function RegistrationForm({ logo, logoAlt, heroImage, heroImageAlt, title, subtitle, adventure, booking, traveller, fields, values, defaultValues, onChange, onSubmit, onValidate, externalErrors, terms, includeTerms, loading, error, defaultPhoneCountry, dateFormatter, labels, className, }: RegistrationFormProps): react_jsx_runtime.JSX.Element;
584
593
  interface RegistrationSuccessCardProps {
585
594
  title?: string;
586
595
  message?: string;
package/dist/index.d.ts CHANGED
@@ -571,6 +571,15 @@ interface RegistrationFormProps {
571
571
  defaultValues?: RegistrationFormValues;
572
572
  onChange?: (values: RegistrationFormValues) => void;
573
573
  onSubmit?: (values: RegistrationFormValues) => void;
574
+ /**
575
+ * Synchronous format/business validator called inside handleSubmit.
576
+ * Return a record of fieldId → error message to block submit and show inline errors.
577
+ * Called after the required-empty check, so values are guaranteed non-empty for required fields.
578
+ * For validating optional fields or additional format checks, use this instead of onSubmit.
579
+ */
580
+ onValidate?: (values: RegistrationFormValues) => Record<string, string>;
581
+ /** @deprecated Use onValidate instead. Per-field errors injected by the parent. */
582
+ externalErrors?: Record<string, string>;
574
583
  terms?: RegistrationTerms;
575
584
  includeTerms?: boolean;
576
585
  loading?: boolean;
@@ -580,7 +589,7 @@ interface RegistrationFormProps {
580
589
  labels?: RegistrationFormLabels;
581
590
  className?: string;
582
591
  }
583
- declare function RegistrationForm({ logo, logoAlt, heroImage, heroImageAlt, title, subtitle, adventure, booking, traveller, fields, values, defaultValues, onChange, onSubmit, terms, includeTerms, loading, error, defaultPhoneCountry, dateFormatter, labels, className, }: RegistrationFormProps): react_jsx_runtime.JSX.Element;
592
+ declare function RegistrationForm({ logo, logoAlt, heroImage, heroImageAlt, title, subtitle, adventure, booking, traveller, fields, values, defaultValues, onChange, onSubmit, onValidate, externalErrors, terms, includeTerms, loading, error, defaultPhoneCountry, dateFormatter, labels, className, }: RegistrationFormProps): react_jsx_runtime.JSX.Element;
584
593
  interface RegistrationSuccessCardProps {
585
594
  title?: string;
586
595
  message?: string;
package/dist/index.js CHANGED
@@ -4500,6 +4500,8 @@ function RegistrationForm({
4500
4500
  defaultValues,
4501
4501
  onChange,
4502
4502
  onSubmit,
4503
+ onValidate,
4504
+ externalErrors,
4503
4505
  terms,
4504
4506
  includeTerms = false,
4505
4507
  loading = false,
@@ -4531,6 +4533,7 @@ function RegistrationForm({
4531
4533
  )
4532
4534
  );
4533
4535
  const [submitAttempted, setSubmitAttempted] = React21.useState(false);
4536
+ const [validationErrors, setValidationErrors] = React21.useState({});
4534
4537
  React21.useEffect(() => {
4535
4538
  if (isControlled) return;
4536
4539
  setInternal((prev) => {
@@ -4556,12 +4559,15 @@ function RegistrationForm({
4556
4559
  const termsEnabled = includeTerms && !!terms;
4557
4560
  const acceptControl = (_a = terms == null ? void 0 : terms.acceptControl) != null ? _a : "checkbox";
4558
4561
  const handleSubmit = (e) => {
4562
+ var _a2;
4559
4563
  e.preventDefault();
4560
4564
  setSubmitAttempted(true);
4561
4565
  const hasRequiredEmpty = sortedFields.some(
4562
4566
  (f) => f.required && isFieldEmpty(f, current[f.id])
4563
4567
  );
4564
- if (hasRequiredEmpty || termsEnabled && !termsAccepted) return;
4568
+ const extraErrors = (_a2 = onValidate == null ? void 0 : onValidate(current)) != null ? _a2 : {};
4569
+ setValidationErrors(extraErrors);
4570
+ if (hasRequiredEmpty || Object.keys(extraErrors).length > 0 || termsEnabled && !termsAccepted) return;
4565
4571
  onSubmit == null ? void 0 : onSubmit(current);
4566
4572
  };
4567
4573
  const dateRange = formatDateRange(adventure, dateFormatter);
@@ -4573,7 +4579,24 @@ function RegistrationForm({
4573
4579
  fieldErrors[field.id] = L.requiredFieldError;
4574
4580
  }
4575
4581
  }
4582
+ for (const [id, msg] of Object.entries(validationErrors)) {
4583
+ if (!fieldErrors[id]) fieldErrors[id] = msg;
4584
+ }
4585
+ if (externalErrors) {
4586
+ for (const [id, msg] of Object.entries(externalErrors)) {
4587
+ if (!fieldErrors[id]) fieldErrors[id] = msg;
4588
+ }
4589
+ }
4576
4590
  }
4591
+ const firstErrorFieldId = Object.keys(fieldErrors)[0];
4592
+ React21.useEffect(() => {
4593
+ if (!submitAttempted || !firstErrorFieldId) return;
4594
+ const timer = setTimeout(() => {
4595
+ const elem = document.getElementById(`rf-${firstErrorFieldId}`);
4596
+ if (elem) elem.scrollIntoView({ behavior: "smooth", block: "center" });
4597
+ }, 50);
4598
+ return () => clearTimeout(timer);
4599
+ }, [submitAttempted, firstErrorFieldId, validationErrors]);
4577
4600
  return /* @__PURE__ */ jsxs(
4578
4601
  "form",
4579
4602
  {
@@ -4625,31 +4648,31 @@ function RegistrationForm({
4625
4648
  /* @__PURE__ */ jsx("h2", { className: "text-2xl font-black uppercase tracking-wide text-foreground font-heading leading-tight", children: title }),
4626
4649
  /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm text-muted-foreground font-ui", children: subtitle != null ? subtitle : L.formSubtitle })
4627
4650
  ] }),
4628
- hasTripInfo && /* @__PURE__ */ jsx(FormSection2, { title: L.tripInfoSectionTitle, children: /* @__PURE__ */ jsxs("dl", { className: "grid grid-cols-1 gap-x-6 gap-y-3 text-sm font-ui sm:grid-cols-[max-content_1fr]", children: [
4629
- adventure && /* @__PURE__ */ jsxs(Fragment, { children: [
4651
+ hasTripInfo && /* @__PURE__ */ jsx(FormSection2, { title: L.tripInfoSectionTitle, children: /* @__PURE__ */ jsxs("dl", { className: "flex flex-col gap-y-3 text-sm font-ui", children: [
4652
+ adventure && /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-x-4", children: [
4630
4653
  /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: L.adventureLabel }),
4631
- /* @__PURE__ */ jsx("dd", { className: "text-foreground font-medium", children: adventure.name })
4654
+ /* @__PURE__ */ jsx("dd", { className: "text-foreground font-medium text-right min-w-0 break-words", children: adventure.name })
4632
4655
  ] }),
4633
- dateRange && /* @__PURE__ */ jsxs(Fragment, { children: [
4656
+ dateRange && /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-x-4", children: [
4634
4657
  /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: (adventure == null ? void 0 : adventure.startDate) && (adventure == null ? void 0 : adventure.endDate) ? "Dates" : "Date" }),
4635
- /* @__PURE__ */ jsx("dd", { className: "text-foreground", children: dateRange })
4658
+ /* @__PURE__ */ jsx("dd", { className: "text-foreground text-right min-w-0", children: dateRange })
4636
4659
  ] }),
4637
- (adventure == null ? void 0 : adventure.partnerName) && /* @__PURE__ */ jsxs(Fragment, { children: [
4660
+ (adventure == null ? void 0 : adventure.partnerName) && /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-x-4", children: [
4638
4661
  /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: L.partnerLabel }),
4639
- /* @__PURE__ */ jsx("dd", { className: "text-foreground", children: adventure.partnerName })
4662
+ /* @__PURE__ */ jsx("dd", { className: "text-foreground text-right min-w-0", children: adventure.partnerName })
4640
4663
  ] }),
4641
- booking && /* @__PURE__ */ jsxs(Fragment, { children: [
4664
+ booking && /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-x-4", children: [
4642
4665
  /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: L.bookingLabel }),
4643
- /* @__PURE__ */ jsx("dd", { className: "text-foreground font-mono tabular-nums", children: booking.id })
4666
+ /* @__PURE__ */ jsx("dd", { className: "text-foreground font-mono tabular-nums text-right min-w-0", children: booking.id })
4644
4667
  ] }),
4645
- traveller && /* @__PURE__ */ jsxs(Fragment, { children: [
4668
+ traveller && /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-x-4", children: [
4646
4669
  /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: L.travellerLabel }),
4647
- /* @__PURE__ */ jsx("dd", { className: "text-foreground font-medium", children: traveller.fullName })
4670
+ /* @__PURE__ */ jsx("dd", { className: "text-foreground font-medium text-right min-w-0 break-words", children: traveller.fullName })
4648
4671
  ] })
4649
4672
  ] }) }),
4650
4673
  /* @__PURE__ */ jsx(FormSection2, { title: L.detailsSectionTitle, children: sortedFields.map((field) => {
4651
4674
  var _a2;
4652
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
4675
+ return /* @__PURE__ */ jsxs("div", { id: `rf-${field.id}`, className: "flex flex-col gap-1.5", children: [
4653
4676
  /* @__PURE__ */ jsx(
4654
4677
  FieldRenderer,
4655
4678
  {
@@ -4837,9 +4860,9 @@ function RegistrationSuccessCard({
4837
4860
  /* @__PURE__ */ jsx("h2", { className: "text-2xl font-black uppercase tracking-wide text-foreground font-heading leading-tight", children: title }),
4838
4861
  /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground font-ui", children: message })
4839
4862
  ] }),
4840
- sorted.length > 0 && /* @__PURE__ */ jsx(FormSection2, { title: answersTitle, children: /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-1 gap-x-6 gap-y-3 text-sm font-ui sm:grid-cols-[max-content_1fr]", children: sorted.map((f) => /* @__PURE__ */ jsxs(React21.Fragment, { children: [
4863
+ sorted.length > 0 && /* @__PURE__ */ jsx(FormSection2, { title: answersTitle, children: /* @__PURE__ */ jsx("dl", { className: "flex flex-col gap-y-3 text-sm font-ui", children: sorted.map((f) => /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-x-4", children: [
4841
4864
  /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: f.label }),
4842
- /* @__PURE__ */ jsx("dd", { className: "text-foreground", children: (formatAnswer != null ? formatAnswer : ((field, v) => defaultFormatAnswer(field, v, dateFormatter)))(
4865
+ /* @__PURE__ */ jsx("dd", { className: "text-foreground text-right min-w-0 break-words", children: (formatAnswer != null ? formatAnswer : ((field, v) => defaultFormatAnswer(field, v, dateFormatter)))(
4843
4866
  f,
4844
4867
  answers[f.id]
4845
4868
  ) })