@planetaexo/design-system 0.4.11 → 0.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1209,7 +1209,7 @@ function CountrySearchField({
1209
1209
  type: "button",
1210
1210
  onClick: () => handleSelect(c.code),
1211
1211
  className: cn(
1212
- "flex w-full items-center px-3 py-2 text-sm font-ui text-left transition-colors hover:bg-muted",
1212
+ "flex w-full items-center px-3 py-2 text-sm font-ui text-left text-foreground transition-colors hover:bg-muted",
1213
1213
  c.code === value && "bg-primary/10 text-primary font-semibold"
1214
1214
  ),
1215
1215
  children: c.name
@@ -4232,6 +4232,83 @@ function FloatingTextarea({
4232
4232
  )
4233
4233
  ] });
4234
4234
  }
4235
+ function SelectField({ field, value, onChange, error }) {
4236
+ var _a, _b, _c;
4237
+ const [open, setOpen] = React21__namespace.useState(false);
4238
+ const containerRef = React21__namespace.useRef(null);
4239
+ const options = (_a = field.options) != null ? _a : [];
4240
+ const selectedOpt = (_b = options.find((o) => o.value === value)) != null ? _b : null;
4241
+ React21__namespace.useEffect(() => {
4242
+ if (!open) return;
4243
+ const handleOutside = (e) => {
4244
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
4245
+ setOpen(false);
4246
+ }
4247
+ };
4248
+ document.addEventListener("mousedown", handleOutside);
4249
+ return () => document.removeEventListener("mousedown", handleOutside);
4250
+ }, [open]);
4251
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: "relative w-full", children: [
4252
+ /* @__PURE__ */ jsxRuntime.jsxs(
4253
+ "button",
4254
+ {
4255
+ type: "button",
4256
+ onClick: () => setOpen((o) => !o),
4257
+ className: cn(
4258
+ "relative flex w-full items-center rounded-lg border border-border bg-background h-14 px-3 text-left transition-colors",
4259
+ open && "border-primary ring-1 ring-primary",
4260
+ error && !open && "border-destructive"
4261
+ ),
4262
+ children: [
4263
+ /* @__PURE__ */ jsxRuntime.jsxs(
4264
+ "span",
4265
+ {
4266
+ className: cn(
4267
+ "pointer-events-none absolute left-3 transition-all duration-150 font-ui",
4268
+ selectedOpt || open ? cn("top-2 text-xs", open ? "text-primary" : "text-muted-foreground") : "top-1/2 -translate-y-1/2 text-base text-muted-foreground"
4269
+ ),
4270
+ children: [
4271
+ field.label,
4272
+ field.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-primary ml-0.5", children: "*" })
4273
+ ]
4274
+ }
4275
+ ),
4276
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-1 pt-3 text-base font-ui truncate", selectedOpt ? "text-foreground" : "invisible"), children: (_c = selectedOpt == null ? void 0 : selectedOpt.label) != null ? _c : "\u2014" }),
4277
+ /* @__PURE__ */ jsxRuntime.jsx(
4278
+ "svg",
4279
+ {
4280
+ className: cn("h-4 w-4 shrink-0 text-muted-foreground transition-transform", open && "rotate-180"),
4281
+ viewBox: "0 0 24 24",
4282
+ fill: "none",
4283
+ stroke: "currentColor",
4284
+ strokeWidth: "2",
4285
+ strokeLinecap: "round",
4286
+ strokeLinejoin: "round",
4287
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" })
4288
+ }
4289
+ )
4290
+ ]
4291
+ }
4292
+ ),
4293
+ open && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-[calc(100%+4px)] left-0 right-0 z-50 rounded-xl border border-border bg-background shadow-lg overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-52 overflow-y-auto py-1", children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(
4294
+ "button",
4295
+ {
4296
+ type: "button",
4297
+ onClick: () => {
4298
+ onChange(opt.value);
4299
+ setOpen(false);
4300
+ },
4301
+ className: cn(
4302
+ "flex w-full items-center px-3 py-2 text-sm font-ui text-left text-foreground transition-colors hover:bg-muted",
4303
+ opt.value === value && "bg-primary/10 text-primary font-semibold"
4304
+ ),
4305
+ children: opt.label
4306
+ },
4307
+ opt.value
4308
+ )) }) }),
4309
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-destructive font-ui", children: error })
4310
+ ] });
4311
+ }
4235
4312
  function FieldRenderer({
4236
4313
  field,
4237
4314
  value,
@@ -4240,7 +4317,7 @@ function FieldRenderer({
4240
4317
  labels,
4241
4318
  error
4242
4319
  }) {
4243
- var _a, _b, _c;
4320
+ var _a, _b;
4244
4321
  const fieldId = `rf-${field.id}`;
4245
4322
  if (field.type === "name") {
4246
4323
  const v = asName(value);
@@ -4354,24 +4431,18 @@ function FieldRenderer({
4354
4431
  );
4355
4432
  }
4356
4433
  if (field.type === "select") {
4357
- const options = (_a = field.options) != null ? _a : [];
4358
- return /* @__PURE__ */ jsxRuntime.jsxs(
4359
- FloatingSelect,
4434
+ return /* @__PURE__ */ jsxRuntime.jsx(
4435
+ SelectField,
4360
4436
  {
4361
- label: field.label,
4362
- required: field.required,
4437
+ field,
4363
4438
  value: typeof value === "string" ? value : "",
4364
- onChange: (e) => onChange(e.target.value),
4365
- error,
4366
- children: [
4367
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, hidden: true }),
4368
- options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
4369
- ]
4439
+ onChange: (v) => onChange(v),
4440
+ error
4370
4441
  }
4371
4442
  );
4372
4443
  }
4373
4444
  if (field.type === "radio") {
4374
- const options = (_b = field.options) != null ? _b : [];
4445
+ const options = (_a = field.options) != null ? _a : [];
4375
4446
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4376
4447
  /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mb-3 text-sm font-ui font-medium text-foreground", children: [
4377
4448
  field.label,
@@ -4406,11 +4477,12 @@ function FieldRenderer({
4406
4477
  opt.value
4407
4478
  ))
4408
4479
  }
4409
- )
4480
+ ),
4481
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-xs text-destructive font-ui", children: error })
4410
4482
  ] });
