@reblu/site-blocks 0.5.0 → 0.6.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.d.cts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { PageDetail, PageListItem, ShopProductListItem, ShopFacets } from '@reblu/site-contracts';
2
+ import { PageDetail, PageListItem, ShopProductListItem, ShopFacets, ShopOrder } from '@reblu/site-contracts';
3
+ import { ReactNode, FormEvent } from 'react';
3
4
 
4
5
  declare function readingTime(content: string | null | undefined): number | null;
5
6
 
@@ -383,4 +384,275 @@ interface ShopFiltersProps {
383
384
  declare function shouldRenderShopFilters(facets: ShopFacets, active?: ShopFiltersActive): boolean;
384
385
  declare function ShopFilters({ facets, hrefs, active, onChange, priceBands, labels, currencyCode, locale, className, }: ShopFiltersProps): react_jsx_runtime.JSX.Element | null;
385
386
 
386
- export { ALLOWED_YOUTUBE_HOSTS, DEFAULT_SHOP_PRICE_BANDS, MarkdownRenderer, type MarkdownRendererProps, ProductCard, type ProductCardProps, ProfileCard, type ProfileCardProps, SafeHtml, type SafeHtmlProps, type ShareUrls, type ShopFilterPriceBand, ShopFilters, type ShopFiltersActive, type ShopFiltersHrefs, type ShopFiltersLabels, type ShopFiltersProps, Specialty, type SpecialtyProps, Treatment, type TreatmentProps, buildShareUrls, formatPrice, isAllowedYouTubeHost, markdownToSafeHtml, readingTime, sanitizeHtml, shouldRenderShopFilters };
387
+ /**
388
+ * `AddToCartButton` — presentational add-to-cart CTA (REB-829). RSC-safe by
389
+ * construction (same contract as `ShopFilters`'s `OptionLink`): passing
390
+ * `onAddToCart` only makes sense from a Client Component, but the component
391
+ * itself carries no `'use client'` directive, so a Server Component may
392
+ * still render it WITHOUT the prop (e.g. a disabled preview state).
393
+ */
394
+ interface AddToCartButtonLabels {
395
+ add: string;
396
+ adding: string;
397
+ outOfStock: string;
398
+ }
399
+ interface AddToCartButtonProps {
400
+ onAddToCart?: () => void;
401
+ disabled?: boolean;
402
+ outOfStock?: boolean;
403
+ /** True while the add-to-cart call (or a navigation it triggers) is in flight. */
404
+ pending?: boolean;
405
+ labels?: Partial<AddToCartButtonLabels>;
406
+ className?: string;
407
+ }
408
+ declare function AddToCartButton({ onAddToCart, disabled, outOfStock, pending, labels, className, }: AddToCartButtonProps): react_jsx_runtime.JSX.Element;
409
+
410
+ /**
411
+ * `CartIcon` — presentational cart badge/link (REB-829). RSC-safe (plain
412
+ * `<a href>`, no hooks) — a Server Component can render it directly with a
413
+ * value already computed server-side; a Client Component drives `itemCount`
414
+ * from `@reblu/site-next/cart`'s `useCart().itemCount`.
415
+ */
416
+ interface CartIconLabels {
417
+ cart: string;
418
+ itemsSuffix: (count: number) => string;
419
+ }
420
+ interface CartIconProps {
421
+ itemCount: number;
422
+ href: string;
423
+ labels?: Partial<CartIconLabels>;
424
+ className?: string;
425
+ }
426
+ declare function CartIcon({ itemCount, href, labels, className }: CartIconProps): react_jsx_runtime.JSX.Element;
427
+
428
+ /**
429
+ * `CartLineList` — presentational cart lines (REB-829), container/
430
+ * presentational split: it takes `items` + optional `onQuantityChange`/
431
+ * `onRemove` callbacks, never fetches or owns cart state itself. The
432
+ * consuming SITE wires these to `@reblu/site-next/cart`'s `useCart()`.
433
+ *
434
+ * RSC-safe by construction (same `OptionLink` contract as `ShopFilters`):
435
+ * the quantity stepper/remove buttons only do anything when `onQuantityChange`/
436
+ * `onRemove` are supplied from a Client Component — omit them from a Server
437
+ * Component to render a read-only summary instead.
438
+ */
439
+ interface CartLineItemView {
440
+ productId: string;
441
+ variantId?: string | null;
442
+ name: string;
443
+ variantName?: string;
444
+ /** Integer cents. */
445
+ unitPrice: number;
446
+ quantity: number;
447
+ imageUrl?: string;
448
+ /** `null`/`undefined` = untracked stock — never clamps the stepper's max. */
449
+ maxStock?: number | null;
450
+ }
451
+ interface CartLineListLabels {
452
+ quantityLabel: string;
453
+ decrease: string;
454
+ increase: string;
455
+ remove: string;
456
+ unitPriceSuffix: string;
457
+ }
458
+ interface CartLineListProps {
459
+ items: CartLineItemView[];
460
+ onQuantityChange?: (productId: string, variantId: string | null | undefined, quantity: number) => void;
461
+ onRemove?: (productId: string, variantId: string | null | undefined) => void;
462
+ /**
463
+ * A visually-hidden `aria-live="polite"` announcement (e.g. "Cantidad
464
+ * actualizada", "Producto eliminado del carrito") — the consuming SITE
465
+ * decides WHEN to set it (after a successful mutation), this component
466
+ * only renders the live region.
467
+ */
468
+ liveMessage?: string;
469
+ labels?: Partial<CartLineListLabels>;
470
+ currencyCode?: string;
471
+ locale?: string;
472
+ className?: string;
473
+ }
474
+ declare function CartLineList({ items, onQuantityChange, onRemove, liveMessage, labels, currencyCode, locale, className, }: CartLineListProps): react_jsx_runtime.JSX.Element;
475
+
476
+ /**
477
+ * `CartSummary` — presentational price breakdown (REB-829): subtotal,
478
+ * optional discount, optional shipping (sourced from `ShopConfig` by the
479
+ * consuming SITE — this component only renders what it's given), and total.
480
+ * Pure data in, RSC-safe (no hooks, no callbacks).
481
+ */
482
+ interface CartSummaryLabels {
483
+ subtotal: string;
484
+ discountPrefix: string;
485
+ shipping: string;
486
+ freeShipping: string;
487
+ /**
488
+ * Shown when `shipping` is `null`/`undefined` (unknown yet) — REB-829
489
+ * review finding: this is NOT the same state as `0` (confirmed free).
490
+ * Claiming "free shipping" for an amount the SITE simply hasn't computed
491
+ * yet understates the real total and is reversed at checkout.
492
+ */
493
+ shippingCalculated: string;
494
+ total: string;
495
+ }
496
+ interface CartSummaryProps {
497
+ /** Integer cents. */
498
+ subtotal: number;
499
+ /** Integer cents, positive. Omit (or `0`) to hide the discount line. */
500
+ discount?: number;
501
+ /** The applied discount code, shown next to the discount amount. */
502
+ discountCode?: string;
503
+ /** Integer cents. Only rendered when `shippingEnabled` is true. */
504
+ shipping?: number | null;
505
+ /** Whether this tenant's shop even has shipping cost — hides the line entirely when false/omitted. */
506
+ shippingEnabled?: boolean;
507
+ /** Integer cents — the final charged amount. */
508
+ total: number;
509
+ labels?: Partial<CartSummaryLabels>;
510
+ currencyCode?: string;
511
+ locale?: string;
512
+ className?: string;
513
+ }
514
+ declare function CartSummary({ subtotal, discount, discountCode, shipping, shippingEnabled, total, labels, currencyCode, locale, className, }: CartSummaryProps): react_jsx_runtime.JSX.Element;
515
+
516
+ /**
517
+ * `CheckoutLoginPrompt` — the "login prompt hook" the checkout flow needs
518
+ * (REB-829): a guest-checkout identification dialog offering "continue with
519
+ * this email" (so the SITE can check for an existing account via
520
+ * `client.shop.checkEmail`) or "continue as guest" outright. Fully
521
+ * controlled/presentational — it performs NO fetch itself (unlike
522
+ * demo-site's original `CheckoutLoginModal`, which called
523
+ * `/api/shop/check-email` internally); the consuming SITE owns `email`
524
+ * state and the `checkEmail` call, and drives `checking`/`error` from its
525
+ * own result.
526
+ */
527
+ interface CheckoutLoginPromptLabels {
528
+ title: string;
529
+ description: string;
530
+ emailLabel: string;
531
+ emailPlaceholder: string;
532
+ continueWithEmail: string;
533
+ checking: string;
534
+ continueAsGuest: string;
535
+ close: string;
536
+ }
537
+ interface CheckoutLoginPromptProps {
538
+ open: boolean;
539
+ email: string;
540
+ onEmailChange: (value: string) => void;
541
+ onClose: () => void;
542
+ /** Called when the visitor confirms a (valid-looking) email. */
543
+ onSubmitEmail: () => void;
544
+ onContinueAsGuest: () => void;
545
+ checking?: boolean;
546
+ error?: string | null;
547
+ labels?: Partial<CheckoutLoginPromptLabels>;
548
+ className?: string;
549
+ }
550
+ declare function CheckoutLoginPrompt({ open, email, onEmailChange, onClose, onSubmitEmail, onContinueAsGuest, checking, error, labels, className, }: CheckoutLoginPromptProps): react_jsx_runtime.JSX.Element | null;
551
+
552
+ /**
553
+ * `CheckoutForm` — presentational guest-checkout form (REB-829): contact
554
+ * fields, a discount-code section, an optional `loginPrompt` slot, and the
555
+ * submit CTA. Fully controlled — `values`/callbacks only, no internal state,
556
+ * no fetch, no react-hook-form/zod dependency (keeping this package's
557
+ * dependency surface minimal); the consuming SITE owns validation and wires
558
+ * its own `onSubmit`.
559
+ *
560
+ * Scope note: shipping/billing address collection is intentionally OUT of
561
+ * this component — those field sets vary by tenant shop config (shipping
562
+ * enabled/disabled, invoicing requirements) far more than the guest-email +
563
+ * discount-code flow the issue named. A SITE that needs them renders its own
564
+ * fields via the `children` slot, rendered between the contact and discount
565
+ * sections.
566
+ */
567
+ interface CheckoutContactValues {
568
+ name: string;
569
+ email: string;
570
+ phone?: string;
571
+ }
572
+ type CheckoutContactErrors = Partial<Record<keyof CheckoutContactValues, string>>;
573
+ interface CheckoutAppliedDiscount {
574
+ code: string;
575
+ amount: number;
576
+ }
577
+ interface CheckoutFormLabels {
578
+ contactTitle: string;
579
+ nameLabel: string;
580
+ namePlaceholder: string;
581
+ emailLabel: string;
582
+ emailPlaceholder: string;
583
+ phoneLabel: string;
584
+ discountTitle: string;
585
+ discountPlaceholder: string;
586
+ applyDiscount: string;
587
+ applyingDiscount: string;
588
+ removeDiscount: string;
589
+ discountAppliedSuffix: (formattedAmount: string) => string;
590
+ submit: string;
591
+ submitting: string;
592
+ }
593
+ interface CheckoutFormProps {
594
+ contact: CheckoutContactValues;
595
+ onContactChange: (values: CheckoutContactValues) => void;
596
+ contactErrors?: CheckoutContactErrors;
597
+ discountCode: string;
598
+ onDiscountCodeChange: (value: string) => void;
599
+ onApplyDiscount: () => void;
600
+ onRemoveDiscount: () => void;
601
+ appliedDiscount?: CheckoutAppliedDiscount | null;
602
+ discountApplying?: boolean;
603
+ discountError?: string | null;
604
+ /**
605
+ * Rendered OUTSIDE the `<form>`, immediately before it — e.g. the
606
+ * `CheckoutLoginPrompt` dialog. It must never render inside the `<form>`:
607
+ * an Enter keypress in one of ITS inputs would otherwise submit checkout
608
+ * (REB-829 review finding — see `handleDiscountCodeKeyDown` below for the
609
+ * same defect class).
610
+ */
611
+ loginPrompt?: ReactNode;
612
+ /** Rendered between the contact and discount sections — e.g. shipping/billing fields. */
613
+ children?: ReactNode;
614
+ submitting?: boolean;
615
+ submitDisabled?: boolean;
616
+ onSubmit: (event: FormEvent<HTMLFormElement>) => void;
617
+ labels?: Partial<CheckoutFormLabels>;
618
+ currencyCode?: string;
619
+ locale?: string;
620
+ className?: string;
621
+ }
622
+ declare function CheckoutForm({ contact, onContactChange, contactErrors, discountCode, onDiscountCodeChange, onApplyDiscount, onRemoveDiscount, appliedDiscount, discountApplying, discountError, loginPrompt, children, submitting, submitDisabled, onSubmit, labels, currencyCode, locale, className, }: CheckoutFormProps): react_jsx_runtime.JSX.Element;
623
+
624
+ /**
625
+ * `OrderConfirmation` — presentational order-confirmation view (REB-829).
626
+ * Pure data + status in, RSC-safe (no hooks). The consuming SITE owns the
627
+ * actual lookup/polling (`client.shop.order(sessionId)` via a Route Handler
628
+ * built from `createShopOrderRoute`, retried while `'polling'` — the Stripe
629
+ * webhook that creates the order may not have landed yet) and passes the
630
+ * resulting `status`/`order` in.
631
+ */
632
+ type OrderConfirmationOrder = ShopOrder;
633
+ type OrderConfirmationStatus = 'polling' | 'found' | 'timeout';
634
+ interface OrderConfirmationLabels {
635
+ pollingTitle: string;
636
+ pollingDescription: string;
637
+ foundTitle: string;
638
+ foundDescription: string;
639
+ timeoutTitle: string;
640
+ timeoutDescription: string;
641
+ orderNumberLabel: string;
642
+ totalLabel: string;
643
+ confirmationEmailPrefix: string;
644
+ sessionReferenceLabel: string;
645
+ }
646
+ interface OrderConfirmationProps {
647
+ status: OrderConfirmationStatus;
648
+ order: OrderConfirmationOrder | null;
649
+ /** Shown as a fallback reference when `status === 'timeout'` and no order was found. */
650
+ sessionId?: string;
651
+ labels?: Partial<OrderConfirmationLabels>;
652
+ currencyCode?: string;
653
+ locale?: string;
654
+ className?: string;
655
+ }
656
+ declare function OrderConfirmation({ status, order, sessionId, labels, currencyCode, locale, className, }: OrderConfirmationProps): react_jsx_runtime.JSX.Element;
657
+
658
+ export { ALLOWED_YOUTUBE_HOSTS, AddToCartButton, type AddToCartButtonLabels, type AddToCartButtonProps, CartIcon, type CartIconLabels, type CartIconProps, type CartLineItemView, CartLineList, type CartLineListLabels, type CartLineListProps, CartSummary, type CartSummaryLabels, type CartSummaryProps, type CheckoutAppliedDiscount, type CheckoutContactErrors, type CheckoutContactValues, CheckoutForm, type CheckoutFormLabels, type CheckoutFormProps, CheckoutLoginPrompt, type CheckoutLoginPromptLabels, type CheckoutLoginPromptProps, DEFAULT_SHOP_PRICE_BANDS, MarkdownRenderer, type MarkdownRendererProps, OrderConfirmation, type OrderConfirmationLabels, type OrderConfirmationOrder, type OrderConfirmationProps, type OrderConfirmationStatus, ProductCard, type ProductCardProps, ProfileCard, type ProfileCardProps, SafeHtml, type SafeHtmlProps, type ShareUrls, type ShopFilterPriceBand, ShopFilters, type ShopFiltersActive, type ShopFiltersHrefs, type ShopFiltersLabels, type ShopFiltersProps, Specialty, type SpecialtyProps, Treatment, type TreatmentProps, buildShareUrls, formatPrice, isAllowedYouTubeHost, markdownToSafeHtml, readingTime, sanitizeHtml, shouldRenderShopFilters };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { PageDetail, PageListItem, ShopProductListItem, ShopFacets } from '@reblu/site-contracts';
2
+ import { PageDetail, PageListItem, ShopProductListItem, ShopFacets, ShopOrder } from '@reblu/site-contracts';
3
+ import { ReactNode, FormEvent } from 'react';
3
4
 
4
5
  declare function readingTime(content: string | null | undefined): number | null;
5
6
 
@@ -383,4 +384,275 @@ interface ShopFiltersProps {
383
384
  declare function shouldRenderShopFilters(facets: ShopFacets, active?: ShopFiltersActive): boolean;
384
385
  declare function ShopFilters({ facets, hrefs, active, onChange, priceBands, labels, currencyCode, locale, className, }: ShopFiltersProps): react_jsx_runtime.JSX.Element | null;
385
386
 
386
- export { ALLOWED_YOUTUBE_HOSTS, DEFAULT_SHOP_PRICE_BANDS, MarkdownRenderer, type MarkdownRendererProps, ProductCard, type ProductCardProps, ProfileCard, type ProfileCardProps, SafeHtml, type SafeHtmlProps, type ShareUrls, type ShopFilterPriceBand, ShopFilters, type ShopFiltersActive, type ShopFiltersHrefs, type ShopFiltersLabels, type ShopFiltersProps, Specialty, type SpecialtyProps, Treatment, type TreatmentProps, buildShareUrls, formatPrice, isAllowedYouTubeHost, markdownToSafeHtml, readingTime, sanitizeHtml, shouldRenderShopFilters };
387
+ /**
388
+ * `AddToCartButton` — presentational add-to-cart CTA (REB-829). RSC-safe by
389
+ * construction (same contract as `ShopFilters`'s `OptionLink`): passing
390
+ * `onAddToCart` only makes sense from a Client Component, but the component
391
+ * itself carries no `'use client'` directive, so a Server Component may
392
+ * still render it WITHOUT the prop (e.g. a disabled preview state).
393
+ */
394
+ interface AddToCartButtonLabels {
395
+ add: string;
396
+ adding: string;
397
+ outOfStock: string;
398
+ }
399
+ interface AddToCartButtonProps {
400
+ onAddToCart?: () => void;
401
+ disabled?: boolean;
402
+ outOfStock?: boolean;
403
+ /** True while the add-to-cart call (or a navigation it triggers) is in flight. */
404
+ pending?: boolean;
405
+ labels?: Partial<AddToCartButtonLabels>;
406
+ className?: string;
407
+ }
408
+ declare function AddToCartButton({ onAddToCart, disabled, outOfStock, pending, labels, className, }: AddToCartButtonProps): react_jsx_runtime.JSX.Element;
409
+
410
+ /**
411
+ * `CartIcon` — presentational cart badge/link (REB-829). RSC-safe (plain
412
+ * `<a href>`, no hooks) — a Server Component can render it directly with a
413
+ * value already computed server-side; a Client Component drives `itemCount`
414
+ * from `@reblu/site-next/cart`'s `useCart().itemCount`.
415
+ */
416
+ interface CartIconLabels {
417
+ cart: string;
418
+ itemsSuffix: (count: number) => string;
419
+ }
420
+ interface CartIconProps {
421
+ itemCount: number;
422
+ href: string;
423
+ labels?: Partial<CartIconLabels>;
424
+ className?: string;
425
+ }
426
+ declare function CartIcon({ itemCount, href, labels, className }: CartIconProps): react_jsx_runtime.JSX.Element;
427
+
428
+ /**
429
+ * `CartLineList` — presentational cart lines (REB-829), container/
430
+ * presentational split: it takes `items` + optional `onQuantityChange`/
431
+ * `onRemove` callbacks, never fetches or owns cart state itself. The
432
+ * consuming SITE wires these to `@reblu/site-next/cart`'s `useCart()`.
433
+ *
434
+ * RSC-safe by construction (same `OptionLink` contract as `ShopFilters`):
435
+ * the quantity stepper/remove buttons only do anything when `onQuantityChange`/
436
+ * `onRemove` are supplied from a Client Component — omit them from a Server
437
+ * Component to render a read-only summary instead.
438
+ */
439
+ interface CartLineItemView {
440
+ productId: string;
441
+ variantId?: string | null;
442
+ name: string;
443
+ variantName?: string;
444
+ /** Integer cents. */
445
+ unitPrice: number;
446
+ quantity: number;
447
+ imageUrl?: string;
448
+ /** `null`/`undefined` = untracked stock — never clamps the stepper's max. */
449
+ maxStock?: number | null;
450
+ }
451
+ interface CartLineListLabels {
452
+ quantityLabel: string;
453
+ decrease: string;
454
+ increase: string;
455
+ remove: string;
456
+ unitPriceSuffix: string;
457
+ }
458
+ interface CartLineListProps {
459
+ items: CartLineItemView[];
460
+ onQuantityChange?: (productId: string, variantId: string | null | undefined, quantity: number) => void;
461
+ onRemove?: (productId: string, variantId: string | null | undefined) => void;
462
+ /**
463
+ * A visually-hidden `aria-live="polite"` announcement (e.g. "Cantidad
464
+ * actualizada", "Producto eliminado del carrito") — the consuming SITE
465
+ * decides WHEN to set it (after a successful mutation), this component
466
+ * only renders the live region.
467
+ */
468
+ liveMessage?: string;
469
+ labels?: Partial<CartLineListLabels>;
470
+ currencyCode?: string;
471
+ locale?: string;
472
+ className?: string;
473
+ }
474
+ declare function CartLineList({ items, onQuantityChange, onRemove, liveMessage, labels, currencyCode, locale, className, }: CartLineListProps): react_jsx_runtime.JSX.Element;
475
+
476
+ /**
477
+ * `CartSummary` — presentational price breakdown (REB-829): subtotal,
478
+ * optional discount, optional shipping (sourced from `ShopConfig` by the
479
+ * consuming SITE — this component only renders what it's given), and total.
480
+ * Pure data in, RSC-safe (no hooks, no callbacks).
481
+ */
482
+ interface CartSummaryLabels {
483
+ subtotal: string;
484
+ discountPrefix: string;
485
+ shipping: string;
486
+ freeShipping: string;
487
+ /**
488
+ * Shown when `shipping` is `null`/`undefined` (unknown yet) — REB-829
489
+ * review finding: this is NOT the same state as `0` (confirmed free).
490
+ * Claiming "free shipping" for an amount the SITE simply hasn't computed
491
+ * yet understates the real total and is reversed at checkout.
492
+ */
493
+ shippingCalculated: string;
494
+ total: string;
495
+ }
496
+ interface CartSummaryProps {
497
+ /** Integer cents. */
498
+ subtotal: number;
499
+ /** Integer cents, positive. Omit (or `0`) to hide the discount line. */
500
+ discount?: number;
501
+ /** The applied discount code, shown next to the discount amount. */
502
+ discountCode?: string;
503
+ /** Integer cents. Only rendered when `shippingEnabled` is true. */
504
+ shipping?: number | null;
505
+ /** Whether this tenant's shop even has shipping cost — hides the line entirely when false/omitted. */
506
+ shippingEnabled?: boolean;
507
+ /** Integer cents — the final charged amount. */
508
+ total: number;
509
+ labels?: Partial<CartSummaryLabels>;
510
+ currencyCode?: string;
511
+ locale?: string;
512
+ className?: string;
513
+ }
514
+ declare function CartSummary({ subtotal, discount, discountCode, shipping, shippingEnabled, total, labels, currencyCode, locale, className, }: CartSummaryProps): react_jsx_runtime.JSX.Element;
515
+
516
+ /**
517
+ * `CheckoutLoginPrompt` — the "login prompt hook" the checkout flow needs
518
+ * (REB-829): a guest-checkout identification dialog offering "continue with
519
+ * this email" (so the SITE can check for an existing account via
520
+ * `client.shop.checkEmail`) or "continue as guest" outright. Fully
521
+ * controlled/presentational — it performs NO fetch itself (unlike
522
+ * demo-site's original `CheckoutLoginModal`, which called
523
+ * `/api/shop/check-email` internally); the consuming SITE owns `email`
524
+ * state and the `checkEmail` call, and drives `checking`/`error` from its
525
+ * own result.
526
+ */
527
+ interface CheckoutLoginPromptLabels {
528
+ title: string;
529
+ description: string;
530
+ emailLabel: string;
531
+ emailPlaceholder: string;
532
+ continueWithEmail: string;
533
+ checking: string;
534
+ continueAsGuest: string;
535
+ close: string;
536
+ }
537
+ interface CheckoutLoginPromptProps {
538
+ open: boolean;
539
+ email: string;
540
+ onEmailChange: (value: string) => void;
541
+ onClose: () => void;
542
+ /** Called when the visitor confirms a (valid-looking) email. */
543
+ onSubmitEmail: () => void;
544
+ onContinueAsGuest: () => void;
545
+ checking?: boolean;
546
+ error?: string | null;
547
+ labels?: Partial<CheckoutLoginPromptLabels>;
548
+ className?: string;
549
+ }
550
+ declare function CheckoutLoginPrompt({ open, email, onEmailChange, onClose, onSubmitEmail, onContinueAsGuest, checking, error, labels, className, }: CheckoutLoginPromptProps): react_jsx_runtime.JSX.Element | null;
551
+
552
+ /**
553
+ * `CheckoutForm` — presentational guest-checkout form (REB-829): contact
554
+ * fields, a discount-code section, an optional `loginPrompt` slot, and the
555
+ * submit CTA. Fully controlled — `values`/callbacks only, no internal state,
556
+ * no fetch, no react-hook-form/zod dependency (keeping this package's
557
+ * dependency surface minimal); the consuming SITE owns validation and wires
558
+ * its own `onSubmit`.
559
+ *
560
+ * Scope note: shipping/billing address collection is intentionally OUT of
561
+ * this component — those field sets vary by tenant shop config (shipping
562
+ * enabled/disabled, invoicing requirements) far more than the guest-email +
563
+ * discount-code flow the issue named. A SITE that needs them renders its own
564
+ * fields via the `children` slot, rendered between the contact and discount
565
+ * sections.
566
+ */
567
+ interface CheckoutContactValues {
568
+ name: string;
569
+ email: string;
570
+ phone?: string;
571
+ }
572
+ type CheckoutContactErrors = Partial<Record<keyof CheckoutContactValues, string>>;
573
+ interface CheckoutAppliedDiscount {
574
+ code: string;
575
+ amount: number;
576
+ }
577
+ interface CheckoutFormLabels {
578
+ contactTitle: string;
579
+ nameLabel: string;
580
+ namePlaceholder: string;
581
+ emailLabel: string;
582
+ emailPlaceholder: string;
583
+ phoneLabel: string;
584
+ discountTitle: string;
585
+ discountPlaceholder: string;
586
+ applyDiscount: string;
587
+ applyingDiscount: string;
588
+ removeDiscount: string;
589
+ discountAppliedSuffix: (formattedAmount: string) => string;
590
+ submit: string;
591
+ submitting: string;
592
+ }
593
+ interface CheckoutFormProps {
594
+ contact: CheckoutContactValues;
595
+ onContactChange: (values: CheckoutContactValues) => void;
596
+ contactErrors?: CheckoutContactErrors;
597
+ discountCode: string;
598
+ onDiscountCodeChange: (value: string) => void;
599
+ onApplyDiscount: () => void;
600
+ onRemoveDiscount: () => void;
601
+ appliedDiscount?: CheckoutAppliedDiscount | null;
602
+ discountApplying?: boolean;
603
+ discountError?: string | null;
604
+ /**
605
+ * Rendered OUTSIDE the `<form>`, immediately before it — e.g. the
606
+ * `CheckoutLoginPrompt` dialog. It must never render inside the `<form>`:
607
+ * an Enter keypress in one of ITS inputs would otherwise submit checkout
608
+ * (REB-829 review finding — see `handleDiscountCodeKeyDown` below for the
609
+ * same defect class).
610
+ */
611
+ loginPrompt?: ReactNode;
612
+ /** Rendered between the contact and discount sections — e.g. shipping/billing fields. */
613
+ children?: ReactNode;
614
+ submitting?: boolean;
615
+ submitDisabled?: boolean;
616
+ onSubmit: (event: FormEvent<HTMLFormElement>) => void;
617
+ labels?: Partial<CheckoutFormLabels>;
618
+ currencyCode?: string;
619
+ locale?: string;
620
+ className?: string;
621
+ }
622
+ declare function CheckoutForm({ contact, onContactChange, contactErrors, discountCode, onDiscountCodeChange, onApplyDiscount, onRemoveDiscount, appliedDiscount, discountApplying, discountError, loginPrompt, children, submitting, submitDisabled, onSubmit, labels, currencyCode, locale, className, }: CheckoutFormProps): react_jsx_runtime.JSX.Element;
623
+
624
+ /**
625
+ * `OrderConfirmation` — presentational order-confirmation view (REB-829).
626
+ * Pure data + status in, RSC-safe (no hooks). The consuming SITE owns the
627
+ * actual lookup/polling (`client.shop.order(sessionId)` via a Route Handler
628
+ * built from `createShopOrderRoute`, retried while `'polling'` — the Stripe
629
+ * webhook that creates the order may not have landed yet) and passes the
630
+ * resulting `status`/`order` in.
631
+ */
632
+ type OrderConfirmationOrder = ShopOrder;
633
+ type OrderConfirmationStatus = 'polling' | 'found' | 'timeout';
634
+ interface OrderConfirmationLabels {
635
+ pollingTitle: string;
636
+ pollingDescription: string;
637
+ foundTitle: string;
638
+ foundDescription: string;
639
+ timeoutTitle: string;
640
+ timeoutDescription: string;
641
+ orderNumberLabel: string;
642
+ totalLabel: string;
643
+ confirmationEmailPrefix: string;
644
+ sessionReferenceLabel: string;
645
+ }
646
+ interface OrderConfirmationProps {
647
+ status: OrderConfirmationStatus;
648
+ order: OrderConfirmationOrder | null;
649
+ /** Shown as a fallback reference when `status === 'timeout'` and no order was found. */
650
+ sessionId?: string;
651
+ labels?: Partial<OrderConfirmationLabels>;
652
+ currencyCode?: string;
653
+ locale?: string;
654
+ className?: string;
655
+ }
656
+ declare function OrderConfirmation({ status, order, sessionId, labels, currencyCode, locale, className, }: OrderConfirmationProps): react_jsx_runtime.JSX.Element;
657
+
658
+ export { ALLOWED_YOUTUBE_HOSTS, AddToCartButton, type AddToCartButtonLabels, type AddToCartButtonProps, CartIcon, type CartIconLabels, type CartIconProps, type CartLineItemView, CartLineList, type CartLineListLabels, type CartLineListProps, CartSummary, type CartSummaryLabels, type CartSummaryProps, type CheckoutAppliedDiscount, type CheckoutContactErrors, type CheckoutContactValues, CheckoutForm, type CheckoutFormLabels, type CheckoutFormProps, CheckoutLoginPrompt, type CheckoutLoginPromptLabels, type CheckoutLoginPromptProps, DEFAULT_SHOP_PRICE_BANDS, MarkdownRenderer, type MarkdownRendererProps, OrderConfirmation, type OrderConfirmationLabels, type OrderConfirmationOrder, type OrderConfirmationProps, type OrderConfirmationStatus, ProductCard, type ProductCardProps, ProfileCard, type ProfileCardProps, SafeHtml, type SafeHtmlProps, type ShareUrls, type ShopFilterPriceBand, ShopFilters, type ShopFiltersActive, type ShopFiltersHrefs, type ShopFiltersLabels, type ShopFiltersProps, Specialty, type SpecialtyProps, Treatment, type TreatmentProps, buildShareUrls, formatPrice, isAllowedYouTubeHost, markdownToSafeHtml, readingTime, sanitizeHtml, shouldRenderShopFilters };