@aurora-studio/starter-core 0.1.8 → 0.1.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.
@@ -20,7 +20,7 @@ type ProductImageProps = {
20
20
  /**
21
21
  * Product image with onError fallback to avoid broken image icons.
22
22
  * Uses imageBaseUrl from store config (or baseUrl prop) for relative URLs.
23
- * Use objectFit="contain" for product cards to preserve portrait/landscape aspect ratios.
23
+ * Default objectFit is "cover" (fill frame, crop from center). Use "contain" to letterbox (e.g. PDP gallery).
24
24
  */
25
25
  export declare function ProductImage({ src, alt, baseUrl, className, fallback, record, objectFit, thumbnail, }: ProductImageProps): import("react/jsx-runtime").JSX.Element;
26
26
  export {};
@@ -1 +1 @@
1
- "use client";import{jsx as _jsx}from"react/jsx-runtime";import{useState}from"react";import{resolveProductImageUrl,getImageUrlFromRecord,getThumbnailImageUrl}from"../lib/image-url";import{useStoreConfigImageBase}from"./StoreConfigContext";const DEFAULT_FALLBACK=_jsx("span",{className:"w-full h-full flex items-center justify-center text-aurora-muted text-2xl","aria-hidden":true,children:"–"});const objectFitClass={cover:"object-cover",contain:"object-contain"};export function ProductImage({src:src,alt:alt="",baseUrl:baseUrl,className:className,fallback:fallback=DEFAULT_FALLBACK,record:record,objectFit:objectFit="cover",thumbnail:thumbnail=false}){const[errored,setErrored]=useState(false);const configBase=useStoreConfigImageBase();const rawUrl=record!==undefined?getImageUrlFromRecord(record):src;let resolved=resolveProductImageUrl(rawUrl,baseUrl??configBase);if(resolved&&thumbnail){resolved=getThumbnailImageUrl(resolved)??resolved}const fitClass=objectFitClass[objectFit];const base=(className??"w-full h-full").replace(/\bobject-(cover|contain)\b/g,"").trim();const mergedClassName=base?`${base} ${fitClass}`.trim():`w-full h-full ${fitClass}`;if(!resolved||errored){return _jsx("div",{className:"w-full h-full flex items-center justify-center min-h-[1px]",children:fallback})}return _jsx("img",{src:resolved,alt:alt,className:mergedClassName,onError:()=>setErrored(true),suppressHydrationWarning:true})}
1
+ "use client";import{jsx as _jsx}from"react/jsx-runtime";import{useState}from"react";import{resolveProductImageUrl,getImageUrlFromRecord,getThumbnailImageUrl}from"../lib/image-url";import{useStoreConfigImageBase}from"./StoreConfigContext";const DEFAULT_FALLBACK=_jsx("span",{className:"w-full h-full flex items-center justify-center text-aurora-muted text-2xl","aria-hidden":true,children:"–"});const objectFitClass={cover:"object-cover object-center",contain:"object-contain object-center"};export function ProductImage({src:src,alt:alt="",baseUrl:baseUrl,className:className,fallback:fallback=DEFAULT_FALLBACK,record:record,objectFit:objectFit="cover",thumbnail:thumbnail=false}){const[errored,setErrored]=useState(false);const configBase=useStoreConfigImageBase();const rawUrl=record!==undefined?getImageUrlFromRecord(record):src;let resolved=resolveProductImageUrl(rawUrl,baseUrl??configBase);if(resolved&&thumbnail){resolved=getThumbnailImageUrl(resolved)??resolved}const fitClass=objectFitClass[objectFit];const base=(className??"w-full h-full").replace(/\bobject-(cover|contain)\b/g,"").trim();const mergedClassName=base?`${base} ${fitClass}`.trim():`w-full h-full ${fitClass}`;if(!resolved||errored){return _jsx("div",{className:"w-full h-full flex items-center justify-center min-h-[1px]",children:fallback})}return _jsx("img",{src:resolved,alt:alt,className:mergedClassName,onError:()=>setErrored(true),suppressHydrationWarning:true})}
@@ -1 +1 @@
1
- "use client";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useState,useEffect,useRef,useCallback}from"react";import Link from"next/link";import{Search}from"lucide-react";import{formatPrice,toCents}from"../lib/format-price";import{search}from"../lib/aurora";import{holmesSearch}from"../lib/holmes-events";import{useCart}from"./CartProvider";import{ProductImage}from"./ProductImage";const RECENT_KEY="aurora-search-recent";const RECENT_MAX=5;function loadRecent(){if(typeof window==="undefined")return[];try{const stored=localStorage.getItem(RECENT_KEY);return stored?JSON.parse(stored):[]}catch{return[]}}function saveRecent(terms){if(typeof window==="undefined")return;localStorage.setItem(RECENT_KEY,JSON.stringify(terms.slice(0,RECENT_MAX)))}export function SearchDropdown({vendorId:vendorId,placeholder:placeholder="Search milk, bananas, pasta…",fullWidth:fullWidth,variant:variant="default",excludeDietary:excludeDietary=[],getRecipeSuggestion:getRecipeSuggestion}){const[query,setQuery]=useState("");const[hits,setHits]=useState([]);const[loading,setLoading]=useState(false);const[open,setOpen]=useState(false);const[recentSearches,setRecentSearches]=useState([]);const debounceRef=useRef(null);const containerRef=useRef(null);const{addItem:addItem}=useCart();useEffect(()=>{setRecentSearches(loadRecent())},[]);const addToRecent=useCallback(term=>{const t=term.trim().toLowerCase();if(!t)return;setRecentSearches(prev=>{const next=[t,...prev.filter(x=>x!==t)].slice(0,RECENT_MAX);saveRecent(next);return next})},[]);const doSearch=useCallback(async q=>{if(!q.trim()){setHits([]);return}holmesSearch(q.trim());setLoading(true);try{const res=await search({q:q.trim(),limit:12,vendorId:vendorId,excludeDietary:excludeDietary.length?excludeDietary:undefined});setHits(res.hits??[])}catch{setHits([])}finally{setLoading(false)}},[vendorId,excludeDietary]);useEffect(()=>{if(debounceRef.current)clearTimeout(debounceRef.current);if(!query.trim()){setHits([]);return}setOpen(true);debounceRef.current=setTimeout(()=>doSearch(query),180);return()=>{if(debounceRef.current)clearTimeout(debounceRef.current)}},[query,doSearch]);useEffect(()=>{function handleClickOutside(e){if(containerRef.current&&!containerRef.current.contains(e.target)){setOpen(false)}}document.addEventListener("mousedown",handleClickOutside);return()=>document.removeEventListener("mousedown",handleClickOutside)},[]);const categories=[...new Set(hits.map(h=>h.category_name??h.category).filter(Boolean))].slice(0,3);const brands=[...new Set(hits.map(h=>h.brand??h.brand_name).filter(Boolean))].slice(0,3);const handleProductSelect=(hit,quickAdd)=>{addToRecent(query);if(quickAdd&&hit.price!=null&&Number(hit.price)>0&&hit.tableSlug){addItem({recordId:hit.recordId,tableSlug:hit.tableSlug,name:hit.name??hit.title??hit.snippet??hit.recordId??"",unitAmount:toCents(hit.price)??0,imageUrl:hit.image_url})}};const showRecent=open&&query.trim()&&!loading&&hits.length===0&&recentSearches.length>0;const recipeSuggestion=getRecipeSuggestion?.(query)??null;const showRecipeSuggestion=open&&query.trim().length>=2&&recipeSuggestion&&!loading;const fieldShell=variant==="default"?"flex w-full items-center rounded-lg border border-aurora-border/90 bg-aurora-surface shadow-sm transition-colors focus-within:border-aurora-primary/70 focus-within:ring-1 focus-within:ring-aurora-primary/40":"flex w-full items-center rounded-lg bg-transparent";const inputClass="flex-1 min-w-0 h-10 py-0 pr-3 text-sm leading-normal text-aurora-text placeholder:text-aurora-muted "+"border-0 bg-transparent shadow-none outline-none ring-0 focus:outline-none focus:ring-0 "+"[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none";return _jsxs("div",{ref:containerRef,className:`relative w-full ${fullWidth?"":"max-w-[280px]"}`,children:[_jsxs("div",{className:fieldShell,children:[_jsx("span",{className:"flex h-10 w-10 shrink-0 items-center justify-center text-aurora-muted pointer-events-none","aria-hidden":true,children:_jsx(Search,{className:"h-4 w-4 shrink-0"})}),_jsx("input",{type:"search",value:query,onChange:e=>setQuery(e.target.value),onFocus:()=>(query.trim()||recentSearches.length)&&setOpen(true),placeholder:placeholder,className:inputClass,"aria-label":"Search products"})]}),open&&(query.trim()||showRecent)&&_jsx("div",{className:"absolute top-full left-0 right-0 mt-1 rounded-component bg-aurora-surface border border-aurora-border shadow-xl z-[9999] max-h-96 overflow-y-auto",children:loading?_jsx("div",{className:"p-4 text-aurora-muted text-sm",children:"Searching…"}):hits.length===0&&!showRecent&&!showRecipeSuggestion?_jsx("div",{className:"p-4 text-aurora-muted text-sm",children:"No results"}):_jsxs("div",{className:"py-2",children:[showRecipeSuggestion&&_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-b border-aurora-border",children:"Suggestions"}),showRecipeSuggestion&&_jsxs(Link,{href:`/catalogue?q=${encodeURIComponent(recipeSuggestion.replace("?","").split(" ")[0].toLowerCase())}`,onClick:()=>{addToRecent(recipeSuggestion);setOpen(false)},className:"flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors border-b border-aurora-border",children:[_jsx(Search,{className:"w-4 h-4 text-aurora-muted shrink-0"}),_jsx("span",{className:"font-medium truncate",children:recipeSuggestion})]}),hits.length>0&&_jsxs(_Fragment,{children:[_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-b border-aurora-border",children:"Products"}),_jsx("ul",{children:hits.slice(0,6).map(hit=>_jsx("li",{className:"group/item",children:_jsxs("div",{className:"flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors",children:[_jsxs(Link,{href:`/catalogue/${hit.recordId}`,onClick:()=>{handleProductSelect(hit);setOpen(false)},className:"flex items-center gap-3 flex-1 min-w-0",children:[_jsx("div",{className:"w-10 h-10 rounded-component bg-aurora-surface-hover shrink-0 overflow-hidden",children:_jsx(ProductImage,{src:hit.image_url,className:"w-full h-full",objectFit:"contain",thumbnail:true,fallback:_jsx("div",{className:"w-full h-full flex items-center justify-center text-aurora-muted text-xs",children:"-"})})}),_jsxs("div",{className:"flex-1 min-w-0",children:[_jsx("p",{className:"font-medium truncate",children:hit.name??hit.title??hit.snippet??hit.recordId}),hit.price!=null&&Number(hit.price)>0&&_jsx("p",{className:"text-sm text-aurora-primary font-semibold",children:formatPrice(toCents(hit.price)??0)})]})]}),hit.price!=null&&Number(hit.price)>0&&_jsx("button",{type:"button",onClick:e=>{e.preventDefault();handleProductSelect(hit,true);setOpen(false)},className:"shrink-0 px-3 py-1.5 rounded-lg bg-aurora-primary text-white text-xs font-medium hover:bg-aurora-primary-dark transition-colors opacity-0 group-hover/item:opacity-100",children:"Quick add"})]})},`${hit.tableSlug}-${hit.recordId}`))}),categories.length>0&&_jsxs(_Fragment,{children:[_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-t border-b border-aurora-border mt-1",children:"Categories"}),_jsx("ul",{children:categories.map(cat=>_jsx("li",{children:_jsx(Link,{href:`/catalogue?category=${encodeURIComponent(String(cat).toLowerCase().replace(/\s+/g,"-"))}`,onClick:()=>{addToRecent(query);setOpen(false)},className:"flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors",children:_jsx("span",{className:"font-medium truncate",children:cat})})},cat))})]}),brands.length>0&&_jsxs(_Fragment,{children:[_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-t border-b border-aurora-border mt-1",children:"Brands"}),_jsx("ul",{children:brands.map(brand=>_jsx("li",{children:_jsx(Link,{href:`/catalogue?q=${encodeURIComponent(brand)}`,onClick:()=>{addToRecent(query);setOpen(false)},className:"flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors",children:_jsx("span",{className:"font-medium truncate",children:brand})})},brand))})]})]}),showRecent&&_jsxs(_Fragment,{children:[_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-b border-aurora-border",children:"Recent searches"}),_jsx("ul",{children:recentSearches.map(term=>_jsx("li",{children:_jsxs("button",{type:"button",onClick:()=>{setQuery(term);doSearch(term)},className:"w-full text-left flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors",children:[_jsx(Search,{className:"w-4 h-4 text-aurora-muted shrink-0"}),_jsx("span",{className:"font-medium truncate",children:term})]})},term))})]})]})})]})}
1
+ "use client";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useState,useEffect,useRef,useCallback}from"react";import Link from"next/link";import{Search}from"lucide-react";import{formatPrice,toCents}from"../lib/format-price";import{search}from"../lib/aurora";import{holmesSearch}from"../lib/holmes-events";import{useCart}from"./CartProvider";import{ProductImage}from"./ProductImage";const RECENT_KEY="aurora-search-recent";const RECENT_MAX=5;function loadRecent(){if(typeof window==="undefined")return[];try{const stored=localStorage.getItem(RECENT_KEY);return stored?JSON.parse(stored):[]}catch{return[]}}function saveRecent(terms){if(typeof window==="undefined")return;localStorage.setItem(RECENT_KEY,JSON.stringify(terms.slice(0,RECENT_MAX)))}export function SearchDropdown({vendorId:vendorId,placeholder:placeholder="Search milk, bananas, pasta…",fullWidth:fullWidth,variant:variant="default",excludeDietary:excludeDietary=[],getRecipeSuggestion:getRecipeSuggestion}){const[query,setQuery]=useState("");const[hits,setHits]=useState([]);const[loading,setLoading]=useState(false);const[open,setOpen]=useState(false);const[recentSearches,setRecentSearches]=useState([]);const debounceRef=useRef(null);const containerRef=useRef(null);const{addItem:addItem}=useCart();useEffect(()=>{setRecentSearches(loadRecent())},[]);const addToRecent=useCallback(term=>{const t=term.trim().toLowerCase();if(!t)return;setRecentSearches(prev=>{const next=[t,...prev.filter(x=>x!==t)].slice(0,RECENT_MAX);saveRecent(next);return next})},[]);const doSearch=useCallback(async q=>{if(!q.trim()){setHits([]);return}holmesSearch(q.trim());setLoading(true);try{const res=await search({q:q.trim(),limit:12,vendorId:vendorId,excludeDietary:excludeDietary.length?excludeDietary:undefined});setHits(res.hits??[])}catch{setHits([])}finally{setLoading(false)}},[vendorId,excludeDietary]);useEffect(()=>{if(debounceRef.current)clearTimeout(debounceRef.current);if(!query.trim()){setHits([]);return}setOpen(true);debounceRef.current=setTimeout(()=>doSearch(query),180);return()=>{if(debounceRef.current)clearTimeout(debounceRef.current)}},[query,doSearch]);useEffect(()=>{function handleClickOutside(e){if(containerRef.current&&!containerRef.current.contains(e.target)){setOpen(false)}}document.addEventListener("mousedown",handleClickOutside);return()=>document.removeEventListener("mousedown",handleClickOutside)},[]);const categories=[...new Set(hits.map(h=>h.category_name??h.category).filter(Boolean))].slice(0,3);const brands=[...new Set(hits.map(h=>h.brand??h.brand_name).filter(Boolean))].slice(0,3);const handleProductSelect=(hit,quickAdd)=>{addToRecent(query);if(quickAdd&&hit.price!=null&&Number(hit.price)>0&&hit.tableSlug){addItem({recordId:hit.recordId,tableSlug:hit.tableSlug,name:hit.name??hit.title??hit.snippet??hit.recordId??"",unitAmount:toCents(hit.price)??0,imageUrl:hit.image_url})}};const showRecent=open&&query.trim()&&!loading&&hits.length===0&&recentSearches.length>0;const recipeSuggestion=getRecipeSuggestion?.(query)??null;const showRecipeSuggestion=open&&query.trim().length>=2&&recipeSuggestion&&!loading;const fieldShell=variant==="default"?"flex w-full items-center rounded-lg border border-aurora-border/90 bg-aurora-surface shadow-sm transition-colors focus-within:border-aurora-primary/70 focus-within:ring-1 focus-within:ring-aurora-primary/40":"flex w-full items-center rounded-lg bg-transparent";const inputClass="flex-1 min-w-0 h-10 py-0 pr-3 text-sm leading-normal text-aurora-text placeholder:text-aurora-muted "+"border-0 bg-transparent shadow-none outline-none ring-0 focus:outline-none focus:ring-0 "+"[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none";return _jsxs("div",{ref:containerRef,className:`relative w-full ${fullWidth?"":"max-w-[280px]"}`,children:[_jsxs("div",{className:fieldShell,children:[_jsx("span",{className:"flex h-10 w-10 shrink-0 items-center justify-center text-aurora-muted pointer-events-none","aria-hidden":true,children:_jsx(Search,{className:"h-4 w-4 shrink-0"})}),_jsx("input",{type:"search",value:query,onChange:e=>setQuery(e.target.value),onFocus:()=>(query.trim()||recentSearches.length)&&setOpen(true),placeholder:placeholder,className:inputClass,"aria-label":"Search products"})]}),open&&(query.trim()||showRecent)&&_jsx("div",{className:"absolute top-full left-0 right-0 mt-1 rounded-component bg-aurora-surface border border-aurora-border shadow-xl z-[9999] max-h-96 overflow-y-auto",children:loading?_jsx("div",{className:"p-4 text-aurora-muted text-sm",children:"Searching…"}):hits.length===0&&!showRecent&&!showRecipeSuggestion?_jsx("div",{className:"p-4 text-aurora-muted text-sm",children:"No results"}):_jsxs("div",{className:"py-2",children:[showRecipeSuggestion&&_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-b border-aurora-border",children:"Suggestions"}),showRecipeSuggestion&&_jsxs(Link,{href:`/catalogue?q=${encodeURIComponent(recipeSuggestion.replace("?","").split(" ")[0].toLowerCase())}`,onClick:()=>{addToRecent(recipeSuggestion);setOpen(false)},className:"flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors border-b border-aurora-border",children:[_jsx(Search,{className:"w-4 h-4 text-aurora-muted shrink-0"}),_jsx("span",{className:"font-medium truncate",children:recipeSuggestion})]}),hits.length>0&&_jsxs(_Fragment,{children:[_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-b border-aurora-border",children:"Products"}),_jsx("ul",{children:hits.slice(0,6).map(hit=>_jsx("li",{className:"group/item",children:_jsxs("div",{className:"flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors",children:[_jsxs(Link,{href:`/catalogue/${hit.recordId}`,onClick:()=>{handleProductSelect(hit);setOpen(false)},className:"flex items-center gap-3 flex-1 min-w-0",children:[_jsx("div",{className:"w-10 h-10 rounded-component bg-aurora-surface-hover shrink-0 overflow-hidden",children:_jsx(ProductImage,{src:hit.image_url,className:"w-full h-full",thumbnail:true,fallback:_jsx("div",{className:"w-full h-full flex items-center justify-center text-aurora-muted text-xs",children:"-"})})}),_jsxs("div",{className:"flex-1 min-w-0",children:[_jsx("p",{className:"font-medium truncate",children:hit.name??hit.title??hit.snippet??hit.recordId}),hit.price!=null&&Number(hit.price)>0&&_jsx("p",{className:"text-sm text-aurora-primary font-semibold",children:formatPrice(toCents(hit.price)??0)})]})]}),hit.price!=null&&Number(hit.price)>0&&_jsx("button",{type:"button",onClick:e=>{e.preventDefault();handleProductSelect(hit,true);setOpen(false)},className:"shrink-0 px-3 py-1.5 rounded-lg bg-aurora-primary text-white text-xs font-medium hover:bg-aurora-primary-dark transition-colors opacity-0 group-hover/item:opacity-100",children:"Quick add"})]})},`${hit.tableSlug}-${hit.recordId}`))}),categories.length>0&&_jsxs(_Fragment,{children:[_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-t border-b border-aurora-border mt-1",children:"Categories"}),_jsx("ul",{children:categories.map(cat=>_jsx("li",{children:_jsx(Link,{href:`/catalogue?category=${encodeURIComponent(String(cat).toLowerCase().replace(/\s+/g,"-"))}`,onClick:()=>{addToRecent(query);setOpen(false)},className:"flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors",children:_jsx("span",{className:"font-medium truncate",children:cat})})},cat))})]}),brands.length>0&&_jsxs(_Fragment,{children:[_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-t border-b border-aurora-border mt-1",children:"Brands"}),_jsx("ul",{children:brands.map(brand=>_jsx("li",{children:_jsx(Link,{href:`/catalogue?q=${encodeURIComponent(brand)}`,onClick:()=>{addToRecent(query);setOpen(false)},className:"flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors",children:_jsx("span",{className:"font-medium truncate",children:brand})})},brand))})]})]}),showRecent&&_jsxs(_Fragment,{children:[_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-b border-aurora-border",children:"Recent searches"}),_jsx("ul",{children:recentSearches.map(term=>_jsx("li",{children:_jsxs("button",{type:"button",onClick:()=>{setQuery(term);doSearch(term)},className:"w-full text-left flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors",children:[_jsx(Search,{className:"w-4 h-4 text-aurora-muted shrink-0"}),_jsx("span",{className:"font-medium truncate",children:term})]})},term))})]})]})})]})}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aurora-studio/starter-core",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "scripts": {
5
5
  "build": "tsc -p tsconfig.build.json && node scripts/minify-dist.mjs",
6
6
  "prepare": "tsc -p tsconfig.build.json && node scripts/minify-dist.mjs",