4411
4483
  }
4412
4484
  if (field.type === "checkbox") {
4413
- const options = (_c = field.options) != null ? _c : [];
4485
+ const options = (_b = field.options) != null ? _b : [];
4414
4486
  if (options.length === 0) {
4415
4487
  return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex min-h-9 cursor-pointer items-center gap-2.5 font-ui text-sm text-foreground", children: [
4416
4488
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -4609,15 +4681,17 @@ function RegistrationForm({
4609
4681
  }
4610
4682
  }
4611
4683
  }
4684
+ const termsError = submitAttempted && termsEnabled && !termsAccepted;
4612
4685
  const firstErrorFieldId = Object.keys(fieldErrors)[0];
4686
+ const scrollTargetId = firstErrorFieldId ? `rf-${firstErrorFieldId}` : termsError ? "rf-terms" : null;
4613
4687
  React21__namespace.useEffect(() => {
4614
- if (!submitAttempted || !firstErrorFieldId) return;
4688
+ if (!submitAttempted || !scrollTargetId) return;
4615
4689
  const timer = setTimeout(() => {
4616
- const elem = document.getElementById(`rf-${firstErrorFieldId}`);
4690
+ const elem = document.getElementById(scrollTargetId);
4617
4691
  if (elem) elem.scrollIntoView({ behavior: "smooth", block: "center" });
4618
4692
  }, 50);
4619
4693
  return () => clearTimeout(timer);
4620
- }, [submitAttempted, firstErrorFieldId, validationErrors]);
4694
+ }, [submitAttempted, scrollTargetId]);
4621
4695
  return /* @__PURE__ */ jsxRuntime.jsxs(
4622
4696
  "form",
4623
4697
  {
@@ -4708,58 +4782,86 @@ function RegistrationForm({
4708
4782
  ((_a2 = field.helpText) == null ? void 0 : _a2.trim()) && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground font-ui leading-relaxed", children: field.helpText.trim() })
4709
4783
  ] }, field.id);
4710
4784
  }) }),
