@planetaexo/design-system 0.2.14 → 0.2.15

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
@@ -16,6 +16,7 @@ var checkbox = require('@base-ui/react/checkbox');
16
16
  var accordion = require('@base-ui/react/accordion');
17
17
  var mergeProps = require('@base-ui/react/merge-props');
18
18
  var useRender = require('@base-ui/react/use-render');
19
+ var input = require('@base-ui/react/input');
19
20
 
20
21
  function _interopNamespace(e) {
21
22
  if (e && e.__esModule) return e;
@@ -6274,6 +6275,368 @@ function ActivityCard({
6274
6275
  }
6275
6276
  );
6276
6277
  }
6278
+ function Input(_a) {
6279
+ var _b = _a, { className, type } = _b, props = __objRest(_b, ["className", "type"]);
6280
+ return /* @__PURE__ */ jsxRuntime.jsx(
6281
+ input.Input,
6282
+ __spreadValues({
6283
+ type,
6284
+ "data-slot": "input",
6285
+ className: cn(
6286
+ "h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
6287
+ className
6288
+ )
6289
+ }, props)
6290
+ );
6291
+ }
6292
+ function Label(_a) {
6293
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
6294
+ return /* @__PURE__ */ jsxRuntime.jsx(
6295
+ "label",
6296
+ __spreadValues({
6297
+ "data-slot": "label",
6298
+ className: cn(
6299
+ "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
6300
+ className
6301
+ )
6302
+ }, props)
6303
+ );
6304
+ }
6305
+ var DEFAULTS = {
6306
+ heading: "Where will your next adventure take you?",
6307
+ subtitle: "Tell us about your dream trip and our travel experts will craft the perfect itinerary for you.",
6308
+ nameLabel: "Your name",
6309
+ namePlaceholder: "e.g. Maria Silva",
6310
+ emailLabel: "Email",
6311
+ emailPlaceholder: "you@example.com",
6312
+ travelDateLabel: "When are you planning to travel?",
6313
+ travelDateOptions: [
6314
+ "In the next 30 days",
6315
+ "1 \u2013 3 months from now",
6316
+ "3 \u2013 6 months from now",
6317
+ "6 \u2013 12 months from now",
6318
+ "I'm just exploring"
6319
+ ],
6320
+ submitLabel: "Send my request",
6321
+ successHeading: "Thank you!",
6322
+ successMessage: "One of our travel experts will reach out soon to help plan your perfect trip.",
6323
+ privacyText: 'By submitting you agree to our <a href="/privacy-policy" target="_blank" rel="noopener">Privacy Policy</a>.',
6324
+ trigger: "delay",
6325
+ delaySeconds: 5,
6326
+ scrollPercent: 50,
6327
+ dismissDays: 7,
6328
+ overlayOpacity: 40,
6329
+ position: "center"
6330
+ };
6331
+ var COOKIE_NAME = "pexo_lead_popup_dismissed";
6332
+ function isDismissed() {
6333
+ return document.cookie.includes(`${COOKIE_NAME}=1`);
6334
+ }
6335
+ function setDismissed(days) {
6336
+ const expires = new Date(Date.now() + days * 864e5).toUTCString();
6337
+ document.cookie = `${COOKIE_NAME}=1; expires=${expires}; path=/; SameSite=Lax`;
6338
+ }
6339
+ function LeadCapturePopup({
6340
+ config: _config
6341
+ }) {
6342
+ var _a;
6343
+ const config = __spreadValues(__spreadValues({}, DEFAULTS), _config);
6344
+ const [open, setOpen] = React18.useState(false);
6345
+ const [closing, setClosing] = React18.useState(false);
6346
+ const [submitted, setSubmitted] = React18.useState(false);
6347
+ const [submitting, setSubmitting] = React18.useState(false);
6348
+ const [error, setError] = React18.useState(null);
6349
+ const [name, setName] = React18.useState("");
6350
+ const [email, setEmail] = React18.useState("");
6351
+ const [travelDate, setTravelDate] = React18.useState("");
6352
+ const panelRef = React18.useRef(null);
6353
+ const nameRef = React18.useRef(null);
6354
+ const show = React18.useCallback(() => {
6355
+ if (isDismissed()) return;
6356
+ setOpen(true);
6357
+ }, []);
6358
+ React18.useEffect(() => {
6359
+ var _a2;
6360
+ if (isDismissed()) return;
6361
+ if (config.trigger === "delay") {
6362
+ const t = setTimeout(show, ((_a2 = config.delaySeconds) != null ? _a2 : 5) * 1e3);
6363
+ return () => clearTimeout(t);
6364
+ }
6365
+ if (config.trigger === "exit_intent") {
6366
+ const handler = (e) => {
6367
+ if (e.clientY <= 5) show();
6368
+ };
6369
+ document.addEventListener("mouseout", handler);
6370
+ return () => document.removeEventListener("mouseout", handler);
6371
+ }
6372
+ if (config.trigger === "scroll") {
6373
+ const handler = () => {
6374
+ var _a3;
6375
+ const pct = window.scrollY / (document.documentElement.scrollHeight - window.innerHeight) * 100;
6376
+ if (pct >= ((_a3 = config.scrollPercent) != null ? _a3 : 50)) {
6377
+ show();
6378
+ window.removeEventListener("scroll", handler);
6379
+ }
6380
+ };
6381
+ window.addEventListener("scroll", handler, { passive: true });
6382
+ return () => window.removeEventListener("scroll", handler);
6383
+ }
6384
+ }, [config.trigger, config.delaySeconds, config.scrollPercent, show]);
6385
+ React18.useEffect(() => {
6386
+ if (open && !submitted) {
6387
+ requestAnimationFrame(() => {
6388
+ var _a2;
6389
+ return (_a2 = nameRef.current) == null ? void 0 : _a2.focus();
6390
+ });
6391
+ }
6392
+ }, [open, submitted]);
6393
+ const close = React18.useCallback(() => {
6394
+ setClosing(true);
6395
+ setDismissed(config.dismissDays);
6396
+ setTimeout(() => {
6397
+ setOpen(false);
6398
+ setClosing(false);
6399
+ }, 250);
6400
+ }, [config.dismissDays]);
6401
+ React18.useEffect(() => {
6402
+ if (!open) return;
6403
+ const handler = (e) => {
6404
+ if (e.key === "Escape") close();
6405
+ };
6406
+ document.addEventListener("keydown", handler);
6407
+ return () => document.removeEventListener("keydown", handler);
6408
+ }, [open, close]);
6409
+ const onOverlayClick = React18.useCallback(
6410
+ (e) => {
6411
+ if (panelRef.current && !panelRef.current.contains(e.target)) {
6412
+ close();
6413
+ }
6414
+ },
6415
+ [close]
6416
+ );
6417
+ const handleSubmit = async (e) => {
6418
+ var _a2;
6419
+ e.preventDefault();
6420
+ setError(null);
6421
+ if (!name.trim() || !email.trim() || !travelDate) {
6422
+ setError("Please fill in all fields.");
6423
+ return;
6424
+ }
6425
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
6426
+ setError("Please enter a valid email address.");
6427
+ return;
6428
+ }
6429
+ setSubmitting(true);
6430
+ try {
6431
+ if (config.ajaxUrl) {
6432
+ const res = await fetch(config.ajaxUrl, {
6433
+ method: "POST",
6434
+ headers: { "Content-Type": "application/json" },
6435
+ body: JSON.stringify({
6436
+ name: name.trim(),
6437
+ email: email.trim(),
6438
+ travel_date: travelDate,
6439
+ nonce: (_a2 = config.nonce) != null ? _a2 : ""
6440
+ })
6441
+ });
6442
+ if (!res.ok) throw new Error("Server error");
6443
+ }
6444
+ setSubmitted(true);
6445
+ setDismissed(config.dismissDays);
6446
+ } catch (e2) {
6447
+ setError("Something went wrong. Please try again.");
6448
+ } finally {
6449
+ setSubmitting(false);
6450
+ }
6451
+ };
6452
+ if (!open) return null;
6453
+ const accentStyle = config.accentColor ? { "--popup-accent": config.accentColor } : void 0;
6454
+ const isCenter = config.position === "center";
6455
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6456
+ "div",
6457
+ {
6458
+ className: cn(
6459
+ "pexo-lead-popup fixed inset-0 z-[99999] flex",
6460
+ isCenter ? "items-center justify-center" : "items-end justify-end",
6461
+ closing ? "animate-fade-out" : "animate-fade-in"
6462
+ ),
6463
+ style: {
6464
+ backgroundColor: `rgba(0,0,0,${((_a = config.overlayOpacity) != null ? _a : 40) / 100})`,
6465
+ backdropFilter: "blur(4px)",
6466
+ WebkitBackdropFilter: "blur(4px)"
6467
+ },
6468
+ onClick: onOverlayClick,
6469
+ role: "dialog",
6470
+ "aria-modal": "true",
6471
+ "aria-label": config.heading,
6472
+ children: [
6473
+ /* @__PURE__ */ jsxRuntime.jsxs(
6474
+ "div",
6475
+ {
6476
+ ref: panelRef,
6477
+ className: cn(
6478
+ "relative flex flex-col overflow-hidden bg-background text-foreground shadow-2xl ring-1 ring-foreground/5",
6479
+ isCenter ? "m-4 w-full max-w-md rounded-2xl sm:max-w-lg" : "m-4 w-full max-w-sm rounded-2xl sm:m-6",
6480
+ closing ? isCenter ? "animate-zoom-out" : "animate-slide-out-right" : isCenter ? "animate-zoom-in" : "animate-slide-in-right"
6481
+ ),
6482
+ style: accentStyle,
6483
+ children: [
6484
+ /* @__PURE__ */ jsxRuntime.jsx(
6485
+ "button",
6486
+ {
6487
+ onClick: close,
6488
+ className: "absolute top-3 right-3 z-10 flex h-8 w-8 items-center justify-center rounded-full bg-black/30 text-white backdrop-blur-sm transition-colors hover:bg-black/50",
6489
+ "aria-label": "Close",
6490
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "h-4 w-4" })
6491
+ }
6492
+ ),
6493
+ config.imageUrl && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative h-44 w-full shrink-0 overflow-hidden sm:h-52", children: [
6494
+ /* @__PURE__ */ jsxRuntime.jsx(
6495
+ "img",
6496
+ {
6497
+ src: config.imageUrl,
6498
+ alt: "",
6499
+ className: "h-full w-full object-cover",
6500
+ loading: "eager"
6501
+ }
6502
+ ),
6503
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/50 to-transparent" })
6504
+ ] }),
6505
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-col gap-5 p-5 sm:p-6", children: !submitted ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6506
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
6507
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "font-heading text-lg font-bold leading-tight tracking-tight text-foreground sm:text-xl", children: config.heading }),
6508
+ config.subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm leading-relaxed text-muted-foreground", children: config.subtitle })
6509
+ ] }),
6510
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [
6511
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
6512
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "pexo-lead-name", className: "text-xs uppercase tracking-wider text-muted-foreground", children: config.nameLabel }),
6513
+ /* @__PURE__ */ jsxRuntime.jsx(
6514
+ Input,
6515
+ {
6516
+ ref: nameRef,
6517
+ id: "pexo-lead-name",
6518
+ type: "text",
6519
+ placeholder: config.namePlaceholder,
6520
+ value: name,
6521
+ onChange: (e) => setName(e.target.value),
6522
+ autoComplete: "name",
6523
+ className: "h-10 rounded-lg border-border/60 bg-muted/30 px-3 text-sm focus-visible:border-primary focus-visible:ring-primary/30"
6524
+ }
6525
+ )
6526
+ ] }),
6527
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
6528
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "pexo-lead-email", className: "text-xs uppercase tracking-wider text-muted-foreground", children: config.emailLabel }),
6529
+ /* @__PURE__ */ jsxRuntime.jsx(
6530
+ Input,
6531
+ {
6532
+ id: "pexo-lead-email",
6533
+ type: "email",
6534
+ placeholder: config.emailPlaceholder,
6535
+ value: email,
6536
+ onChange: (e) => setEmail(e.target.value),
6537
+ autoComplete: "email",
6538
+ className: "h-10 rounded-lg border-border/60 bg-muted/30 px-3 text-sm focus-visible:border-primary focus-visible:ring-primary/30"
6539
+ }
6540
+ )
6541
+ ] }),
6542
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
6543
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "pexo-lead-travel", className: "text-xs uppercase tracking-wider text-muted-foreground", children: config.travelDateLabel }),
6544
+ /* @__PURE__ */ jsxRuntime.jsxs(
6545
+ "select",
6546
+ {
6547
+ id: "pexo-lead-travel",
6548
+ value: travelDate,
6549
+ onChange: (e) => setTravelDate(e.target.value),
6550
+ className: cn(
6551
+ "h-10 w-full appearance-none rounded-lg border border-border/60 bg-muted/30 px-3 text-sm text-foreground outline-none transition-colors",
6552
+ "focus-visible:border-primary focus-visible:ring-3 focus-visible:ring-primary/30",
6553
+ !travelDate && "text-muted-foreground"
6554
+ ),
6555
+ style: {
6556
+ backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")`,
6557
+ backgroundRepeat: "no-repeat",
6558
+ backgroundPosition: "right 0.75rem center",
6559
+ paddingRight: "2.5rem"
6560
+ },
6561
+ children: [
6562
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: "Select a timeframe\u2026" }),
6563
+ config.travelDateOptions.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt, children: opt }, opt))
6564
+ ]
6565
+ }
6566
+ )
6567
+ ] }),
6568
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium text-destructive", role: "alert", children: error }),
6569
+ /* @__PURE__ */ jsxRuntime.jsxs(
6570
+ Button,
6571
+ {
6572
+ type: "submit",
6573
+ disabled: submitting,
6574
+ className: cn(
6575
+ "h-11 w-full gap-2 rounded-lg text-sm font-bold tracking-wide",
6576
+ config.accentColor ? "border-transparent text-white" : "bg-primary text-primary-foreground hover:bg-primary/90"
6577
+ ),
6578
+ style: config.accentColor ? { backgroundColor: config.accentColor } : void 0,
6579
+ children: [
6580
+ submitting ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2Icon, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SendIcon, { className: "h-4 w-4" }),
6581
+ submitting ? "Sending\u2026" : config.submitLabel
6582
+ ]
6583
+ }
6584
+ ),
6585
+ config.privacyText && /* @__PURE__ */ jsxRuntime.jsx(
6586
+ "p",
6587
+ {
6588
+ className: "text-center text-[11px] leading-relaxed text-muted-foreground [&_a]:underline [&_a]:underline-offset-2 [&_a]:hover:text-foreground",
6589
+ dangerouslySetInnerHTML: { __html: config.privacyText }
6590
+ }
6591
+ )
6592
+ ] })
6593
+ ] }) : (
6594
+ /* ---- Success state ---- */
6595
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-4 py-8 text-center", children: [
6596
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-16 w-16 items-center justify-center rounded-full bg-primary/10", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircleIcon, { className: "h-8 w-8 text-primary" }) }),
6597
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
6598
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "font-heading text-lg font-bold text-foreground", children: config.successHeading }),
6599
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm leading-relaxed text-muted-foreground", children: config.successMessage })
6600
+ ] }),
6601
+ /* @__PURE__ */ jsxRuntime.jsx(
6602
+ Button,
6603
+ {
6604
+ onClick: close,
6605
+ variant: "outline",
6606
+ className: "mt-2 h-10 px-6 text-sm",
6607
+ children: "Close"
6608
+ }
6609
+ )
6610
+ ] })
6611
+ ) })
6612
+ ]
6613
+ }
6614
+ ),
6615
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
6616
+ @keyframes pexo-fade-in { from { opacity: 0 } to { opacity: 1 } }
6617
+ @keyframes pexo-fade-out { from { opacity: 1 } to { opacity: 0 } }
6618
+ @keyframes pexo-zoom-in { from { opacity: 0; transform: scale(0.92) } to { opacity: 1; transform: scale(1) } }
6619
+ @keyframes pexo-zoom-out { from { opacity: 1; transform: scale(1) } to { opacity: 0; transform: scale(0.92) } }
6620
+ @keyframes pexo-slide-in-right { from { opacity: 0; transform: translateX(100%) } to { opacity: 1; transform: translateX(0) } }
6621
+ @keyframes pexo-slide-out-right { from { opacity: 1; transform: translateX(0) } to { opacity: 0; transform: translateX(100%) } }
6622
+
6623
+ .pexo-lead-popup .animate-fade-in { animation: pexo-fade-in 0.3s ease-out both }
6624
+ .pexo-lead-popup .animate-fade-out { animation: pexo-fade-out 0.25s ease-in both }
6625
+ .pexo-lead-popup .animate-zoom-in { animation: pexo-zoom-in 0.35s cubic-bezier(0.16,1,0.3,1) both }
6626
+ .pexo-lead-popup .animate-zoom-out { animation: pexo-zoom-out 0.25s ease-in both }
6627
+ .pexo-lead-popup .animate-slide-in-right { animation: pexo-slide-in-right 0.4s cubic-bezier(0.16,1,0.3,1) both }
6628
+ .pexo-lead-popup .animate-slide-out-right { animation: pexo-slide-out-right 0.3s ease-in both }
6629
+
6630
+ /* Ensure popup fonts inherit from design system */
6631
+ .pexo-lead-popup { font-family: var(--font-sans, "Literata", Georgia, serif); }
6632
+ .pexo-lead-popup h1, .pexo-lead-popup h2, .pexo-lead-popup h3 { font-family: var(--font-heading, "ArcaMajora3", sans-serif); }
6633
+ .pexo-lead-popup button, .pexo-lead-popup label { font-family: var(--font-ui, "ArcaMajora3", sans-serif); }
6634
+ .pexo-lead-popup select { font-family: var(--font-sans, "Literata", Georgia, serif); }
6635
+ ` })
6636
+ ]
6637
+ }
6638
+ );
6639
+ }
6277
6640
 
6278
6641
  exports.ActivityCard = ActivityCard;
6279
6642
  exports.BookingConfirmation = BookingConfirmation;
@@ -6290,6 +6653,7 @@ exports.FilterPanel = FilterPanel;
6290
6653
  exports.FloatingInput = FloatingInput;
6291
6654
  exports.FloatingSelect = FloatingSelect;
6292
6655
  exports.Itinerary = Itinerary;
6656
+ exports.LeadCapturePopup = LeadCapturePopup;
6293
6657
  exports.MenuTrip = MenuTrip;
6294
6658
  exports.Offer = Offer;
6295
6659
  exports.OfferAdventureCard = OfferAdventureCard;