@zappie/theme-base 0.0.0-stage → 0.1.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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +64 -2
  3. package/dist/address.d.ts +32 -0
  4. package/dist/address.js +4 -0
  5. package/dist/address.js.map +1 -0
  6. package/dist/cart.d.ts +12 -0
  7. package/dist/cart.js +1140 -0
  8. package/dist/cart.js.map +1 -0
  9. package/dist/catalogue.d.ts +60 -0
  10. package/dist/catalogue.js +1389 -0
  11. package/dist/catalogue.js.map +1 -0
  12. package/dist/checkout.d.ts +36 -0
  13. package/dist/checkout.js +4 -0
  14. package/dist/checkout.js.map +1 -0
  15. package/dist/chunk-2MV6KU3R.js +352 -0
  16. package/dist/chunk-2MV6KU3R.js.map +1 -0
  17. package/dist/chunk-FB5DRCU7.js +146 -0
  18. package/dist/chunk-FB5DRCU7.js.map +1 -0
  19. package/dist/chunk-IG63ONID.js +139 -0
  20. package/dist/chunk-IG63ONID.js.map +1 -0
  21. package/dist/chunk-ILOCSCZL.js +217 -0
  22. package/dist/chunk-ILOCSCZL.js.map +1 -0
  23. package/dist/chunk-JFEI2OUZ.js +13 -0
  24. package/dist/chunk-JFEI2OUZ.js.map +1 -0
  25. package/dist/chunk-NTJONY3N.js +95 -0
  26. package/dist/chunk-NTJONY3N.js.map +1 -0
  27. package/dist/chunk-QWST2TA2.js +22 -0
  28. package/dist/chunk-QWST2TA2.js.map +1 -0
  29. package/dist/chunk-USSLDBDY.js +48 -0
  30. package/dist/chunk-USSLDBDY.js.map +1 -0
  31. package/dist/chunk-VIAJ27YC.js +59 -0
  32. package/dist/chunk-VIAJ27YC.js.map +1 -0
  33. package/dist/host-bridge.d.ts +100 -0
  34. package/dist/host-bridge.js +4 -0
  35. package/dist/host-bridge.js.map +1 -0
  36. package/dist/index.d.ts +3 -0
  37. package/dist/index.js +6 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/item-frame.d.ts +20 -0
  40. package/dist/item-frame.js +5 -0
  41. package/dist/item-frame.js.map +1 -0
  42. package/dist/item.d.ts +20 -0
  43. package/dist/item.js +153 -0
  44. package/dist/item.js.map +1 -0
  45. package/dist/navigation.d.ts +64 -0
  46. package/dist/navigation.js +4 -0
  47. package/dist/navigation.js.map +1 -0
  48. package/dist/styles.css +842 -0
  49. package/package.json +73 -3
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/url-navigation-state.ts","../src/url-navigation.ts","../src/navigation.tsx"],"names":[],"mappings":";;;;;;;AAGO,IAAM,gBAAA,GAAmB,oCAAA;AAEzB,IAAM,SAAA,GAAY,CAAC,KAAA,KAA2B;AACnD,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,MAAA,IAAU,KAAA,CAAM,SAAS,YAAA,EAAc;AACxD,IAAA,OAAO;AAAA,MACL,UAAU,KAAA,CAAM,QAAA;AAAA,MAChB,GAAI,MAAM,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAO,GAAI;AAAC,KAC/D;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT,CAAA;AAEO,IAAM,SAAA,GAAY,CACvB,KAAA,EACA,MAAA,KAOwB;AACxB,EAAA,MAAM,KAAA,GAAQ,EAAE,GAAG,KAAA,CAAM,KAAA,EAAM;AAC/B,EAAA,MAAM,IAAA,GAA4B,EAAE,GAAG,KAAA,EAAO,KAAA,EAAM;AACpD,EAAA,MAAM,MAAA,GAAS,CACb,QAAA,EACA,GAAA,EACA,KAAA,KACG;AACH,IAAA,IAAI,CAAC,MAAA,CAAO,MAAA,CAAO,MAAA,EAAQ,QAAQ,CAAA,EAAG;AACpC,MAAA;AAAA,IACF;AACA,IAAA,IAAI,UAAU,MAAA,EAAW;AACvB,MAAA,OAAO,MAAM,GAAG,CAAA;AAChB,MAAA,OAAO,KAAK,QAAQ,CAAA;AACpB,MAAA;AAAA,IACF;AACA,IAAA,KAAA,CAAM,GAAG,CAAA,GAAI,QAAA,KAAa,SAAS,MAAA,CAAO,KAAA,KAAU,QAAQ,CAAA,GAAI,KAAA;AAChE,IAAA,IAAI,aAAa,MAAA,EAAQ;AACvB,MAAA,IAAA,CAAK,IAAA,GAAO,KAAA,KAAU,QAAA,GAAW,QAAA,GAAW,UAAA;AAAA,IAC9C,CAAA,MAAA,IAAW,aAAa,QAAA,EAAU;AAChC,MAAA,IAAA,CAAK,MAAA,GAAS,KAAA;AAAA,IAChB,CAAA,MAAA,IAAW,aAAa,YAAA,EAAc;AACpC,MAAA,IAAA,CAAK,UAAA,GAAa,KAAA;AAAA,IACpB,CAAA,MAAA,IAAW,aAAa,YAAA,EAAc;AACpC,MAAA,IAAA,CAAK,UAAA,GAAa,KAAA;AAAA,IACpB,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AAAA,IACjB;AAAA,EACF,CAAA;AACA,EAAA,MAAA,CAAO,QAAA,EAAU,SAAA,EAAW,MAAA,CAAO,MAAM,CAAA;AACzC,EAAA,MAAA,CAAO,YAAA,EAAc,aAAA,EAAe,MAAA,CAAO,UAAU,CAAA;AACrD,EAAA,MAAA,CAAO,YAAA,EAAc,aAAA,EAAe,MAAA,CAAO,UAAU,CAAA;AACrD,EAAA,MAAA,CAAO,SAAA,EAAW,UAAA,EAAY,MAAA,CAAO,OAAO,CAAA;AAC5C,EAAA,MAAA,CAAO,MAAA,EAAQ,QAAA,EAAU,MAAA,CAAO,IAAI,CAAA;AACpC,EAAA,OAAO,IAAA;AACT,CAAA;AAEO,IAAM,cAAA,GAAiB,CAC5B,KAAA,EACA,KAAA,KACoB;AACpB,EAAA,MAAM,IAAA,GAAO,UAAU,KAAK,CAAA;AAC5B,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,YAAA;AAAA,IACN,GAAG,IAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA;;;AC5DO,SAAS,mBAAA,CACd,OAAA,GAAgC,EAAC,EACZ;AACrB,EAAA,MAAM,OAAA,GAAU,QAAQ,MAAA,IAAU,MAAA;AAClC,EAAA,MAAM,UAAU,MAAM,kBAAA,CAAmB,OAAA,CAAQ,QAAA,CAAS,MAAM,OAAO,CAAA;AAEvE,EAAA,MAAM,MAAA,GAAS,CAAC,KAAA,KACd,kBAAA,CAAmB,OAAO,OAAO,CAAA;AACnC,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,OAAA,CAAQ,aAAA;AAAA,MACN,IAAI,QAAQ,aAAA,CAAc,UAAA,EAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAO;AAAA,KACxE;AAAA,EACF,CAAA;AACA,EAAA,MAAM,KAAA,GAAQ,CAAC,GAAA,EAAa,MAAA,EAA4B,KAAA,KAAkB;AACxE,IAAA,MAAM,KAAA,GAAQ;AAAA,MACZ,GAAI,OAAO,OAAA,CAAQ,OAAA,CAAQ,KAAA,KAAU,QAAA,IAAY,OAAA,CAAQ,OAAA,CAAQ,KAAA,GAC7D,OAAA,CAAQ,OAAA,CAAQ,KAAA,GAChB,EAAC;AAAA,MACL,CAAC,gBAAgB,GAAG;AAAA,KACtB;AACA,IAAA,IAAI,WAAW,MAAA,EAAQ;AACrB,MAAA,OAAA,CAAQ,OAAA,CAAQ,SAAA,CAAU,KAAA,EAAO,EAAA,EAAI,GAAG,CAAA;AAAA,IAC1C,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,OAAA,CAAQ,YAAA,CAAa,KAAA,EAAO,EAAA,EAAI,GAAG,CAAA;AAAA,IAC7C;AACA,IAAA,MAAA,EAAO;AAAA,EACT,CAAA;AACA,EAAA,MAAM,OAAA,GAAU,CAAC,MAAA,KAAsC;AACrD,IAAA,MAAM,QAAQ,OAAA,EAAQ;AACtB,IAAA,MAAM,IAAA,GAAO,UAAU,KAAK,CAAA;AAC5B,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,OAAO,QAAQ,QAAA,CAAS,IAAA;AAAA,IAC1B;AACA,IAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,KAAA,CAAM,KAAA,EAAO;AAAA,MACnC,GAAI,OAAO,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,EAAQ,MAAA,CAAO,MAAA,EAAO,GAAI,EAAC;AAAA,MAC/D,GAAI,OAAO,UAAA,KAAe,MAAA,GACtB,EAAE,UAAA,EAAY,MAAA,CAAO,UAAA,EAAW,GAChC;AAAC,KACN,CAAA;AACD,IAAA,OAAO,MAAA,CAAO;AAAA,MACZ,IAAA,EAAM,MAAA;AAAA,MACN,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,GAAI,KAAK,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAO,GAAI,EAAC;AAAA,MAC3D,MAAM,MAAA,CAAO,MAAA;AAAA,MACb;AAAA,KACD,CAAA;AAAA,EACH,CAAA;AACA,EAAA,MAAM,kBAAkB,CACtB,MAAA,EACA,MAAA,GAA6B,SAAA,EAC7B,QAAQ,WAAA,KACL;AACH,IAAA,MAAM,QAAQ,OAAA,EAAQ;AACtB,IAAA,MAAM,OAAO,cAAA,CAAe,KAAA,EAAO,UAAU,KAAA,CAAM,KAAA,EAAO,MAAM,CAAC,CAAA;AACjE,IAAA,KAAA,CAAM,MAAA,CAAO,IAAI,CAAA,EAAG,MAAA,EAAQ,KAAK,CAAA;AAAA,EACnC,CAAA;AACA,EAAA,MAAM,YAAY,YAAY;AAC5B,IAAA,MAAM,QAAQ,OAAA,EAAQ;AACtB,IAAA,IAAI,KAAA,CAAM,SAAS,MAAA,EAAQ;AACzB,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAA,CAAQ,OAAA,CAAQ,KAAA,GAAQ,gBAAgB,MAAM,MAAA,EAAQ;AACxD,MAAA,MAAM,IAAI,OAAA,CAAc,CAAC,OAAA,KAAY;AACnC,QAAA,OAAA,CAAQ,gBAAA,CAAiB,YAAY,MAAM,OAAA,IAAW,EAAE,IAAA,EAAM,MAAM,CAAA;AACpE,QAAA,OAAA,CAAQ,QAAQ,IAAA,EAAK;AAAA,MACvB,CAAC,CAAA;AACD,MAAA;AAAA,IACF;AACA,IAAA,MAAM,IAAA,GAAO,cAAA;AAAA,MACX,KAAA;AAAA,MACA,UAAU,KAAA,CAAM,KAAA,EAAO,EAAE,OAAA,EAAS,QAAW;AAAA,KAC/C;AACA,IAAA,KAAA,CAAM,MAAA,CAAO,IAAI,CAAA,EAAG,SAAA,EAAW,WAAW,CAAA;AAAA,EAC5C,CAAA;AACA,EAAA,OAAO;AAAA,IACL,IAAI,QAAA,GAAW;AACb,MAAA,MAAM,QAAQ,OAAA,EAAQ;AACtB,MAAA,MAAM,MAAA,GAAS,MAAM,KAAA,CAAM,UAAA;AAC3B,MAAA,MAAM,aACJ,MAAA,KAAW,MAAA,IAAU,WAAW,MAAA,IAAU,MAAA,KAAW,SACjD,MAAA,GACA,MAAA;AACN,MAAA,OAAO;AAAA,QACL,QAAA,EAAU,QAAQ,QAAA,CAAS,QAAA;AAAA,QAC3B,GAAI,KAAA,CAAM,KAAA,CAAM,MAAA,KAAW,MAAA,GACvB,EAAE,MAAA,EAAQ,KAAA,CAAM,KAAA,CAAM,MAAA,EAAO,GAC7B,EAAC;AAAA,QACL,GAAI,KAAA,CAAM,KAAA,CAAM,UAAA,KAAe,MAAA,GAC3B,EAAE,UAAA,EAAY,KAAA,CAAM,KAAA,CAAM,UAAA,EAAW,GACrC,EAAC;AAAA,QACL,GAAI,UAAA,KAAe,MAAA,GAAY,EAAE,UAAA,KAAe,EAAC;AAAA,QACjD,GAAI,KAAA,CAAM,IAAA,KAAS,MAAA,GACf;AAAA,UACE,IAAA,EAAM;AAAA,YACJ,IAAI,KAAA,CAAM,IAAA;AAAA,YACV,IAAA,EAAM,QAAQ,QAAA,CAAS,QAAA;AAAA,YACvB,YAAA,EAAc,KAAA,CAAM,KAAA,CAAM,OAAA,GACrB,OAAA,GACA;AAAA;AACP,YAEF;AAAC,OACP;AAAA,IACF,CAAA;AAAA,IACA,OAAA;AAAA,IACA,WAAW,MAAA,EAAQ;AACjB,MAAA,eAAA,CAAgB,EAAE,QAAQ,CAAA;AAAA,IAC5B,CAAA;AAAA,IACA,eAAe,UAAA,EAAY;AACzB,MAAA,eAAA,CAAgB,EAAE,YAAY,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,UAAU,UAAA,EAAY;AACpB,MAAA,eAAA,CAAgB,EAAE,YAAY,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,MAAM,QAAA,CAAS,EAAE,MAAA,EAAQ,MAAA,EAAQ,YAAW,EAAG;AAC7C,MAAA,KAAA;AAAA,QACE,OAAA,CAAQ;AAAA,UAEN,MAAA;AAAA,UACA,MAAA;AAAA,UACA,GAAI,UAAA,KAAe,MAAA,GAAY,EAAE,UAAA,KAAe;AAAC,SAClD,CAAA;AAAA,QACD,MAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF,CAAA;AAAA,IACA,SAAA;AAAA,IACA,MAAM,QAAA,GAAW;AACf,MAAA,MAAM,SAAA,EAAU;AAChB,MAAA,eAAA,CAAgB,EAAE,OAAA,EAAS,aAAA,EAAc,EAAG,QAAQ,MAAM,CAAA;AAAA,IAC5D,CAAA;AAAA,IACA,MAAM,gBAAA,GAAmB;AACvB,MAAA,MAAM,SAAA,EAAU;AAChB,MAAA,eAAA,CAAgB,EAAE,OAAA,EAAS,eAAA,EAAgB,EAAG,QAAQ,eAAe,CAAA;AAAA,IACvE,CAAA;AAAA,IACA,MAAM,iBAAA,GAAoB;AACxB,MAAA,MAAM,SAAA,EAAU;AAChB,MAAA,eAAA,CAAgB,EAAE,OAAA,EAAS,gBAAA,EAAiB,EAAG,QAAQ,gBAAgB,CAAA;AAAA,IACzE,CAAA;AAAA,IACA,MAAM,iBAAiB,IAAA,EAAM;AAC3B,MAAA,MAAM,SAAA,EAAU;AAChB,MAAA,eAAA,CAAgB,EAAE,MAAM,CAAA;AACxB,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA,YAAA,CAAa,EAAE,MAAA,EAAO,EAAG;AACvB,MAAA,MAAM,IAAA,GAAO,SACT,OAAA,CAAQ,QAAA,CAAS,eAAe,CAAA,UAAA,EAAa,MAAM,EAAE,CAAA,GACrD,IAAA;AACJ,MAAA,MAAM,MAAA,GACJ,IAAA,IAAQ,OAAA,CAAQ,QAAA,CAAS,eAAe,wBAAwB,CAAA;AAClE,MAAA,MAAA,EAAQ,KAAA,EAAM;AAAA,IAChB;AAAA,GACF;AACF;AC5GA,IAAM,OAAA,GAAU,cAA0C,IAAI,CAAA;AAEvD,SAAS,2BAAA,CAA4B;AAAA,EAC1C,UAAA;AAAA,EACA;AACF,CAAA,EAGG;AACD,EAAA,MAAM,GAAG,OAAO,CAAA,GAAI,SAAS,CAAC,CAAA;AAC9B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,SAAS,MAAM,OAAA,CAAQ,CAAC,KAAA,KAAU,QAAQ,CAAC,CAAA;AACjD,IAAA,MAAA,CAAO,gBAAA,CAAiB,YAAY,MAAM,CAAA;AAC1C,IAAA,OAAO,MAAM;AACX,MAAA,MAAA,CAAO,mBAAA,CAAoB,YAAY,MAAM,CAAA;AAAA,IAC/C,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AACf,EAAA,2BAAQ,OAAA,CAAQ,QAAA,EAAR,EAAiB,KAAA,EAAO,YAAa,QAAA,EAAS,CAAA;AACxD;AAEO,SAAS,sBAAA,GAAyB;AACvC,EAAA,MAAM,UAAA,GAAa,WAAW,OAAO,CAAA;AACrC,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACA,EAAA,OAAO,UAAA;AACT","file":"chunk-ILOCSCZL.js","sourcesContent":["import type { StorefrontPageState, StorefrontRoute } from \"@zappie/sdk/url\";\n\n/** History-state key marking entries this provider pushed, so close can go Back. */\nexport const NAVIGATION_ENTRY = \"zappie:storefront-navigation-entry\";\n\nexport const routeBase = (route: StorefrontRoute) => {\n if (route.type === \"item\" || route.type === \"order-menu\") {\n return {\n business: route.business,\n ...(route.branch !== undefined ? { branch: route.branch } : {}),\n };\n }\n return null;\n};\n\nexport const stateWith = (\n state: StorefrontPageState,\n values: {\n menuId?: string | undefined;\n categoryId?: string | undefined;\n menuLayout?: string | undefined;\n modalId?: string | undefined;\n mode?: \"delivery\" | \"pickup\" | undefined;\n },\n): StorefrontPageState => {\n const query = { ...state.query };\n const next: StorefrontPageState = { ...state, query };\n const update = (\n property: \"menuId\" | \"categoryId\" | \"menuLayout\" | \"modalId\" | \"mode\",\n key: string,\n value: string | undefined,\n ) => {\n if (!Object.hasOwn(values, property)) {\n return;\n }\n if (value === undefined) {\n delete query[key];\n delete next[property];\n return;\n }\n query[key] = property === \"mode\" ? String(value === \"pickup\") : value;\n if (property === \"mode\") {\n next.mode = value === \"pickup\" ? \"pickup\" : \"delivery\";\n } else if (property === \"menuId\") {\n next.menuId = value;\n } else if (property === \"categoryId\") {\n next.categoryId = value;\n } else if (property === \"menuLayout\") {\n next.menuLayout = value;\n } else {\n next.modalId = value;\n }\n };\n update(\"menuId\", \"menu_id\", values.menuId);\n update(\"categoryId\", \"category_id\", values.categoryId);\n update(\"menuLayout\", \"menu_layout\", values.menuLayout);\n update(\"modalId\", \"modal_id\", values.modalId);\n update(\"mode\", \"pickup\", values.mode);\n return next;\n};\n\nexport const catalogueRoute = (\n route: StorefrontRoute,\n state: StorefrontPageState,\n): StorefrontRoute => {\n const base = routeBase(route);\n if (!base) {\n return route;\n }\n return {\n type: \"order-menu\",\n ...base,\n state,\n };\n};\n","import { buildStorefrontUrl, parseStorefrontUrl } from \"@zappie/sdk/url\";\nimport type {\n CatalogueLocation,\n CatalogueNavigation,\n CatalogueNavigationTarget,\n UrlNavigationOptions,\n} from \"./navigation\";\nimport {\n catalogueRoute,\n NAVIGATION_ENTRY,\n routeBase,\n stateWith,\n} from \"./url-navigation-state\";\n\nexport function createUrlNavigation(\n options: UrlNavigationOptions = {},\n): CatalogueNavigation {\n const browser = options.window ?? window;\n const current = () => parseStorefrontUrl(browser.location.href, options);\n\n const urlFor = (route: Parameters<typeof buildStorefrontUrl>[0]) =>\n buildStorefrontUrl(route, options);\n const notify = () => {\n browser.dispatchEvent(\n new browser.PopStateEvent(\"popstate\", { state: browser.history.state }),\n );\n };\n const write = (url: string, method: \"push\" | \"replace\", entry: string) => {\n const state = {\n ...(typeof browser.history.state === \"object\" && browser.history.state\n ? browser.history.state\n : {}),\n [NAVIGATION_ENTRY]: entry,\n };\n if (method === \"push\") {\n browser.history.pushState(state, \"\", url);\n } else {\n browser.history.replaceState(state, \"\", url);\n }\n notify();\n };\n const hrefFor = (target: CatalogueNavigationTarget) => {\n const route = current();\n const base = routeBase(route);\n if (!base) {\n return browser.location.href;\n }\n const state = stateWith(route.state, {\n ...(target.menuId !== undefined ? { menuId: target.menuId } : {}),\n ...(target.categoryId !== undefined\n ? { categoryId: target.categoryId }\n : {}),\n });\n return urlFor({\n type: \"item\",\n business: base.business,\n ...(base.branch !== undefined ? { branch: base.branch } : {}),\n item: target.itemId,\n state,\n });\n };\n const updateCatalogue = (\n values: Parameters<typeof stateWith>[1],\n method: \"push\" | \"replace\" = \"replace\",\n entry = \"catalogue\",\n ) => {\n const route = current();\n const next = catalogueRoute(route, stateWith(route.state, values));\n write(urlFor(next), method, entry);\n };\n const closeItem = async () => {\n const route = current();\n if (route.type !== \"item\") {\n return;\n }\n if (browser.history.state?.[NAVIGATION_ENTRY] === \"item\") {\n await new Promise<void>((resolve) => {\n browser.addEventListener(\"popstate\", () => resolve(), { once: true });\n browser.history.back();\n });\n return;\n }\n const next = catalogueRoute(\n route,\n stateWith(route.state, { modalId: undefined }),\n );\n write(urlFor(next), \"replace\", \"catalogue\");\n };\n return {\n get location() {\n const route = current();\n const layout = route.state.menuLayout;\n const menuLayout: CatalogueLocation[\"menuLayout\"] =\n layout === \"GRID\" || layout === \"LIST\" || layout === \"CARD\"\n ? layout\n : undefined;\n return {\n pathname: browser.location.pathname,\n ...(route.state.menuId !== undefined\n ? { menuId: route.state.menuId }\n : {}),\n ...(route.state.categoryId !== undefined\n ? { categoryId: route.state.categoryId }\n : {}),\n ...(menuLayout !== undefined ? { menuLayout } : {}),\n ...(route.type === \"item\"\n ? {\n item: {\n id: route.item,\n path: browser.location.pathname,\n presentation: route.state.modalId\n ? (\"query\" as const)\n : (\"path\" as const),\n },\n }\n : {}),\n };\n },\n hrefFor,\n selectMenu(menuId) {\n updateCatalogue({ menuId });\n },\n selectCategory(categoryId) {\n updateCatalogue({ categoryId });\n },\n setLayout(menuLayout) {\n updateCatalogue({ menuLayout });\n },\n async openItem({ itemId, menuId, categoryId }) {\n write(\n hrefFor({\n type: \"item\",\n itemId,\n menuId,\n ...(categoryId !== undefined ? { categoryId } : {}),\n }),\n \"push\",\n \"item\",\n );\n },\n closeItem,\n async openCart() {\n await closeItem();\n updateCatalogue({ modalId: \"review-menu\" }, \"push\", \"cart\");\n },\n async openBranchFinder() {\n await closeItem();\n updateCatalogue({ modalId: \"branch-finder\" }, \"push\", \"branch-finder\");\n },\n async openBranchDetails() {\n await closeItem();\n updateCatalogue({ modalId: \"branch-details\" }, \"push\", \"branch-details\");\n },\n async switchFulfilment(mode) {\n await closeItem();\n updateCatalogue({ mode });\n return true;\n },\n restoreFocus({ itemId }) {\n const item = itemId\n ? browser.document.getElementById(`base-item-${itemId}`)\n : null;\n const target =\n item ?? browser.document.getElementById(\"base-catalogue-heading\");\n target?.focus();\n },\n };\n}\n","\"use client\";\n\nimport type { Item } from \"@zappie/sdk\";\nimport type { StorefrontUrlOptions } from \"@zappie/sdk/url\";\nimport {\n createContext,\n useContext,\n useEffect,\n useState,\n type ReactNode,\n} from \"react\";\n\n/** URL-owned selection, shared by template routers and reusable base screens. */\nexport type CatalogueLocation = {\n pathname: string;\n menuId?: string;\n categoryId?: string;\n menuLayout?: \"GRID\" | \"LIST\" | \"CARD\";\n item?: { id: string; path: string; presentation: \"path\" | \"query\" };\n};\n\n/** Stable identities, not host selectors or retained DOM nodes. */\nexport type CatalogueFocusTarget = { itemId?: string; fallback: \"catalogue\" };\n\nexport type CatalogueNavigationTarget = {\n type: \"item\";\n itemId: string;\n menuId?: string;\n categoryId?: string;\n};\n\nexport type CatalogueNavigation = {\n /** Fresh URL snapshot on every read; providers re-render on history changes. */\n readonly location: CatalogueLocation;\n hrefFor(target: CatalogueNavigationTarget): string;\n selectMenu(menuId: string): void;\n selectCategory(categoryId: string): void;\n setLayout(layout: NonNullable<CatalogueLocation[\"menuLayout\"]>): void;\n openItem(input: {\n itemId: string;\n /** Already normalized catalogue/search item; opening it must not fetch it again. */\n item?: Item;\n menuId: string;\n categoryId?: string;\n }): Promise<void>;\n /** Resolves after history changes and the item releases its modal/focus lock. */\n closeItem(): Promise<void>;\n /** Close the active item/base overlay before opening another surface. */\n openCart(): Promise<void>;\n openBranchFinder(): Promise<void>;\n openBranchDetails?(): Promise<void>;\n switchFulfilment(mode: \"delivery\" | \"pickup\"): Promise<boolean>;\n /** Called after close settles; use a registered trigger, or the catalogue heading. */\n restoreFocus(target: CatalogueFocusTarget): void;\n};\n\nexport type UrlNavigationOptions = StorefrontUrlOptions & {\n window?: Window & typeof globalThis;\n};\nconst Context = createContext<CatalogueNavigation | null>(null);\n\nexport function CatalogueNavigationProvider({\n navigation,\n children,\n}: {\n navigation: CatalogueNavigation;\n children: ReactNode;\n}) {\n const [, refresh] = useState(0);\n useEffect(() => {\n const update = () => refresh((value) => value + 1);\n window.addEventListener(\"popstate\", update);\n return () => {\n window.removeEventListener(\"popstate\", update);\n };\n }, [navigation]);\n return <Context.Provider value={navigation}>{children}</Context.Provider>;\n}\n\nexport function useCatalogueNavigation() {\n const navigation = useContext(Context);\n if (!navigation) {\n throw new Error(\n \"useCatalogueNavigation requires CatalogueNavigationProvider\",\n );\n }\n return navigation;\n}\n\nexport { createUrlNavigation } from \"./url-navigation\";\n"]}
@@ -0,0 +1,13 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ // src/cart/theme-class.tsx
4
+ var ThemeClass = createContext(void 0);
5
+ var ThemeClassProvider = ThemeClass.Provider;
6
+ function useThemeClass(className) {
7
+ const themeClass = useContext(ThemeClass);
8
+ return themeClass ? `${className} ${themeClass}` : className;
9
+ }
10
+
11
+ export { ThemeClassProvider, useThemeClass };
12
+ //# sourceMappingURL=chunk-JFEI2OUZ.js.map
13
+ //# sourceMappingURL=chunk-JFEI2OUZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cart/theme-class.tsx"],"names":[],"mappings":";;;AAEA,IAAM,UAAA,GAAa,cAAkC,MAAS,CAAA;AACvD,IAAM,qBAAqB,UAAA,CAAW;AAMtC,SAAS,cAAc,SAAA,EAAmB;AAC/C,EAAA,MAAM,UAAA,GAAa,WAAW,UAAU,CAAA;AACxC,EAAA,OAAO,UAAA,GAAa,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,GAAK,SAAA;AACrD","file":"chunk-JFEI2OUZ.js","sourcesContent":["\"use client\";\nimport { createContext, useContext } from \"react\";\nconst ThemeClass = createContext<string | undefined>(undefined);\nexport const ThemeClassProvider = ThemeClass.Provider;\n/**\n * Class names for an overlay root, plus the class a template passed to\n * `CartReview`. Overlays render in a portal, outside any template wrapper, so\n * a template's tokens reach them only through this class.\n */\nexport function useThemeClass(className: string) {\n const themeClass = useContext(ThemeClass);\n return themeClass ? `${className} ${themeClass}` : className;\n}\n"]}
@@ -0,0 +1,95 @@
1
+ import { createContext, useContext } from 'react';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ // src/address.tsx
5
+ function deliveryAddress(place, source) {
6
+ const result = {
7
+ line1: place.line1,
8
+ placeId: place.place_id,
9
+ coordinates: { lat: place.lat, lng: place.lng }
10
+ };
11
+ if (place.city !== void 0) {
12
+ result.city = place.city;
13
+ }
14
+ if (source?.line2 !== void 0) {
15
+ result.line2 = source.line2;
16
+ }
17
+ if (source?.instructions !== void 0) {
18
+ result.instructions = source.instructions;
19
+ }
20
+ return result;
21
+ }
22
+ var Context = createContext(null);
23
+ function AddressLookupProvider({
24
+ lookup,
25
+ children
26
+ }) {
27
+ return /* @__PURE__ */ jsx(Context.Provider, { value: lookup, children });
28
+ }
29
+ function useAddressLookup() {
30
+ const lookup = useContext(Context);
31
+ if (!lookup) {
32
+ throw new Error("useAddressLookup requires AddressLookupProvider");
33
+ }
34
+ return lookup;
35
+ }
36
+ function createSdkAddressLookup({
37
+ places,
38
+ branchId
39
+ }) {
40
+ let sessionToken = crypto.randomUUID();
41
+ const Map = ({ address }) => {
42
+ if (!address.coordinates) {
43
+ return null;
44
+ }
45
+ return (
46
+ // The theme can't use next/image; the map's size is fixed by the API.
47
+ // eslint-disable-next-line @next/next/no-img-element
48
+ /* @__PURE__ */ jsx(
49
+ "img",
50
+ {
51
+ className: "z-base-address-map",
52
+ src: places.staticMapUrl(
53
+ address.coordinates.lat,
54
+ address.coordinates.lng,
55
+ branchId
56
+ ),
57
+ alt: `Map of ${address.line1}`,
58
+ width: 640,
59
+ height: 320,
60
+ loading: "lazy"
61
+ }
62
+ )
63
+ );
64
+ };
65
+ return {
66
+ async suggest(query) {
67
+ const suggestions = await places.autocomplete(query, sessionToken);
68
+ return suggestions.map((suggestion) => ({
69
+ placeId: suggestion.place_id,
70
+ address: suggestion.secondary ? `${suggestion.text}, ${suggestion.secondary}` : suggestion.text,
71
+ sessionToken
72
+ }));
73
+ },
74
+ async resolve(address, token) {
75
+ if (!address.placeId) {
76
+ throw new Error("Choose a suggested delivery address");
77
+ }
78
+ const place = await places.place(address.placeId, {
79
+ branchId,
80
+ sessionToken: token ?? sessionToken
81
+ });
82
+ sessionToken = crypto.randomUUID();
83
+ return deliveryAddress(place, address);
84
+ },
85
+ async reverse({ lat, lng }) {
86
+ const place = await places.reverse(lat, lng);
87
+ return deliveryAddress(place);
88
+ },
89
+ Map
90
+ };
91
+ }
92
+
93
+ export { AddressLookupProvider, createSdkAddressLookup, useAddressLookup };
94
+ //# sourceMappingURL=chunk-NTJONY3N.js.map
95
+ //# sourceMappingURL=chunk-NTJONY3N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/address.tsx"],"names":[],"mappings":"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","file":"chunk-NTJONY3N.js","sourcesContent":["\"use client\";\n\nimport type { DeliveryAddress } from \"@zappie/sdk\";\nimport type { Place, PlacesClient } from \"@zappie/sdk/places\";\nimport {\n createContext,\n useContext,\n type ComponentType,\n type ReactNode,\n} from \"react\";\n\nexport type AddressSuggestion = {\n placeId: string;\n address: string;\n sessionToken?: string;\n};\n\nexport type AddressLookup = {\n suggest(query: string): Promise<AddressSuggestion[]>;\n reverse?(coordinates: { lat: number; lng: number }): Promise<DeliveryAddress>;\n resolve?(\n address: DeliveryAddress,\n sessionToken?: string,\n ): Promise<DeliveryAddress>;\n Map?: ComponentType<{ address: DeliveryAddress }>;\n};\n\nfunction deliveryAddress(\n place: Place,\n source?: DeliveryAddress,\n): DeliveryAddress {\n const result: DeliveryAddress = {\n line1: place.line1,\n placeId: place.place_id,\n coordinates: { lat: place.lat, lng: place.lng },\n };\n if (place.city !== undefined) {\n result.city = place.city;\n }\n if (source?.line2 !== undefined) {\n result.line2 = source.line2;\n }\n if (source?.instructions !== undefined) {\n result.instructions = source.instructions;\n }\n return result;\n}\n\nconst Context = createContext<AddressLookup | null>(null);\n\nexport function AddressLookupProvider({\n lookup,\n children,\n}: {\n lookup: AddressLookup;\n children: ReactNode;\n}) {\n return <Context.Provider value={lookup}>{children}</Context.Provider>;\n}\n\nexport function useAddressLookup() {\n const lookup = useContext(Context);\n if (!lookup) {\n throw new Error(\"useAddressLookup requires AddressLookupProvider\");\n }\n return lookup;\n}\n\nexport function createSdkAddressLookup({\n places,\n branchId,\n}: {\n places: PlacesClient;\n branchId: string;\n}): AddressLookup {\n let sessionToken = crypto.randomUUID();\n const Map = ({ address }: { address: DeliveryAddress }) => {\n if (!address.coordinates) {\n return null;\n }\n return (\n // The theme can't use next/image; the map's size is fixed by the API.\n // eslint-disable-next-line @next/next/no-img-element\n <img\n className=\"z-base-address-map\"\n src={places.staticMapUrl(\n address.coordinates.lat,\n address.coordinates.lng,\n branchId,\n )}\n alt={`Map of ${address.line1}`}\n width={640}\n height={320}\n loading=\"lazy\"\n />\n );\n };\n return {\n async suggest(query) {\n const suggestions = await places.autocomplete(query, sessionToken);\n return suggestions.map((suggestion) => ({\n placeId: suggestion.place_id,\n address: suggestion.secondary\n ? `${suggestion.text}, ${suggestion.secondary}`\n : suggestion.text,\n sessionToken,\n }));\n },\n async resolve(address, token) {\n if (!address.placeId) {\n throw new Error(\"Choose a suggested delivery address\");\n }\n const place = await places.place(address.placeId, {\n branchId,\n sessionToken: token ?? sessionToken,\n });\n sessionToken = crypto.randomUUID();\n return deliveryAddress(place, address);\n },\n async reverse({ lat, lng }) {\n const place = await places.reverse(lat, lng);\n return deliveryAddress(place);\n },\n Map,\n };\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import { createContext, useContext } from 'react';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ // src/host-bridge.tsx
5
+ var Context = createContext(null);
6
+ function BaseHostBridgeProvider({
7
+ bridge,
8
+ children
9
+ }) {
10
+ return /* @__PURE__ */ jsx(Context.Provider, { value: bridge, children });
11
+ }
12
+ function useBaseHostBridge() {
13
+ const bridge = useContext(Context);
14
+ if (!bridge) {
15
+ throw new Error("useBaseHostBridge requires BaseHostBridgeProvider");
16
+ }
17
+ return bridge;
18
+ }
19
+
20
+ export { BaseHostBridgeProvider, useBaseHostBridge };
21
+ //# sourceMappingURL=chunk-QWST2TA2.js.map
22
+ //# sourceMappingURL=chunk-QWST2TA2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/host-bridge.tsx"],"names":[],"mappings":";;;;AAuFA,IAAM,OAAA,GAAU,cAAqC,IAAI,CAAA;AAClD,SAAS,sBAAA,CAAuB;AAAA,EACrC,MAAA;AAAA,EACA;AACF,CAAA,EAGG;AACD,EAAA,2BAAQ,OAAA,CAAQ,QAAA,EAAR,EAAiB,KAAA,EAAO,QAAS,QAAA,EAAS,CAAA;AACpD;AACO,SAAS,iBAAA,GAAoB;AAClC,EAAA,MAAM,MAAA,GAAS,WAAW,OAAO,CAAA;AACjC,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,IAAI,MAAM,mDAAmD,CAAA;AAAA,EACrE;AACA,EAAA,OAAO,MAAA;AACT","file":"chunk-QWST2TA2.js","sourcesContent":["\"use client\";\nimport type { CartFulfilment, Money, OpeningTime } from \"@zappie/sdk\";\nimport { createContext, useContext, type ReactNode } from \"react\";\n\nexport type { AddressSuggestion } from \"./address\";\nexport type HostPromo = {\n id: string;\n name: string;\n description: string;\n code: string;\n disabled: boolean;\n endsAt?: string;\n};\nexport type HostReward = {\n id: string;\n name: string;\n description: string;\n pointsCost: number;\n disabled: boolean;\n reward: string;\n};\nexport type HostAppliedReward = {\n redemptionId: string;\n perkId: string;\n name: string;\n pointsSpent: number;\n};\n/** Temporary Stage A integration. Themes never import host stores or payment implementations. */\nexport type BaseHostBridge = {\n /**\n * Host-optimised, responsive URLs for a merchant image at the given\n * `sizes`. Absent, themes load the original URL.\n */\n imageProps?(\n src: string,\n sizes: string,\n ): { src: string; srcSet?: string; sizes?: string };\n /**\n * Recoverable host synchronization or checkout failure for the cart screen.\n * Host checkout failures are reported here, so callers don't show them again.\n */\n error?: string | null;\n /** Host-owned mode capabilities during Stage A. */\n fulfilmentMode?: \"delivery\" | \"pickup\";\n scheduleMaxDays?: number;\n /** Delivery regions, when the branch prices delivery by region (else absent). */\n deliveryRegions?: { id: string; name: string; fee: Money }[];\n deliveryRegionId?: string;\n setDeliveryRegion?(id: string): void;\n /**\n * Details the business requires before payment (absent when it requires\n * none). Values start from the customer's profile; the host saves them to\n * the profile when the order is confirmed.\n */\n customerDetails?: {\n requiresEmail: boolean;\n values: CustomerDetailsValues;\n update(field: keyof CustomerDetailsValues, value: string): void;\n };\n /** Opening hours the host accepts scheduled orders in (may start later than the branch's). */\n scheduleOpeningTimes?: OpeningTime[];\n saveFulfilment?: (value: CartFulfilment) => void;\n availablePromos?: HostPromo[];\n rewards?: {\n balance: number;\n items: HostReward[];\n applied: HostAppliedReward[];\n busyPerkId?: string;\n redeem(perkId: string): Promise<void>;\n cancel(redemptionId: string): Promise<void>;\n };\n deliveryDistance?: {\n status: \"unknown\" | \"far\" | \"too_far\";\n message?: string;\n };\n /**\n * Switches the host between delivery and pickup. The host keeps a basket per\n * mode, so the cart remounts against the other basket; returns false when the\n * branch or menu does not allow the switch.\n */\n setFulfilmentMode(mode: \"delivery\" | \"pickup\"): boolean;\n};\nexport type CustomerDetailsValues = {\n firstName: string;\n lastName: string;\n email: string;\n};\nconst Context = createContext<BaseHostBridge | null>(null);\nexport function BaseHostBridgeProvider({\n bridge,\n children,\n}: {\n bridge: BaseHostBridge;\n children: ReactNode;\n}) {\n return <Context.Provider value={bridge}>{children}</Context.Provider>;\n}\nexport function useBaseHostBridge() {\n const bridge = useContext(Context);\n if (!bridge) {\n throw new Error(\"useBaseHostBridge requires BaseHostBridgeProvider\");\n }\n return bridge;\n}\n"]}
@@ -0,0 +1,48 @@
1
+ import { useBaseHostBridge } from './chunk-QWST2TA2.js';
2
+ import { createSanitizeRichText } from '@zappie/foundations/rich-text';
3
+ import { parseRichText } from '@zappie/foundations/rich-text/browser';
4
+ import { useState, useEffect } from 'react';
5
+ import { jsx } from 'react/jsx-runtime';
6
+
7
+ var sanitize = createSanitizeRichText(parseRichText);
8
+ function Description({ value }) {
9
+ const [html, setHtml] = useState("");
10
+ useEffect(() => setHtml(sanitize(value)), [value]);
11
+ return /* @__PURE__ */ jsx(
12
+ "div",
13
+ {
14
+ className: "z-base-description",
15
+ dangerouslySetInnerHTML: { __html: html }
16
+ }
17
+ );
18
+ }
19
+ function ItemImage({
20
+ src,
21
+ sizes,
22
+ priority = false
23
+ }) {
24
+ const bridge = useBaseHostBridge();
25
+ const [failed, setFailed] = useState(false);
26
+ useEffect(() => setFailed(false), [src]);
27
+ const image = src ? bridge.imageProps?.(src, sizes) ?? { src } : void 0;
28
+ return /* @__PURE__ */ jsx("div", { className: "z-base-item-image", children: image && !failed ? (
29
+ // Public themes remain framework independent; the host may optimise
30
+ // image URLs through the bridge.
31
+ // eslint-disable-next-line @next/next/no-img-element
32
+ /* @__PURE__ */ jsx(
33
+ "img",
34
+ {
35
+ ...image,
36
+ loading: priority ? "eager" : "lazy",
37
+ fetchPriority: priority ? "high" : "auto",
38
+ decoding: "async",
39
+ alt: "",
40
+ onError: () => setFailed(true)
41
+ }
42
+ )
43
+ ) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "Image unavailable" }) });
44
+ }
45
+
46
+ export { Description, ItemImage };
47
+ //# sourceMappingURL=chunk-USSLDBDY.js.map
48
+ //# sourceMappingURL=chunk-USSLDBDY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/catalogue/presentation.tsx"],"names":[],"mappings":";;;;;;AAKA,IAAM,QAAA,GAAW,uBAAuB,aAAa,CAAA;AAC9C,SAAS,WAAA,CAAY,EAAE,KAAA,EAAM,EAAsB;AACxD,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,EAAE,CAAA;AACnC,EAAA,SAAA,CAAU,MAAM,QAAQ,QAAA,CAAS,KAAK,CAAC,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACjD,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,oBAAA;AAAA,MACV,uBAAA,EAAyB,EAAE,MAAA,EAAQ,IAAA;AAAK;AAAA,GAC1C;AAEJ;AACO,SAAS,SAAA,CAAU;AAAA,EACxB,GAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA,GAAW;AACb,CAAA,EAMG;AACD,EAAA,MAAM,SAAS,iBAAA,EAAkB;AACjC,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAS,KAAK,CAAA;AAC1C,EAAA,SAAA,CAAU,MAAM,SAAA,CAAU,KAAK,CAAA,EAAG,CAAC,GAAG,CAAC,CAAA;AACvC,EAAA,MAAM,KAAA,GAAQ,MAAO,MAAA,CAAO,UAAA,GAAa,KAAK,KAAK,CAAA,IAAK,EAAE,GAAA,EAAI,GAAK,MAAA;AACnE,EAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mBAAA,EACZ,mBAAS,CAAC,MAAA;AAAA;AAAA;AAAA;AAAA,oBAIT,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACE,GAAG,KAAA;AAAA,QACJ,OAAA,EAAS,WAAW,OAAA,GAAU,MAAA;AAAA,QAC9B,aAAA,EAAe,WAAW,MAAA,GAAS,MAAA;AAAA,QACnC,QAAA,EAAS,OAAA;AAAA,QACT,GAAA,EAAI,EAAA;AAAA,QACJ,OAAA,EAAS,MAAM,SAAA,CAAU,IAAI;AAAA;AAAA;AAC/B,sBAEA,GAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAY,MAAA,EAAO,+BAAiB,CAAA,EAE9C,CAAA;AAEJ","file":"chunk-USSLDBDY.js","sourcesContent":["\"use client\";\nimport { createSanitizeRichText } from \"@zappie/foundations/rich-text\";\nimport { parseRichText } from \"@zappie/foundations/rich-text/browser\";\nimport { useEffect, useState } from \"react\";\nimport { useBaseHostBridge } from \"../host-bridge\";\nconst sanitize = createSanitizeRichText(parseRichText);\nexport function Description({ value }: { value: string }) {\n const [html, setHtml] = useState(\"\");\n useEffect(() => setHtml(sanitize(value)), [value]);\n return (\n <div\n className=\"z-base-description\"\n dangerouslySetInnerHTML={{ __html: html }}\n />\n );\n}\nexport function ItemImage({\n src,\n sizes,\n priority = false,\n}: {\n src?: string | undefined;\n /** Rendered width hint for responsive host images. */\n sizes: string;\n /** Tiles likely to be the largest paint load first instead of lazily. */\n priority?: boolean;\n}) {\n const bridge = useBaseHostBridge();\n const [failed, setFailed] = useState(false);\n useEffect(() => setFailed(false), [src]);\n const image = src ? (bridge.imageProps?.(src, sizes) ?? { src }) : undefined;\n return (\n <div className=\"z-base-item-image\">\n {image && !failed ? (\n // Public themes remain framework independent; the host may optimise\n // image URLs through the bridge.\n // eslint-disable-next-line @next/next/no-img-element\n <img\n {...image}\n loading={priority ? \"eager\" : \"lazy\"}\n fetchPriority={priority ? \"high\" : \"auto\"}\n decoding=\"async\"\n alt=\"\"\n onError={() => setFailed(true)}\n />\n ) : (\n <span aria-hidden=\"true\">Image unavailable</span>\n )}\n </div>\n );\n}\n"]}
@@ -0,0 +1,59 @@
1
+ import { ThemeClassProvider } from './chunk-JFEI2OUZ.js';
2
+ import { Overlay } from '@zappie/foundations';
3
+ import { createContext, useRef } from 'react';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ var ItemEscapeContext = createContext(null);
7
+ function ItemFrame({
8
+ id,
9
+ name,
10
+ hasImages,
11
+ navigation,
12
+ themeClass,
13
+ children
14
+ }) {
15
+ const escape = useRef(void 0);
16
+ const classes = [
17
+ "z-base-cart z-base-item",
18
+ hasImages ? "z-base-item-with-media" : "",
19
+ themeClass
20
+ ].filter(Boolean).join(" ");
21
+ return /* @__PURE__ */ jsx(ItemEscapeContext.Provider, { value: escape, children: /* @__PURE__ */ jsx(ThemeClassProvider, { value: themeClass, children: /* @__PURE__ */ jsx(
22
+ Overlay.Root,
23
+ {
24
+ param: "modal_id",
25
+ id: `product_${id}`,
26
+ navigation,
27
+ presentation: { base: "drawer", lg: "dialog" },
28
+ children: /* @__PURE__ */ jsxs(
29
+ Overlay.Content,
30
+ {
31
+ "data-zappie-theme": "base",
32
+ className: classes,
33
+ "aria-label": name,
34
+ onEscape: (event) => {
35
+ if (escape.current) {
36
+ event.preventDefault();
37
+ escape.current();
38
+ }
39
+ },
40
+ children: [
41
+ /* @__PURE__ */ jsx("header", { className: "z-base-item-header", children: /* @__PURE__ */ jsx(
42
+ Overlay.Close,
43
+ {
44
+ className: "z-base-button-secondary",
45
+ "aria-label": "Close product",
46
+ children: "\u2715"
47
+ }
48
+ ) }),
49
+ children
50
+ ]
51
+ }
52
+ )
53
+ }
54
+ ) }) });
55
+ }
56
+
57
+ export { ItemEscapeContext, ItemFrame };
58
+ //# sourceMappingURL=chunk-VIAJ27YC.js.map
59
+ //# sourceMappingURL=chunk-VIAJ27YC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/item/frame.tsx"],"names":[],"mappings":";;;;;AAIO,IAAM,iBAAA,GAAoB,cAEvB,IAAI;AAEP,SAAS,SAAA,CAAU;AAAA,EACxB,EAAA;AAAA,EACA,IAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAAA,EAOG;AACD,EAAA,MAAM,MAAA,GAAS,OAAiC,MAAS,CAAA;AACzD,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,yBAAA;AAAA,IACA,YAAY,wBAAA,GAA2B,EAAA;AAAA,IACvC;AAAA,GACF,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AACX,EAAA,uBACE,GAAA,CAAC,kBAAkB,QAAA,EAAlB,EAA2B,OAAO,MAAA,EACjC,QAAA,kBAAA,GAAA,CAAC,kBAAA,EAAA,EAAmB,KAAA,EAAO,UAAA,EACzB,QAAA,kBAAA,GAAA;AAAA,IAAC,OAAA,CAAQ,IAAA;AAAA,IAAR;AAAA,MACC,KAAA,EAAM,UAAA;AAAA,MACN,EAAA,EAAI,WAAW,EAAE,CAAA,CAAA;AAAA,MACjB,UAAA;AAAA,MACA,YAAA,EAAc,EAAE,IAAA,EAAM,QAAA,EAAU,IAAI,QAAA,EAAS;AAAA,MAE7C,QAAA,kBAAA,IAAA;AAAA,QAAC,OAAA,CAAQ,OAAA;AAAA,QAAR;AAAA,UACC,mBAAA,EAAkB,MAAA;AAAA,UAClB,SAAA,EAAW,OAAA;AAAA,UACX,YAAA,EAAY,IAAA;AAAA,UACZ,QAAA,EAAU,CAAC,KAAA,KAAU;AACnB,YAAA,IAAI,OAAO,OAAA,EAAS;AAClB,cAAA,KAAA,CAAM,cAAA,EAAe;AACrB,cAAA,MAAA,CAAO,OAAA,EAAQ;AAAA,YACjB;AAAA,UACF,CAAA;AAAA,UAEA,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,QAAA,EAAA,EAAO,WAAU,oBAAA,EAChB,QAAA,kBAAA,GAAA;AAAA,cAAC,OAAA,CAAQ,KAAA;AAAA,cAAR;AAAA,gBACC,SAAA,EAAU,yBAAA;AAAA,gBACV,YAAA,EAAW,eAAA;AAAA,gBACZ,QAAA,EAAA;AAAA;AAAA,aAED,EACF,CAAA;AAAA,YACC;AAAA;AAAA;AAAA;AACH;AAAA,KAEJ,CAAA,EACF,CAAA;AAEJ","file":"chunk-VIAJ27YC.js","sourcesContent":["\"use client\";\nimport { Overlay } from \"@zappie/foundations\";\nimport { createContext, useRef, type ReactNode, type RefObject } from \"react\";\nimport { ThemeClassProvider } from \"../cart/theme-class\";\nexport const ItemEscapeContext = createContext<RefObject<\n (() => void) | undefined\n> | null>(null);\n/** The eager modal frame stays mounted while the configurator chunk loads. */\nexport function ItemFrame({\n id,\n name,\n hasImages,\n navigation,\n themeClass,\n children,\n}: {\n id: string;\n name: string;\n hasImages?: boolean;\n themeClass?: string | undefined;\n children: ReactNode;\n navigation: { isOpen: boolean; open(): void; close(): void };\n}) {\n const escape = useRef<(() => void) | undefined>(undefined);\n const classes = [\n \"z-base-cart z-base-item\",\n hasImages ? \"z-base-item-with-media\" : \"\",\n themeClass,\n ]\n .filter(Boolean)\n .join(\" \");\n return (\n <ItemEscapeContext.Provider value={escape}>\n <ThemeClassProvider value={themeClass}>\n <Overlay.Root\n param=\"modal_id\"\n id={`product_${id}`}\n navigation={navigation}\n presentation={{ base: \"drawer\", lg: \"dialog\" }}\n >\n <Overlay.Content\n data-zappie-theme=\"base\"\n className={classes}\n aria-label={name}\n onEscape={(event) => {\n if (escape.current) {\n event.preventDefault();\n escape.current();\n }\n }}\n >\n <header className=\"z-base-item-header\">\n <Overlay.Close\n className=\"z-base-button-secondary\"\n aria-label=\"Close product\"\n >\n ✕\n </Overlay.Close>\n </header>\n {children}\n </Overlay.Content>\n </Overlay.Root>\n </ThemeClassProvider>\n </ItemEscapeContext.Provider>\n );\n}\n"]}
@@ -0,0 +1,100 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { Money, OpeningTime, CartFulfilment } from '@zappie/sdk';
3
+ import { ReactNode } from 'react';
4
+ export { AddressSuggestion } from './address.js';
5
+ import '@zappie/sdk/places';
6
+
7
+ type HostPromo = {
8
+ id: string;
9
+ name: string;
10
+ description: string;
11
+ code: string;
12
+ disabled: boolean;
13
+ endsAt?: string;
14
+ };
15
+ type HostReward = {
16
+ id: string;
17
+ name: string;
18
+ description: string;
19
+ pointsCost: number;
20
+ disabled: boolean;
21
+ reward: string;
22
+ };
23
+ type HostAppliedReward = {
24
+ redemptionId: string;
25
+ perkId: string;
26
+ name: string;
27
+ pointsSpent: number;
28
+ };
29
+ /** Temporary Stage A integration. Themes never import host stores or payment implementations. */
30
+ type BaseHostBridge = {
31
+ /**
32
+ * Host-optimised, responsive URLs for a merchant image at the given
33
+ * `sizes`. Absent, themes load the original URL.
34
+ */
35
+ imageProps?(src: string, sizes: string): {
36
+ src: string;
37
+ srcSet?: string;
38
+ sizes?: string;
39
+ };
40
+ /**
41
+ * Recoverable host synchronization or checkout failure for the cart screen.
42
+ * Host checkout failures are reported here, so callers don't show them again.
43
+ */
44
+ error?: string | null;
45
+ /** Host-owned mode capabilities during Stage A. */
46
+ fulfilmentMode?: "delivery" | "pickup";
47
+ scheduleMaxDays?: number;
48
+ /** Delivery regions, when the branch prices delivery by region (else absent). */
49
+ deliveryRegions?: {
50
+ id: string;
51
+ name: string;
52
+ fee: Money;
53
+ }[];
54
+ deliveryRegionId?: string;
55
+ setDeliveryRegion?(id: string): void;
56
+ /**
57
+ * Details the business requires before payment (absent when it requires
58
+ * none). Values start from the customer's profile; the host saves them to
59
+ * the profile when the order is confirmed.
60
+ */
61
+ customerDetails?: {
62
+ requiresEmail: boolean;
63
+ values: CustomerDetailsValues;
64
+ update(field: keyof CustomerDetailsValues, value: string): void;
65
+ };
66
+ /** Opening hours the host accepts scheduled orders in (may start later than the branch's). */
67
+ scheduleOpeningTimes?: OpeningTime[];
68
+ saveFulfilment?: (value: CartFulfilment) => void;
69
+ availablePromos?: HostPromo[];
70
+ rewards?: {
71
+ balance: number;
72
+ items: HostReward[];
73
+ applied: HostAppliedReward[];
74
+ busyPerkId?: string;
75
+ redeem(perkId: string): Promise<void>;
76
+ cancel(redemptionId: string): Promise<void>;
77
+ };
78
+ deliveryDistance?: {
79
+ status: "unknown" | "far" | "too_far";
80
+ message?: string;
81
+ };
82
+ /**
83
+ * Switches the host between delivery and pickup. The host keeps a basket per
84
+ * mode, so the cart remounts against the other basket; returns false when the
85
+ * branch or menu does not allow the switch.
86
+ */
87
+ setFulfilmentMode(mode: "delivery" | "pickup"): boolean;
88
+ };
89
+ type CustomerDetailsValues = {
90
+ firstName: string;
91
+ lastName: string;
92
+ email: string;
93
+ };
94
+ declare function BaseHostBridgeProvider({ bridge, children, }: {
95
+ bridge: BaseHostBridge;
96
+ children: ReactNode;
97
+ }): react_jsx_runtime.JSX.Element;
98
+ declare function useBaseHostBridge(): BaseHostBridge;
99
+
100
+ export { type BaseHostBridge, BaseHostBridgeProvider, type CustomerDetailsValues, type HostAppliedReward, type HostPromo, type HostReward, useBaseHostBridge };
@@ -0,0 +1,4 @@
1
+ "use client";
2
+ export { BaseHostBridgeProvider, useBaseHostBridge } from './chunk-QWST2TA2.js';
3
+ //# sourceMappingURL=host-bridge.js.map
4
+ //# sourceMappingURL=host-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"host-bridge.js"}
@@ -0,0 +1,3 @@
1
+ declare const BASE_THEME_ID = "base-next";
2
+
3
+ export { BASE_THEME_ID };
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // src/index.ts
2
+ var BASE_THEME_ID = "base-next";
3
+
4
+ export { BASE_THEME_ID };
5
+ //# sourceMappingURL=index.js.map
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";AAAO,IAAM,aAAA,GAAgB","file":"index.js","sourcesContent":["export const BASE_THEME_ID = \"base-next\";\n"]}
@@ -0,0 +1,20 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as react from 'react';
3
+ import { RefObject, ReactNode } from 'react';
4
+
5
+ declare const ItemEscapeContext: react.Context<RefObject<(() => void) | undefined> | null>;
6
+ /** The eager modal frame stays mounted while the configurator chunk loads. */
7
+ declare function ItemFrame({ id, name, hasImages, navigation, themeClass, children, }: {
8
+ id: string;
9
+ name: string;
10
+ hasImages?: boolean;
11
+ themeClass?: string | undefined;
12
+ children: ReactNode;
13
+ navigation: {
14
+ isOpen: boolean;
15
+ open(): void;
16
+ close(): void;
17
+ };
18
+ }): react_jsx_runtime.JSX.Element;
19
+
20
+ export { ItemEscapeContext, ItemFrame };
@@ -0,0 +1,5 @@
1
+ "use client";
2
+ export { ItemEscapeContext, ItemFrame } from './chunk-VIAJ27YC.js';
3
+ import './chunk-JFEI2OUZ.js';
4
+ //# sourceMappingURL=item-frame.js.map
5
+ //# sourceMappingURL=item-frame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"item-frame.js"}
package/dist/item.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { Item } from '@zappie/sdk';
3
+
4
+ type ItemDetailProps = {
5
+ item: Item;
6
+ menuId: string;
7
+ scope: string;
8
+ href: string;
9
+ themeClass?: string;
10
+ navigation: {
11
+ isOpen: boolean;
12
+ open(): void;
13
+ close(): void;
14
+ };
15
+ };
16
+ /** Framework-independent SDK item screen, reusable through themeClass. */
17
+ declare function ItemDetail(props: ItemDetailProps): react_jsx_runtime.JSX.Element;
18
+ declare function ItemContent({ item, menuId, scope, href, navigation, }: ItemDetailProps): react_jsx_runtime.JSX.Element;
19
+
20
+ export { ItemContent, ItemDetail, type ItemDetailProps };