4711
- termsEnabled && terms && /* @__PURE__ */ jsxRuntime.jsxs(FormSection2, { title: L.termsSectionTitle, children: [
4785
+ termsEnabled && terms && /* @__PURE__ */ jsxRuntime.jsx("div", { id: "rf-terms", children: /* @__PURE__ */ jsxRuntime.jsxs(FormSection2, { title: L.termsSectionTitle, children: [
4712
4786
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-72 overflow-y-auto rounded-lg border border-border bg-muted/30 p-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "whitespace-pre-wrap text-sm leading-relaxed text-foreground font-ui", children: terms.markdown }) }),
4713
- acceptControl === "checkbox" ? /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex cursor-pointer items-start gap-2.5 font-ui text-sm text-foreground", children: [
4714
- /* @__PURE__ */ jsxRuntime.jsx(
4715
- "input",
4787
+ acceptControl === "checkbox" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
4788
+ /* @__PURE__ */ jsxRuntime.jsxs(
4789
+ "label",
4716
4790
  {
4717
- type: "checkbox",
4718
- checked: termsAccepted,
4719
- required: true,
4720
- onChange: (e) => setField(TERMS_ACCEPT_KEY, e.target.checked),
4721
- className: "mt-0.5 h-4 w-4 shrink-0 accent-primary cursor-pointer"
4722
- }
4723
- ),
4724
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: L.termsAccept })
4725
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(
4726
- "div",
4727
- {
4728
- role: "radiogroup",
4729
- "aria-label": L.termsSectionTitle,
4730
- className: "flex flex-wrap items-center gap-x-6 gap-y-3",
4731
- children: [
4732
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex min-h-9 cursor-pointer items-center gap-2.5 font-ui text-sm text-foreground", children: [
4791
+ className: cn(
4792
+ "flex cursor-pointer items-start gap-2.5 font-ui text-sm",
4793
+ termsError ? "text-destructive" : "text-foreground"
4794
+ ),
4795
+ children: [
4733
4796
  /* @__PURE__ */ jsxRuntime.jsx(
4734
4797
  "input",
4735
4798
  {
4736
- type: "radio",
4737
- name: "registration-terms-accept",
4799
+ type: "checkbox",
4738
4800
  checked: termsAccepted,
4739
4801
  required: true,
4740
- onChange: () => setField(TERMS_ACCEPT_KEY, true),
4741
- className: "h-4 w-4 shrink-0 accent-primary cursor-pointer"
4802
+ onChange: (e) => setField(TERMS_ACCEPT_KEY, e.target.checked),
4803
+ className: "mt-0.5 h-4 w-4 shrink-0 accent-primary cursor-pointer"
4742
4804
  }
4743
4805
  ),
4744
- L.termsAccept
4745
- ] }),
4746
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex min-h-9 cursor-pointer items-center gap-2.5 font-ui text-sm text-muted-foreground", children: [
4747
- /* @__PURE__ */ jsxRuntime.jsx(
4748
- "input",
4806
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
4807
+ L.termsAccept,
4808
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-primary ml-0.5", children: "*" })
4809
+ ] })
4810
+ ]
4811
+ }
4812
+ ),
4813
+ termsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive font-ui", children: L.requiredFieldError })
4814
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
4815
+ /* @__PURE__ */ jsxRuntime.jsxs(
4816
+ "div",
4817
+ {
4818
+ role: "radiogroup",
4819
+ "aria-label": L.termsSectionTitle,
4820
+ className: "flex flex-wrap items-center gap-x-6 gap-y-3",
4821
+ children: [
4822
+ /* @__PURE__ */ jsxRuntime.jsxs(
4823
+ "label",
4749
4824
  {
4750
- type: "radio",
4751
- name: "registration-terms-accept",
4752
- checked: current[TERMS_ACCEPT_KEY] === false,
4753
- onChange: () => setField(TERMS_ACCEPT_KEY, false),
4754
- className: "h-4 w-4 shrink-0 accent-primary cursor-pointer"
4825
+ className: cn(
4826
+ "flex min-h-9 cursor-pointer items-center gap-2.5 font-ui text-sm",
4827
+ termsError ? "text-destructive" : "text-foreground"
4828
+ ),
4829
+ children: [
4830
+ /* @__PURE__ */ jsxRuntime.jsx(
4831
+ "input",
4832
+ {
4833
+ type: "radio",
4834
+ name: "registration-terms-accept",
4835
+ checked: termsAccepted,
4836
+ required: true,
4837
+ onChange: () => setField(TERMS_ACCEPT_KEY, true),
4838
+ className: "h-4 w-4 shrink-0 accent-primary cursor-pointer"
4839
+ }
4840
+ ),
4841
+ L.termsAccept,
4842
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-primary ml-0.5", children: "*" })
4843
+ ]
4755
4844
  }
4756
4845
  ),
4757
- L.termsDecline
4758
- ] })
4759
- ]
4760
- }
4761
- )
4762
- ] }),
4846
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex min-h-9 cursor-pointer items-center gap-2.5 font-ui text-sm text-muted-foreground", children: [
4847
+ /* @__PURE__ */ jsxRuntime.jsx(
4848
+ "input",
4849
+ {
4850
+ type: "radio",
4851
+ name: "registration-terms-accept",
4852
+ checked: current[TERMS_ACCEPT_KEY] === false,
4853
+ onChange: () => setField(TERMS_ACCEPT_KEY, false),
4854
+ className: "h-4 w-4 shrink-0 accent-primary cursor-pointer"
4855
+ }
4856
+ ),
4857
+ L.termsDecline
4858
+ ] })
4859
+ ]
4860
+ }
4861
+ ),
4862
+ termsError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive font-ui", children: L.requiredFieldError })
4863
+ ] })
4864
+ ] }) }),
4763
4865
  error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-sm text-destructive font-ui", children: error }),
4764
4866
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center pt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
4765
4867
  "button",