{"version":3,"sources":["/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-UXOOVP77.cjs","../src/components/empty-state.tsx","../src/components/unified-pagination.tsx"],"names":["jsx"],"mappings":"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","file":"/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-UXOOVP77.cjs","sourcesContent":[null,"'use client';\n\nimport { Search, FileText, Package } from 'lucide-react';\nimport { useRouter } from '../embed-shims/next-navigation';\nimport { Button } from './ui/button';\n\nexport interface EmptyStateProps {\n  type: 'vendors' | 'posts' | 'search' | 'generic';\n  title?: string;\n  description?: string;\n  showBackButton?: boolean;\n  onGoBack?: () => void;\n  backButtonText?: string;\n  // New CTA properties\n  showCTA?: boolean;\n  ctaText?: string;\n  onCtaClick?: () => void;\n  /**\n   * Link-CTA mode: render the CTA as a navigation link (`href` — plain or\n   * `mailto:`). Wins over `onCtaClick`, and SHORT-CIRCUITS the smart-CTA\n   * path-sniffing below (which reads `window.location.pathname` — an\n   * SSR/client divergence server-rendered pages must never enter).\n   */\n  ctaHref?: string;\n  ctaVariant?: 'primary' | 'secondary';\n}\n\nexport function EmptyState({\n  type,\n  title,\n  description,\n  showBackButton = false,\n  onGoBack,\n  backButtonText = 'Go Back',\n  showCTA = true,\n  ctaText,\n  onCtaClick,\n  ctaHref,\n  ctaVariant = 'primary',\n}: EmptyStateProps) {\n  const router = useRouter();\n\n  // Default content based on type\n  const getDefaultContent = () => {\n    switch (type) {\n      case 'vendors':\n        return {\n          icon: <Package className=\"h-full w-full\" />,\n          title: 'No vendors found',\n          description:\n            \"We couldn't find any vendors matching your criteria. Try adjusting your filters or search terms.\",\n        };\n      case 'posts':\n        return {\n          icon: <FileText className=\"h-full w-full\" />,\n          title: 'No articles found',\n          description:\n            \"We couldn't find any articles matching your criteria. Try different categories, tags, or search terms.\",\n        };\n      case 'search':\n        return {\n          icon: <Search className=\"h-full w-full\" />,\n          title: 'No results found',\n          description: \"Your search didn't return any results. Try different keywords or browse our categories.\",\n        };\n      default:\n        return {\n          icon: <Search className=\"h-full w-full\" />,\n          title: 'Nothing found',\n          description: \"We couldn't find what you're looking for. Try adjusting your search or filters.\",\n        };\n    }\n  };\n\n  // Smart CTA logic based on context\n  const getSmartCTA = () => {\n    // If custom CTA is provided, use it\n    if (ctaText && onCtaClick) {\n      return {\n        text: ctaText,\n        action: onCtaClick,\n      };\n    }\n\n    // Check if we're on the client side\n    const isClient = typeof window !== 'undefined';\n    const currentPath = isClient ? window.location.pathname : '';\n\n    // Surgical filter reset (promoted from the hub's diverged clone during\n    // the EmptyState convergence): delete ONLY the filter params the surface\n    // owns — nuking the whole query string threw away unrelated state — and\n    // use `replace` with `scroll: false` so resetting filters neither adds a\n    // history entry nor jumps the page.\n    const resetParams = (paramsToDelete: string[]) => {\n      if (!isClient) return;\n      const params = new URLSearchParams(window.location.search);\n      for (const p of paramsToDelete) params.delete(p);\n      const queryString = params.toString();\n      // Keep the hash — a filter reset must not clear an unrelated\n      // deep-link anchor (e.g. #delivery-123).\n      const hash = window.location.hash;\n      router.replace(`${window.location.pathname}${queryString ? `?${queryString}` : ''}${hash}`, { scroll: false });\n    };\n\n    // Smart defaults based on type and context\n    switch (type) {\n      case 'search':\n        return {\n          text: 'Reset Filters',\n          action: () => resetParams(['search', 'page']),\n        };\n      case 'posts':\n        // Blog-style listing pages (blog, case studies) reset their filters\n        if (currentPath.includes('/blog') || currentPath.includes('/case-studies')) {\n          return {\n            text: 'Reset Filters',\n            action: () => resetParams(['search', 'page', 'category', 'tags']),\n          };\n        } else if (currentPath.includes('/profile')) {\n          return {\n            text: 'Browse Vendors',\n            action: () => router.push('/vendors'),\n          };\n        }\n        return {\n          text: 'View All Posts',\n          action: () => router.push('/blog'),\n        };\n      case 'vendors':\n        // If we're in profile or other pages, direct to main content\n        if (currentPath.includes('/profile')) {\n          return {\n            text: 'Browse Vendors',\n            action: () => router.push('/vendors'),\n          };\n        } else if (currentPath.includes('/vendors') || currentPath.includes('/margin-increase/compare')) {\n          return {\n            text: 'Reset Filters',\n            action: () => resetParams(['search', 'page', 'category', 'subcategory']),\n          };\n        }\n        return {\n          text: 'Browse Vendors',\n          action: () => router.push('/vendors'),\n        };\n      default:\n        return {\n          text: 'Browse Vendors',\n          action: () => router.push('/vendors'),\n        };\n    }\n  };\n\n  const defaultContent = getDefaultContent();\n  const displayTitle = title || defaultContent.title;\n  const displayDescription = description || defaultContent.description;\n  // ctaHref short-circuits BEFORE getSmartCTA(): the smart defaults read\n  // window.location.pathname (SSR-empty, client-real), so a server-rendered\n  // page with a link CTA must never enter that branch. Existing callers\n  // without ctaHref keep today's smart-default behavior unchanged.\n  const smartCTA = ctaHref ? null : getSmartCTA();\n  const ctaClassName =\n    ctaVariant === 'primary'\n      ? 'w-full bg-ods-accent text-ods-text-on-accent hover:bg-ods-accent-hover transition-all duration-150 font-body font-medium'\n      : 'w-full bg-transparent border border-ods-border text-ods-text-primary hover:border-ods-accent hover:text-ods-accent transition-all duration-150 font-body font-medium';\n\n  return (\n    <div className=\"flex flex-col items-center justify-center px-6 py-6 text-center md:py-16\">\n      {/* Icon */}\n      <div className=\"mb-3 flex items-center justify-center md:mb-6\">\n        <div className=\"rounded-full border border-ods-border bg-ods-card p-3 md:p-6\">\n          <div className=\"flex h-8 w-8 items-center justify-center text-ods-text-secondary md:h-16 md:w-16\">\n            {defaultContent.icon}\n          </div>\n        </div>\n      </div>\n\n      {/* Title */}\n      <h2 className=\"mb-2 text-ods-text-primary text-h3 md:mb-3\">{displayTitle}</h2>\n\n      {/* Description */}\n      <p className=\"mb-4 max-w-md text-ods-text-secondary text-h6 md:mb-8\">{displayDescription}</p>\n\n      {/* Link CTA (ctaHref) — SSR-safe, no path sniffing */}\n      {showCTA && ctaHref && (\n        <div className=\"mb-3 w-full max-w-xs\">\n          <Button href={ctaHref} className={ctaClassName}>\n            {ctaText || 'Contact us'}\n          </Button>\n        </div>\n      )}\n\n      {/* Smart CTA Button */}\n      {showCTA && !ctaHref && smartCTA && (\n        <div className=\"mb-3 w-full max-w-xs\">\n          <Button onClick={smartCTA.action} className={ctaClassName}>\n            {smartCTA.text}\n          </Button>\n        </div>\n      )}\n\n      {/* Optional Back Button */}\n      {showBackButton && onGoBack && (\n        <div className=\"w-full max-w-xs\">\n          <Button\n            onClick={onGoBack}\n            variant=\"outline\"\n            className=\"w-full font-body font-medium transition-all duration-150\"\n          >\n            {backButtonText}\n          </Button>\n        </div>\n      )}\n    </div>\n  );\n}\n","'use client';\n\nimport { useSearchParams, usePathname } from '../embed-shims/next-navigation';\nimport { withQuery } from '../utils/search-params';\nimport { Pagination } from './pagination';\n\ninterface UnifiedPaginationProps {\n  currentPage: number;\n  totalPages: number;\n  onPageChange?: (page: number) => void;\n  className?: string;\n  /**\n   * Write `?page=` into the URL on every change (default true, the historical\n   * behaviour). Set false when the CALLER owns the URL — a surface whose whole\n   * filter state is one schema would otherwise get two writers racing on it.\n   */\n  syncUrl?: boolean;\n  /**\n   * Keep the row's height when there is only one page, instead of rendering\n   * nothing. Stops a one-page result from shifting the content above it.\n   */\n  reserveSpace?: boolean;\n}\n\nexport function UnifiedPagination({\n  currentPage,\n  totalPages,\n  onPageChange,\n  className = 'mt-8 flex justify-center w-full',\n  syncUrl = true,\n  reserveSpace = false,\n}: UnifiedPaginationProps) {\n  const searchParams = useSearchParams();\n  const pathname = usePathname();\n\n  const handlePageChange = (page: number) => {\n    // Preserve current scroll position\n    const currentScrollY = window.scrollY;\n\n    // Call the callback to update local state (prevents reload)\n    if (onPageChange) {\n      onPageChange(page);\n    }\n\n    // Update URL for bookmarking without navigation — unless the caller owns\n    // the URL (`syncUrl={false}`), in which case a second writer here would\n    // race the caller's own param write.\n    if (syncUrl) {\n      const params = new URLSearchParams(searchParams.toString());\n      params.set('page', page.toString());\n      window.history.replaceState(null, '', withQuery(pathname, params.toString()));\n    }\n\n    // Restore scroll position after a brief delay to allow content to render\n    setTimeout(() => {\n      window.scrollTo({\n        top: currentScrollY,\n        behavior: 'instant', // Instant to prevent any scroll animation\n      });\n    }, 0);\n  };\n\n  // Don't render pagination if there's only one page (optionally holding the\n  // row's height so the content above it does not shift).\n  //\n  // The reserved row renders the REAL control, hidden — an empty div reserves\n  // nothing, and a hardcoded spacer height silently drifts the day the control\n  // changes. `invisible` keeps the box, `aria-hidden` + `pointer-events-none`\n  // keep it out of the accessibility tree and out of the way.\n  if (totalPages <= 1) {\n    return reserveSpace ? (\n      <div className={className} aria-hidden=\"true\">\n        <div className=\"pointer-events-none invisible\">\n          <Pagination currentPage={1} totalPages={1} onPageChange={() => {}} />\n        </div>\n      </div>\n    ) : null;\n  }\n\n  return (\n    <div className={className}>\n      <Pagination currentPage={currentPage} totalPages={totalPages} onPageChange={handlePageChange} />\n    </div>\n  );\n}\n"]}