bitsnap-react 1.14.1 → 1.16.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 (144) hide show
  1. package/AGENTS.md +3 -0
  2. package/README.md +76 -2
  3. package/dist/CartProvider-VGZMDVFJ.js +2 -0
  4. package/dist/CartProvider-VGZMDVFJ.js.map +1 -0
  5. package/dist/CartProvider-ZY5OLTAF.mjs +2 -0
  6. package/dist/PanelModelFiles-NYCOFPLY.js +2 -0
  7. package/dist/PanelModelFiles-NYCOFPLY.js.map +1 -0
  8. package/dist/PanelModelFiles-RV7OHUUZ.mjs +2 -0
  9. package/dist/PanelModelFiles-RV7OHUUZ.mjs.map +1 -0
  10. package/dist/Viewer3D-2IDEH6W3.mjs +2 -0
  11. package/dist/Viewer3D-2IDEH6W3.mjs.map +1 -0
  12. package/dist/analytics.js +1 -1
  13. package/dist/analytics.js.map +1 -1
  14. package/dist/analytics.mjs +1 -1
  15. package/dist/catalog.d.mts +5 -1
  16. package/dist/catalog.d.ts +5 -1
  17. package/dist/catalog.js +1 -1
  18. package/dist/catalog.js.map +1 -1
  19. package/dist/catalog.mjs +1 -1
  20. package/dist/chunk-5AYH23UJ.mjs +4 -0
  21. package/dist/chunk-5AYH23UJ.mjs.map +1 -0
  22. package/dist/chunk-5ED7FWNY.mjs +2 -0
  23. package/dist/chunk-5ED7FWNY.mjs.map +1 -0
  24. package/dist/chunk-5R6AGO3Z.mjs +2 -0
  25. package/dist/chunk-5R6AGO3Z.mjs.map +1 -0
  26. package/dist/chunk-6Q3VGPSF.js +2 -0
  27. package/dist/chunk-6Q3VGPSF.js.map +1 -0
  28. package/dist/chunk-6YIRRDCL.mjs +2 -0
  29. package/dist/chunk-6YIRRDCL.mjs.map +1 -0
  30. package/dist/chunk-7RXW6XFY.js +2 -0
  31. package/dist/chunk-7RXW6XFY.js.map +1 -0
  32. package/dist/chunk-AGYS7Z6G.mjs +2 -0
  33. package/dist/{chunk-L7LZG6MR.mjs.map → chunk-AGYS7Z6G.mjs.map} +1 -1
  34. package/dist/chunk-CUPG4B5W.mjs +2 -0
  35. package/dist/chunk-CUPG4B5W.mjs.map +1 -0
  36. package/dist/chunk-DPKWYLN7.mjs +2 -0
  37. package/dist/chunk-DPKWYLN7.mjs.map +1 -0
  38. package/dist/{chunk-PVJ2I46C.js → chunk-GQJDFLSL.js} +2 -2
  39. package/dist/chunk-GQJDFLSL.js.map +1 -0
  40. package/dist/chunk-GXUNRJ5S.js +2 -0
  41. package/dist/chunk-GXUNRJ5S.js.map +1 -0
  42. package/dist/chunk-I3QXJJ7U.mjs +2 -0
  43. package/dist/{chunk-ONTCJSSD.mjs.map → chunk-I3QXJJ7U.mjs.map} +1 -1
  44. package/dist/chunk-JSDGZ4NY.js.map +1 -1
  45. package/dist/chunk-KOYBZORL.js.map +1 -1
  46. package/dist/{chunk-KKOIDDOW.js → chunk-LL7ASBGY.js} +2 -2
  47. package/dist/chunk-LL7ASBGY.js.map +1 -0
  48. package/dist/chunk-OZHXRKMX.js +2 -0
  49. package/dist/chunk-OZHXRKMX.js.map +1 -0
  50. package/dist/chunk-QERYM7RC.js +2 -0
  51. package/dist/chunk-QERYM7RC.js.map +1 -0
  52. package/dist/{chunk-JZBU5SZJ.mjs → chunk-QQQ2JSPQ.mjs} +2 -2
  53. package/dist/{chunk-JZBU5SZJ.mjs.map → chunk-QQQ2JSPQ.mjs.map} +1 -1
  54. package/dist/chunk-QXGK337V.mjs +2 -0
  55. package/dist/{chunk-4TZAGNEU.mjs.map → chunk-QXGK337V.mjs.map} +1 -1
  56. package/dist/{chunk-5DBLZ3VL.js → chunk-SRQOFCMO.js} +2 -2
  57. package/dist/chunk-SRQOFCMO.js.map +1 -0
  58. package/dist/chunk-SULHGFYN.mjs +2 -0
  59. package/dist/chunk-SULHGFYN.mjs.map +1 -0
  60. package/dist/chunk-SXKJ26OA.mjs +2 -0
  61. package/dist/chunk-SXKJ26OA.mjs.map +1 -0
  62. package/dist/chunk-VNYHJT6V.mjs +2 -0
  63. package/dist/chunk-VNYHJT6V.mjs.map +1 -0
  64. package/dist/chunk-W3RGQYPD.js.map +1 -1
  65. package/dist/chunk-WKE6ECID.mjs +2 -0
  66. package/dist/chunk-WKE6ECID.mjs.map +1 -0
  67. package/dist/{chunk-QQDZIVWY.js → chunk-WPOXLITY.js} +2 -2
  68. package/dist/chunk-WPOXLITY.js.map +1 -0
  69. package/dist/chunk-Y5KWVTXT.js +4 -0
  70. package/dist/chunk-Y5KWVTXT.js.map +1 -0
  71. package/dist/consent.js +14 -7
  72. package/dist/consent.js.map +1 -1
  73. package/dist/consent.mjs +14 -7
  74. package/dist/consent.mjs.map +1 -1
  75. package/dist/course.js +1 -1
  76. package/dist/course.js.map +1 -1
  77. package/dist/course.mjs +1 -1
  78. package/dist/course.mjs.map +1 -1
  79. package/dist/embed/analytics.js +1 -1
  80. package/dist/embed/consent.js +14 -7
  81. package/dist/errors.js.map +1 -1
  82. package/dist/index.css +1 -1
  83. package/dist/index.css.map +1 -1
  84. package/dist/index.js +1 -1
  85. package/dist/index.js.map +1 -1
  86. package/dist/index.mjs +1 -1
  87. package/dist/index.mjs.map +1 -1
  88. package/dist/internal.js.map +1 -1
  89. package/dist/methods-NJEP64AG.mjs +2 -0
  90. package/dist/methods-WRONKK3D.js +2 -0
  91. package/dist/methods-WRONKK3D.js.map +1 -0
  92. package/dist/model-files-client-HHDXJDTS.mjs +2 -0
  93. package/dist/model-files-client-HHDXJDTS.mjs.map +1 -0
  94. package/dist/model-files-client-P4PORZJ6.js +2 -0
  95. package/dist/model-files-client-P4PORZJ6.js.map +1 -0
  96. package/dist/models.d.mts +2 -0
  97. package/dist/models.d.ts +2 -0
  98. package/dist/models.js +1 -1
  99. package/dist/models.js.map +1 -1
  100. package/dist/models.mjs +1 -1
  101. package/dist/models.mjs.map +1 -1
  102. package/dist/returns.js +1 -1
  103. package/dist/returns.js.map +1 -1
  104. package/dist/returns.mjs +1 -1
  105. package/dist/viewer3d.css +2 -0
  106. package/dist/viewer3d.css.map +1 -0
  107. package/dist/viewer3d.d.mts +318 -0
  108. package/dist/viewer3d.d.ts +318 -0
  109. package/dist/viewer3d.js +2 -0
  110. package/dist/viewer3d.js.map +1 -0
  111. package/dist/viewer3d.mjs +63 -0
  112. package/dist/viewer3d.mjs.map +1 -0
  113. package/package.json +30 -3
  114. package/dist/CartProvider-2RNAKU3U.js +0 -2
  115. package/dist/CartProvider-2RNAKU3U.js.map +0 -1
  116. package/dist/CartProvider-OSGG573S.mjs +0 -2
  117. package/dist/chunk-2OOQPXCQ.js +0 -4
  118. package/dist/chunk-2OOQPXCQ.js.map +0 -1
  119. package/dist/chunk-4MU2YAQT.js +0 -2
  120. package/dist/chunk-4MU2YAQT.js.map +0 -1
  121. package/dist/chunk-4TZAGNEU.mjs +0 -2
  122. package/dist/chunk-5DBLZ3VL.js.map +0 -1
  123. package/dist/chunk-7WJSK6SJ.mjs +0 -4
  124. package/dist/chunk-7WJSK6SJ.mjs.map +0 -1
  125. package/dist/chunk-EJRI366W.js +0 -2
  126. package/dist/chunk-EJRI366W.js.map +0 -1
  127. package/dist/chunk-FIWADPQX.mjs +0 -2
  128. package/dist/chunk-FIWADPQX.mjs.map +0 -1
  129. package/dist/chunk-GTOZ5BZX.js +0 -2
  130. package/dist/chunk-GTOZ5BZX.js.map +0 -1
  131. package/dist/chunk-KKOIDDOW.js.map +0 -1
  132. package/dist/chunk-L7LZG6MR.mjs +0 -2
  133. package/dist/chunk-ONTCJSSD.mjs +0 -2
  134. package/dist/chunk-PVJ2I46C.js.map +0 -1
  135. package/dist/chunk-QQDZIVWY.js.map +0 -1
  136. package/dist/chunk-TBYY3RL2.mjs +0 -2
  137. package/dist/chunk-TBYY3RL2.mjs.map +0 -1
  138. package/dist/chunk-WJGC6EHC.mjs +0 -2
  139. package/dist/chunk-WJGC6EHC.mjs.map +0 -1
  140. package/dist/methods-4WVTFI3Q.mjs +0 -2
  141. package/dist/methods-W5JTLIIX.js +0 -2
  142. package/dist/methods-W5JTLIIX.js.map +0 -1
  143. /package/dist/{CartProvider-OSGG573S.mjs.map → CartProvider-ZY5OLTAF.mjs.map} +0 -0
  144. /package/dist/{methods-4WVTFI3Q.mjs.map → methods-NJEP64AG.mjs.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/viewer3d/Product3DViewer.tsx","../src/viewer3d/copy.ts","../src/viewer3d/Model3DShell.tsx","../src/viewer3d/facts.ts","../src/viewer3d/fullscreen.ts","../src/viewer3d/gesture-hint.ts","../src/viewer3d/shell.machine.ts","../src/viewer3d/styles.ts","../src/viewer3d/useProduct3DModel.ts","../src/viewer3d/model.ts"],"sourcesContent":["import { useState, type ReactNode } from \"react\";\n\nimport { addProductToCart } from \"../components/products/add-to-cart\";\nimport { formatProductPrice } from \"../components/products/format\";\nimport { HOST } from \"../components/checkout/constants\";\nimport { getPanelConfig } from \"../panel/config\";\nimport { viewer3DCopy, type Viewer3DCopy } from \"./copy\";\nimport type { Product3DProduct, Product3DVariant } from \"./model\";\nimport { Model3DViewer, type Model3DViewerProps } from \"./Model3DShell\";\nimport {\n useProduct3DModel,\n type UseProduct3DModelOptions,\n type UseProduct3DModelResult,\n} from \"./useProduct3DModel\";\n\nexport type Product3DBuyBarArgs = {\n product: Product3DProduct;\n variant?: Product3DVariant;\n /** Leaves full screen (e.g. before the page shows its own error or dialog). */\n close: () => void;\n};\n\nexport type Product3DViewerProps = UseProduct3DModelOptions &\n Omit<\n Model3DViewerProps,\n \"model\" | \"productName\" | \"renderFullscreenBar\" | \"loadViewer\"\n > & {\n /** Bitsnap product ID (`prodv2_…`), or a variant ID. */\n productId: string;\n /** The variant the page shows; switching it swaps the model in place. */\n variantId?: string;\n /**\n * The bar of the full screen view. Default: name, price and an\n * \"Add to cart\" button that uses the Bitsnap cart (loaded on the first\n * click). Return `null` for no bar.\n */\n renderBuyBar?: (args: Product3DBuyBarArgs) => ReactNode;\n /** Rendered while loading, when there is no model, and on error. Default: nothing. */\n fallback?: ReactNode;\n /** Product page URL stored with the cart item (default buy bar). */\n productUrl?: string;\n /** Called after the default buy bar added the product. */\n onAddedToCart?: (args: { product: Product3DProduct; variant?: Product3DVariant }) => void;\n /** @internal Tests replace the three viewer. */\n loadViewer?: Model3DViewerProps[\"loadViewer\"];\n };\n\n/**\n * The 3D viewer of a Bitsnap product: loads the product's public model and\n * shows it (auto-rotate, click-to-load over 10 MB, reduced motion, full screen\n * with a buy bar, gesture hint). Renders `fallback` (nothing by default) when\n * the product has no ready model or the server has no 3D support.\n *\n * Needs the optional peer dependencies `three`, `@react-three/fiber` and\n * `@react-three/drei`; they load only once the model may be shown.\n */\nexport function Product3DViewer({\n productId,\n variantId,\n projectID,\n host,\n locale,\n renderBuyBar,\n fallback = null,\n productUrl,\n onAddedToCart,\n ...viewer\n}: Product3DViewerProps) {\n const result = useProduct3DModel(productId, variantId, {\n projectID,\n host,\n locale,\n });\n if (result.status !== \"ready\" || result.model == null || result.product == null) {\n return <>{fallback}</>;\n }\n const product = result.product;\n const copy = viewer3DCopy(locale, viewer.texts);\n return (\n <Model3DViewer\n {...viewer}\n locale={locale}\n model={result.model}\n productName={result.variant?.name ? `${product.name} – ${result.variant.name}` : product.name}\n renderFullscreenBar={({ close }) =>\n renderBuyBar != null\n ? renderBuyBar({ product, variant: result.variant, close })\n : (\n <DefaultBuyBar\n product={product}\n variant={result.variant}\n copy={copy}\n locale={locale}\n projectID={projectID ?? getPanelConfig().projectID}\n host={host}\n productUrl={productUrl}\n onAdded={onAddedToCart}\n />\n )\n }\n />\n );\n}\n\n/** Whether the default bar may add the item straight to the cart. */\nexport function isCartable(\n product: Product3DProduct,\n variant: Product3DVariant | undefined,\n): boolean {\n if (product.recurring != null) return false;\n const priceType = variant?.priceType ?? product.priceType;\n if (priceType != null && priceType !== \"one_time\") return false;\n const quantity = variant?.availableQuantity ?? product.availableQuantity;\n return quantity == null || quantity > 0;\n}\n\n/** The cart id: the chosen variant, else the first (default) variant, else the product. */\nexport function cartItemIdFor(\n product: Product3DProduct,\n variant: Product3DVariant | undefined,\n): string {\n return variant?.id ?? product.variants?.[0]?.id ?? product.id;\n}\n\nfunction DefaultBuyBar({\n product,\n variant,\n copy,\n locale,\n projectID,\n host,\n productUrl,\n onAdded,\n}: {\n product: Product3DProduct;\n variant?: Product3DVariant;\n copy: Viewer3DCopy;\n locale?: string;\n projectID?: string;\n host?: string;\n productUrl?: string;\n onAdded?: Product3DViewerProps[\"onAddedToCart\"];\n}) {\n const [state, setState] = useState<\"idle\" | \"adding\" | \"added\" | \"error\">(\"idle\");\n const price = variant?.price ?? product.price;\n const currency = variant?.currency ?? product.currency;\n const canAdd = projectID != null && isCartable(product, variant);\n\n return (\n <div>\n <div className=\"bsv3d-buybar-row\">\n <div>\n <p className=\"bsv3d-buybar-name\">\n {product.name}\n {variant?.name ? ` – ${variant.name}` : \"\"}\n </p>\n <p className=\"bsv3d-buybar-price\">\n {formatProductPrice(price, currency, locale)}\n </p>\n </div>\n {canAdd && (\n <button\n type=\"button\"\n className=\"bsv3d-button\"\n data-viewer3d-add=\"\"\n disabled={state === \"adding\"}\n aria-live=\"polite\"\n onClick={async () => {\n setState(\"adding\");\n try {\n await addProductToCart(\n {\n id: product.id,\n cartItemId: cartItemIdFor(product, variant),\n name: variant?.name ? `${product.name} – ${variant.name}` : product.name,\n price,\n currency,\n },\n {\n projectID: projectID!,\n host: host ?? HOST,\n showCart: false,\n url:\n productUrl ??\n (typeof window !== \"undefined\" ? window.location.href : undefined),\n },\n );\n setState(\"added\");\n onAdded?.({ product, variant });\n } catch {\n setState(\"error\");\n }\n }}\n >\n {state === \"adding\"\n ? copy.addingToCart\n : state === \"added\"\n ? copy.addedToCart\n : copy.addToCart}\n </button>\n )}\n </div>\n {state === \"error\" && (\n <p className=\"bsv3d-buybar-error\" role=\"alert\">\n {copy.addToCartError}\n </p>\n )}\n </div>\n );\n}\n\nexport type { UseProduct3DModelResult };\n","import type { Model3DUnit } from \"./types\";\n\n/**\n * Every string of the 3D viewer. Polish is the default, English for `en*`\n * locales; pass `texts` to `Product3DViewer` to override any of them.\n */\nexport type Viewer3DCopy = {\n sectionLabel: string;\n show: (size: string) => string;\n heroPill: string;\n heroPillWithSize: (size: string) => string;\n loading: string;\n loadingProgress: (percent: number) => string;\n error: string;\n retry: string;\n unsupported: string;\n hintDrag: string;\n hintTap: string;\n touchDone: string;\n reset: string;\n fullscreen: string;\n closeFullscreen: string;\n disclaimer: string;\n report: string;\n factsTitle: string;\n factsFormat: string;\n factsFileSize: string;\n factsTriangles: string;\n factsDimensions: string;\n triangles: (count: string) => string;\n licence: string;\n licenceShow: string;\n licenceOpen: string;\n licenceClose: string;\n licenceDefaultName: string;\n units: Record<Model3DUnit, string>;\n /** Fullscreen bar: add to the cart. */\n addToCart: string;\n addingToCart: string;\n addedToCart: string;\n addToCartError: string;\n};\n\nexport const VIEWER3D_COPY_PL: Viewer3DCopy = {\n sectionLabel: \"Model 3D\",\n show: (size) => `Pokaż model 3D (${size})`,\n heroPill: \"Zobacz w 3D\",\n heroPillWithSize: (size) => `Zobacz w 3D (${size})`,\n loading: \"Wczytywanie modelu 3D…\",\n loadingProgress: (percent) => `Wczytywanie modelu 3D: ${percent}%`,\n error: \"Nie udało się wczytać modelu 3D\",\n retry: \"Spróbuj ponownie\",\n unsupported: \"Ta przeglądarka nie wyświetli modelu 3D.\",\n hintDrag: \"Przeciągnij, aby obrócić\",\n hintTap: \"Dotknij, aby obracać\",\n touchDone: \"Gotowe\",\n reset: \"Reset widoku\",\n fullscreen: \"Pełny ekran\",\n closeFullscreen: \"Zamknij pełny ekran\",\n disclaimer:\n \"Model 3D jest poglądowy; kolory i detale mogą się różnić od produktu.\",\n report: \"Zgłoś ten model\",\n factsTitle: \"Szczegóły modelu\",\n factsFormat: \"Format\",\n factsFileSize: \"Rozmiar pliku\",\n factsTriangles: \"Trójkąty\",\n factsDimensions: \"Wymiary\",\n triangles: (count) => count,\n licence: \"Licencja\",\n licenceShow: \"Warunki licencji\",\n licenceOpen: \"Otwórz licencję\",\n licenceClose: \"Zamknij\",\n licenceDefaultName: \"Licencja sprzedawcy\",\n units: { meters: \"m\", centimeters: \"cm\", millimeters: \"mm\", inches: \"in\" },\n addToCart: \"Dodaj do koszyka\",\n addingToCart: \"Dodawanie…\",\n addedToCart: \"Dodano do koszyka\",\n addToCartError: \"Nie udało się dodać do koszyka. Spróbuj ponownie.\",\n};\n\nexport const VIEWER3D_COPY_EN: Viewer3DCopy = {\n sectionLabel: \"3D model\",\n show: (size) => `Show 3D model (${size})`,\n heroPill: \"View in 3D\",\n heroPillWithSize: (size) => `View in 3D (${size})`,\n loading: \"Loading the 3D model…\",\n loadingProgress: (percent) => `Loading the 3D model: ${percent}%`,\n error: \"The 3D model could not be loaded\",\n retry: \"Try again\",\n unsupported: \"This browser cannot show the 3D model.\",\n hintDrag: \"Drag to rotate\",\n hintTap: \"Tap to rotate\",\n touchDone: \"Done\",\n reset: \"Reset view\",\n fullscreen: \"Full screen\",\n closeFullscreen: \"Close full screen\",\n disclaimer:\n \"The 3D model is illustrative; colours and details may differ from the product.\",\n report: \"Report this model\",\n factsTitle: \"Model details\",\n factsFormat: \"Format\",\n factsFileSize: \"File size\",\n factsTriangles: \"Triangles\",\n factsDimensions: \"Dimensions\",\n triangles: (count) => count,\n licence: \"Licence\",\n licenceShow: \"Licence terms\",\n licenceOpen: \"Open the licence\",\n licenceClose: \"Close\",\n licenceDefaultName: \"Seller's licence\",\n units: { meters: \"m\", centimeters: \"cm\", millimeters: \"mm\", inches: \"in\" },\n addToCart: \"Add to cart\",\n addingToCart: \"Adding…\",\n addedToCart: \"Added to cart\",\n addToCartError: \"Could not add to the cart. Try again.\",\n};\n\nexport function viewer3DCopy(\n locale?: string,\n overrides?: Partial<Viewer3DCopy>,\n): Viewer3DCopy {\n const base = locale?.toLowerCase().startsWith(\"en\")\n ? VIEWER3D_COPY_EN\n : VIEWER3D_COPY_PL;\n return overrides ? { ...base, ...overrides } : base;\n}\n\nexport function numberLocale(locale?: string): string {\n return locale?.toLowerCase().startsWith(\"en\") ? \"en-GB\" : \"pl-PL\";\n}\n","import { Box, Hand, Maximize2, Rotate3d, RotateCcw, X } from \"lucide-react\";\nimport {\n useCallback,\n useEffect,\n useId,\n useReducer,\n useRef,\n useState,\n type ComponentType,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { formatModelSize, GESTURE_HINT_MS } from \"./constants\";\nimport { numberLocale, viewer3DCopy, type Viewer3DCopy } from \"./copy\";\nimport { modelFactRows } from \"./facts\";\nimport { useViewerFullscreen } from \"./fullscreen\";\nimport { hasSeenGestureHint, markGestureHintSeen } from \"./gesture-hint\";\nimport {\n initialShellState,\n isViewerMounted,\n shellReducer,\n type ShellModel,\n} from \"./shell.machine\";\nimport { VIEWER3D_CSS, VIEWER3D_STYLE_HREF } from \"./styles\";\nimport type { Model3DView } from \"./types\";\nimport type { Viewer3DProps } from \"./Viewer3D\";\n\n/** Theme of the viewer; each value sets one `--bitsnap-viewer3d-*` property. */\nexport type Viewer3DAppearance = {\n background?: string;\n foreground?: string;\n muted?: string;\n border?: string;\n accent?: string;\n radius?: string;\n};\n\nexport type Model3DViewerProps = {\n model: Model3DView;\n /** The product name: the alt text of the poster. */\n productName: string;\n /** `pl-PL` (default) or an `en*` locale. */\n locale?: string;\n /** Overrides of any viewer string. */\n texts?: Partial<Viewer3DCopy>;\n appearance?: Viewer3DAppearance;\n /**\n * Draco decoder folder (trailing slash). Default: three's decoder files on\n * jsDelivr for the installed `three` revision.\n */\n decoderPath?: string;\n /**\n * \"Report this model\" link (DSA notice form); the viewer adds the page URL\n * as `url`. Absent = no link.\n */\n reportHref?: string;\n /** Bump to start loading now, whatever the size (e.g. from a \"View in 3D\" button). */\n startSignal?: number;\n /**\n * The bar at the bottom of the full screen view (name, price, buy button).\n * `close` leaves full screen. Absent = no bar.\n */\n renderFullscreenBar?: (args: { close: () => void }) => ReactNode;\n /** Hide the notes under the viewer (disclaimer, report link, model facts). */\n hideNotes?: boolean;\n id?: string;\n className?: string;\n style?: CSSProperties;\n /** @internal Tests replace the three viewer. */\n loadViewer?: () => Promise<{ default: ComponentType<Viewer3DProps> }>;\n};\n\nconst loadDefaultViewer = () => import(\"./Viewer3D\");\n\nfunction appearanceStyle(appearance?: Viewer3DAppearance): CSSProperties {\n const style: Record<string, string> = {};\n if (appearance == null) return style;\n for (const [key, value] of Object.entries(appearance)) {\n if (value) style[`--bitsnap-viewer3d-${key}`] = value;\n }\n return style as CSSProperties;\n}\n\nfunction hasWebGL(): boolean {\n try {\n const canvas = document.createElement(\"canvas\");\n return (canvas.getContext(\"webgl2\") ?? canvas.getContext(\"webgl\")) != null;\n } catch {\n return false;\n }\n}\n\nfunction useMediaQuery(query: string): boolean {\n const [matches, setMatches] = useState(false);\n useEffect(() => {\n if (typeof window.matchMedia !== \"function\") return;\n const media = window.matchMedia(query);\n const update = () => setMatches(media.matches);\n update();\n media.addEventListener?.(\"change\", update);\n return () => media.removeEventListener?.(\"change\", update);\n }, [query]);\n return matches;\n}\n\nfunction usePageVisible(): boolean {\n const [visible, setVisible] = useState(true);\n useEffect(() => {\n const update = () => setVisible(document.visibilityState !== \"hidden\");\n update();\n document.addEventListener(\"visibilitychange\", update);\n return () => document.removeEventListener(\"visibilitychange\", update);\n }, []);\n return visible;\n}\n\n/**\n * The 3D viewer of one model, without data fetching (see `Product3DViewer`\n * for the product-id version). No three import: the poster, the states and\n * the controls live here; `Viewer3D` is loaded with `import()` in an effect\n * once the model may load, so the server render and the page's main chunk\n * never touch three.\n */\nexport function Model3DViewer({\n model,\n productName,\n locale,\n texts,\n appearance,\n decoderPath,\n reportHref,\n startSignal,\n renderFullscreenBar,\n hideNotes,\n id,\n className,\n style,\n loadViewer = loadDefaultViewer,\n}: Model3DViewerProps) {\n const copy = viewer3DCopy(locale, texts);\n const shellModel: ShellModel = {\n key: model.previewUrl,\n size: model.previewSize,\n };\n const [state, dispatch] = useReducer(\n shellReducer,\n shellModel,\n initialShellState,\n );\n const [Viewer, setViewer] = useState<ComponentType<Viewer3DProps> | null>(\n null,\n );\n const frameRef = useRef<HTMLDivElement>(null);\n const stageRef = useRef<HTMLDivElement>(null);\n const [near, setNear] = useState(false);\n const [onScreen, setOnScreen] = useState(false);\n const pageVisible = usePageVisible();\n const reducedMotion = useMediaQuery(\"(prefers-reduced-motion: reduce)\");\n const coarsePointer = useMediaQuery(\"(pointer: coarse)\");\n const [touchActive, setTouchActive] = useState(false);\n const [hint, setHint] = useState(false);\n const [resetSignal, setResetSignal] = useState(0);\n const fullscreen = useViewerFullscreen(frameRef);\n const titleID = useId();\n const themeStyle = appearanceStyle(appearance);\n\n // WebGL is checked once, in the browser.\n useEffect(() => {\n if (!hasWebGL()) dispatch({ type: \"NO_WEBGL\" });\n }, []);\n\n // Near the viewport → may load; on screen → may draw.\n useEffect(() => {\n const element = stageRef.current;\n if (element == null || typeof IntersectionObserver === \"undefined\") {\n setNear(true);\n setOnScreen(true);\n return;\n }\n const nearObserver = new IntersectionObserver(\n ([entry]) => setNear(entry?.isIntersecting ?? false),\n { rootMargin: \"200px 0px\" },\n );\n const screenObserver = new IntersectionObserver(\n ([entry]) => setOnScreen(entry?.isIntersecting ?? false),\n { threshold: 0.05 },\n );\n nearObserver.observe(element);\n screenObserver.observe(element);\n return () => {\n nearObserver.disconnect();\n screenObserver.disconnect();\n };\n }, []);\n\n useEffect(() => {\n if (near) dispatch({ type: \"VISIBLE\" });\n }, [near, state.status]);\n\n // Another variant: the size rule is checked again for its model.\n useEffect(() => {\n dispatch({ type: \"MODEL_CHANGED\", model: shellModel, visible: near });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [shellModel.key, shellModel.size]);\n\n // An outside \"View in 3D\" button: start now, a big model included.\n const firstStart = useRef(startSignal);\n useEffect(() => {\n if (startSignal == null || startSignal === firstStart.current) return;\n dispatch({ type: \"REQUEST\" });\n }, [startSignal]);\n\n // The viewer code, only once the model may load.\n const mounted = isViewerMounted(state.status);\n useEffect(() => {\n if (!mounted || Viewer != null) return;\n let cancelled = false;\n loadViewer().then(\n (module) => {\n if (!cancelled) setViewer(() => module.default);\n },\n (error) => {\n console.warn(\n \"[bitsnap-react/viewer3d] the viewer could not be loaded; are three, @react-three/fiber and @react-three/drei installed?\",\n error,\n );\n if (!cancelled) dispatch({ type: \"FAILED\", key: state.model.key });\n },\n );\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [mounted, Viewer, state.model.key, state.attempt]);\n\n // Gesture hint: once per browser, the first time the model is interactive.\n const ready = state.status === \"ready\";\n useEffect(() => {\n if (!ready || hasSeenGestureHint()) return;\n markGestureHintSeen();\n setHint(true);\n const timer = setTimeout(() => setHint(false), GESTURE_HINT_MS);\n return () => clearTimeout(timer);\n }, [ready]);\n\n // Phones: rotating needs a tap first; a tap elsewhere or scrolling away gives the page back.\n useEffect(() => {\n if (!touchActive) return;\n const onPointerDown = (event: PointerEvent) => {\n if (!frameRef.current?.contains(event.target as Node))\n setTouchActive(false);\n };\n document.addEventListener(\"pointerdown\", onPointerDown);\n return () => document.removeEventListener(\"pointerdown\", onPointerDown);\n }, [touchActive]);\n useEffect(() => {\n if (!onScreen && !fullscreen.isFullscreen) setTouchActive(false);\n }, [onScreen, fullscreen.isFullscreen]);\n\n const interactive = !coarsePointer || touchActive || fullscreen.isFullscreen;\n const onInteract = useCallback(() => setHint(false), []);\n\n const key = state.model.key;\n const onProgress = useCallback(\n (loaded: number, total: number) =>\n dispatch({ type: \"PROGRESS\", key, loaded, total }),\n [key],\n );\n const onLoaded = useCallback(() => dispatch({ type: \"LOADED\", key }), [key]);\n const onError = useCallback(\n (error: unknown) => {\n console.warn(\"[bitsnap-react/viewer3d] model failed\", error);\n dispatch({ type: \"FAILED\", key });\n },\n [key],\n );\n\n const sizeLabel = formatModelSize(model.previewSize, numberLocale(locale));\n const percent = Math.round(state.progress * 100);\n const isFullscreen = fullscreen.isFullscreen;\n const motionAllowed =\n !reducedMotion && pageVisible && (onScreen || isFullscreen);\n\n // The overlay (no element fullscreen, e.g. iPhone) goes to <body>, so no\n // transformed or contained ancestor traps the fixed element.\n const portal = (node: ReactNode) =>\n fullscreen.mode === \"overlay\" ? createPortal(node, document.body) : node;\n\n return (\n <section\n id={id}\n aria-labelledby={titleID}\n data-bitsnap-viewer3d=\"\"\n className={className}\n style={{ ...themeStyle, ...style }}\n >\n <style href={VIEWER3D_STYLE_HREF} precedence=\"default\">\n {VIEWER3D_CSS}\n </style>\n <h2 id={titleID} className=\"bsv3d-sr\">\n {copy.sectionLabel}\n </h2>\n {fullscreen.mode === \"overlay\" && (\n // Keeps the place of the frame while it is shown over the page.\n <div aria-hidden=\"true\" className=\"bsv3d-placeholder\" />\n )}\n {portal(\n <div\n ref={frameRef}\n data-viewer3d-frame=\"\"\n data-state={state.status}\n data-motion={motionAllowed ? \"on\" : \"off\"}\n data-fullscreen={isFullscreen ? \"\" : undefined}\n className=\"bsv3d-frame\"\n style={themeStyle}\n onClick={() => {\n if (ready && coarsePointer && !touchActive) {\n setTouchActive(true);\n setHint(false);\n }\n }}\n >\n <div ref={stageRef} className=\"bsv3d-stage\">\n {mounted && Viewer != null && (\n <Viewer\n key={`${state.model.key}#${state.attempt}`}\n className=\"bsv3d-canvas\"\n url={state.model.key}\n decoderPath={decoderPath}\n expectedSize={state.model.size}\n attempt={state.attempt}\n motionAllowed={motionAllowed}\n interactive={interactive}\n allowZoom={isFullscreen || (coarsePointer && touchActive)}\n resetSignal={resetSignal}\n onProgress={onProgress}\n onLoaded={onLoaded}\n onError={onError}\n onInteract={onInteract}\n />\n )}\n\n <Poster src={model.thumbnailUrl} alt={productName} hidden={ready} />\n\n {state.status === \"loading\" && (\n <div className=\"bsv3d-loading\">\n <span className=\"bsv3d-chip\" data-small=\"\" aria-hidden=\"true\">\n {percent > 0 ? copy.loadingProgress(percent) : copy.loading}\n </span>\n <div className=\"bsv3d-bar\">\n <div style={{ width: `${Math.max(percent, 3)}%` }} />\n </div>\n </div>\n )}\n\n {state.status === \"awaiting-click\" && (\n <div className=\"bsv3d-center\">\n <button\n type=\"button\"\n className=\"bsv3d-button\"\n data-viewer3d-show=\"\"\n onClick={(event) => {\n event.stopPropagation();\n dispatch({ type: \"REQUEST\" });\n }}\n >\n <Box aria-hidden=\"true\" />\n {copy.show(sizeLabel)}\n </button>\n </div>\n )}\n\n {state.status === \"error\" && (\n <div className=\"bsv3d-center\">\n <div role=\"alert\" className=\"bsv3d-alert\">\n <p>{copy.error}</p>\n <button\n type=\"button\"\n className=\"bsv3d-button\"\n data-viewer3d-retry=\"\"\n onClick={(event) => {\n event.stopPropagation();\n dispatch({ type: \"RETRY\" });\n }}\n >\n <RotateCcw aria-hidden=\"true\" />\n {copy.retry}\n </button>\n </div>\n </div>\n )}\n\n {state.status === \"unsupported\" && (\n <p className=\"bsv3d-chip bsv3d-unsupported\" data-small=\"\">\n {copy.unsupported}\n </p>\n )}\n\n {/* The gesture hint, once per browser. */}\n {ready && (\n <div\n aria-hidden={!hint}\n className=\"bsv3d-hint\"\n data-visible={hint ? \"\" : undefined}\n >\n <span className=\"bsv3d-chip\">\n {coarsePointer ? (\n <Hand aria-hidden=\"true\" />\n ) : (\n <Rotate3d aria-hidden=\"true\" />\n )}\n {coarsePointer && !isFullscreen\n ? copy.hintTap\n : copy.hintDrag}\n </span>\n </div>\n )}\n\n {ready && (\n <div className=\"bsv3d-controls\">\n <div>\n {coarsePointer &&\n !isFullscreen &&\n (touchActive ? (\n <button\n type=\"button\"\n className=\"bsv3d-icon\"\n data-wide=\"\"\n onClick={(event) => {\n event.stopPropagation();\n setTouchActive(false);\n }}\n >\n {copy.touchDone}\n </button>\n ) : (\n !hint && (\n <span className=\"bsv3d-chip\" data-small=\"\">\n <Hand aria-hidden=\"true\" />\n {copy.hintTap}\n </span>\n )\n ))}\n </div>\n <div>\n <button\n type=\"button\"\n aria-label={copy.reset}\n title={copy.reset}\n className=\"bsv3d-icon\"\n onClick={(event) => {\n event.stopPropagation();\n setResetSignal((value) => value + 1);\n }}\n >\n <RotateCcw aria-hidden=\"true\" />\n </button>\n {!isFullscreen && (\n <button\n type=\"button\"\n aria-label={copy.fullscreen}\n title={copy.fullscreen}\n className=\"bsv3d-icon\"\n data-viewer3d-fullscreen=\"\"\n onClick={(event) => {\n event.stopPropagation();\n fullscreen.enter();\n }}\n >\n <Maximize2 aria-hidden=\"true\" />\n </button>\n )}\n </div>\n </div>\n )}\n\n {isFullscreen && (\n <button\n type=\"button\"\n aria-label={copy.closeFullscreen}\n title={copy.closeFullscreen}\n className=\"bsv3d-icon bsv3d-close\"\n onClick={(event) => {\n event.stopPropagation();\n fullscreen.exit();\n }}\n >\n <X aria-hidden=\"true\" />\n </button>\n )}\n\n <p className=\"bsv3d-sr\" aria-live=\"polite\">\n {state.status === \"loading\"\n ? percent > 0\n ? copy.loadingProgress(percent)\n : copy.loading\n : state.status === \"error\"\n ? copy.error\n : \"\"}\n </p>\n </div>\n\n {isFullscreen && renderFullscreenBar != null && (\n <div\n className=\"bsv3d-buybar\"\n onClick={(event) => event.stopPropagation()}\n >\n {renderFullscreenBar({ close: fullscreen.exit })}\n </div>\n )}\n </div>,\n )}\n\n {!hideNotes && (\n <ModelNotes\n model={model}\n copy={copy}\n locale={locale}\n reportHref={reportHref}\n />\n )}\n </section>\n );\n}\n\nfunction Poster({\n src,\n alt,\n hidden,\n}: {\n src?: string;\n alt: string;\n hidden: boolean;\n}) {\n const [broken, setBroken] = useState(false);\n return (\n <div\n aria-hidden={hidden}\n className=\"bsv3d-poster\"\n data-hidden={hidden ? \"\" : undefined}\n >\n {src != null && !broken ? (\n <img\n src={src}\n alt={alt}\n decoding=\"async\"\n loading=\"lazy\"\n onError={() => setBroken(true)}\n />\n ) : (\n <Box aria-hidden=\"true\" strokeWidth={1.25} />\n )}\n </div>\n );\n}\n\nfunction ModelNotes({\n model,\n copy,\n locale,\n reportHref,\n}: {\n model: Model3DView;\n copy: Viewer3DCopy;\n locale?: string;\n reportHref?: string;\n}) {\n const [href, setHref] = useState(reportHref);\n // The notice form gets the page that is reported.\n useEffect(() => {\n if (reportHref == null) {\n setHref(undefined);\n return;\n }\n try {\n const url = new URL(reportHref, window.location.href);\n if (!url.searchParams.has(\"url\"))\n url.searchParams.set(\"url\", window.location.href);\n setHref(url.toString());\n } catch {\n setHref(reportHref);\n }\n }, [reportHref]);\n const facts =\n model.facts != null ? modelFactRows(model.facts, copy, locale) : [];\n\n if (!model.illustrative && href == null && facts.length === 0) return null;\n return (\n <div className=\"bsv3d-notes\">\n {facts.length > 0 && (\n <div>\n <p className=\"bsv3d-facts-title\">{copy.factsTitle}</p>\n <dl>\n {facts.map((row) => (\n <div key={row.label}>\n <dt>{row.label}</dt>\n <dd>{row.value}</dd>\n </div>\n ))}\n </dl>\n </div>\n )}\n {(model.illustrative || href != null) && (\n <p className=\"bsv3d-links\">\n {model.illustrative && <span>{copy.disclaimer}</span>}\n {href != null && <a href={href}>{copy.report}</a>}\n </p>\n )}\n </div>\n );\n}\n","import type { Model3DFacts, Model3DUnit } from \"./types\";\n\nimport { formatModelSize } from \"./constants\";\nimport { numberLocale, type Viewer3DCopy } from \"./copy\";\n\nconst MM_PER_UNIT: Record<Model3DUnit, number> = {\n meters: 1000,\n centimeters: 10,\n millimeters: 1,\n inches: 25.4,\n};\n\n/** \"32 × 18 × 12 cm\": the dimensions in the unit the merchant made the model in. */\nexport function formatDimensions(\n dimensionsMm: readonly number[],\n unit: Model3DUnit,\n copy: Viewer3DCopy,\n locale?: string,\n): string | undefined {\n if (dimensionsMm.length !== 3) return undefined;\n const format = new Intl.NumberFormat(numberLocale(locale), {\n maximumFractionDigits: unit === \"millimeters\" ? 0 : 2,\n });\n const scale = MM_PER_UNIT[unit] ?? 1000;\n return `${dimensionsMm.map((mm) => format.format(mm / scale)).join(\" × \")} ${copy.units[unit]}`;\n}\n\n/** The rows of \"Szczegóły modelu\" (D12), in display order. */\nexport function modelFactRows(\n facts: Model3DFacts,\n copy: Viewer3DCopy,\n locale?: string,\n): { label: string; value: string }[] {\n const rows = [{ label: copy.factsFormat, value: \"GLB\" }];\n if (facts.fileSize > 0) {\n rows.push({\n label: copy.factsFileSize,\n value: formatModelSize(facts.fileSize, numberLocale(locale)),\n });\n }\n if (facts.triangleCount > 0) {\n rows.push({\n label: copy.factsTriangles,\n value: copy.triangles(\n new Intl.NumberFormat(numberLocale(locale)).format(facts.triangleCount),\n ),\n });\n }\n const dimensions = formatDimensions(\n facts.dimensionsMm,\n facts.unit,\n copy,\n locale,\n );\n if (dimensions) rows.push({ label: copy.factsDimensions, value: dimensions });\n return rows;\n}\n\n/** A licence \"text\" that is just a link opens in a new tab instead of a dialog. */\nexport function licenceLink(text: string | undefined): string | undefined {\n const trimmed = text?.trim();\n if (!trimmed || /\\s/.test(trimmed)) return undefined;\n try {\n const url = new URL(trimmed);\n return url.protocol === \"https:\" || url.protocol === \"http:\"\n ? url.toString()\n : undefined;\n } catch {\n return undefined;\n }\n}\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type RefObject,\n} from \"react\";\n\n/**\n * Full screen for the viewer section: the Fullscreen API where an element can\n * go full screen, else a fixed CSS overlay (iPhone Safari has no element\n * fullscreen). Escape or close returns to the page at the same scroll position.\n */\nexport type FullscreenMode = \"native\" | \"overlay\";\n\nfunction canUseNativeFullscreen(element: HTMLElement | null): boolean {\n return (\n element != null &&\n typeof element.requestFullscreen === \"function\" &&\n document.fullscreenEnabled === true\n );\n}\n\nexport function useViewerFullscreen(ref: RefObject<HTMLElement | null>) {\n const [mode, setMode] = useState<FullscreenMode | null>(null);\n const scrollRef = useRef(0);\n\n const exit = useCallback(() => {\n if (document.fullscreenElement != null) {\n void document.exitFullscreen().catch(() => setMode(null));\n return;\n }\n setMode(null);\n }, []);\n\n const enter = useCallback(() => {\n const element = ref.current;\n scrollRef.current = window.scrollY;\n if (canUseNativeFullscreen(element)) {\n element!\n .requestFullscreen({ navigationUI: \"hide\" })\n .then(() => setMode(\"native\"))\n .catch(() => setMode(\"overlay\"));\n return;\n }\n setMode(\"overlay\");\n }, [ref]);\n\n // Native: leaving with Escape or the browser's own control.\n useEffect(() => {\n const onChange = () => {\n if (document.fullscreenElement == null) {\n setMode((current) => (current === \"native\" ? null : current));\n }\n };\n document.addEventListener(\"fullscreenchange\", onChange);\n return () => document.removeEventListener(\"fullscreenchange\", onChange);\n }, []);\n\n // Native: browsers handle Escape themselves; this covers the ones that pass\n // the key to the page instead.\n useEffect(() => {\n if (mode !== \"native\") return;\n const onKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && document.fullscreenElement != null) {\n void document.exitFullscreen().catch(() => setMode(null));\n }\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [mode]);\n\n // Overlay: lock the page behind it and close it with Escape.\n useEffect(() => {\n if (mode !== \"overlay\") return;\n const { body, documentElement } = document;\n const previous = {\n overflow: body.style.overflow,\n rootOverflow: documentElement.style.overflow,\n };\n body.style.overflow = \"hidden\";\n documentElement.style.overflow = \"hidden\";\n const onKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") setMode(null);\n };\n window.addEventListener(\"keydown\", onKey);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n body.style.overflow = previous.overflow;\n documentElement.style.overflow = previous.rootOverflow;\n };\n }, [mode]);\n\n // Back on the page where the buyer left it.\n useEffect(() => {\n if (mode == null && scrollRef.current > 0) {\n const y = scrollRef.current;\n scrollRef.current = 0;\n requestAnimationFrame(() =>\n window.scrollTo({ top: y, behavior: \"instant\" }),\n );\n }\n }, [mode]);\n\n return { mode, isFullscreen: mode != null, enter, exit };\n}\n","/**\n * The gesture hint (\"Przeciągnij, aby obrócić\") shows once per browser: the\n * first time a viewer becomes interactive (plan: gap 9). Storage may be absent\n * or throw (private mode, blocked cookies); then the hint just shows again.\n */\nexport const GESTURE_HINT_STORAGE_KEY = \"bitsnap:viewer3d:gesture-hint-seen\";\n\ntype HintStorage = Pick<Storage, \"getItem\" | \"setItem\">;\n\nfunction defaultStorage(): HintStorage | undefined {\n try {\n return typeof window === \"undefined\" ? undefined : window.localStorage;\n } catch {\n return undefined;\n }\n}\n\nexport function hasSeenGestureHint(\n storage: HintStorage | undefined = defaultStorage(),\n): boolean {\n try {\n return storage?.getItem(GESTURE_HINT_STORAGE_KEY) === \"1\";\n } catch {\n return false;\n }\n}\n\nexport function markGestureHintSeen(\n storage: HintStorage | undefined = defaultStorage(),\n): void {\n try {\n storage?.setItem(GESTURE_HINT_STORAGE_KEY, \"1\");\n } catch {\n // Not remembered; the hint shows again next time.\n }\n}\n","import { needsClickToLoad } from \"./constants\";\n\n/**\n * The states of `Model3DShell` (plan: \"Buyer viewer\" → Module). Pure, so the\n * click-to-load rule, the per-variant re-check and the error path are tested\n * without a browser.\n *\n * - `poster`: the thumbnail; the model loads once the section is visible.\n * - `awaiting-click`: a display copy over 10 MB; nothing is downloaded until\n * the buyer asks (\"Pokaż model 3D (24 MB)\" or the hero pill).\n * - `loading`: the viewer is mounted and downloads; the poster stays with a\n * progress bar until the first frame.\n * - `ready`: the model is on screen.\n * - `error`: the poster stays with \"Spróbuj ponownie\".\n * - `unsupported`: no WebGL; the poster stays.\n */\nexport type ShellStatus =\n \"poster\" | \"awaiting-click\" | \"loading\" | \"ready\" | \"error\" | \"unsupported\";\n\nexport type ShellModel = {\n /** Identifies the model (its preview URL). */\n key: string;\n /** Bytes of the display copy. */\n size: number;\n};\n\nexport type ShellState = {\n status: ShellStatus;\n model: ShellModel;\n /** 0..1 of the download; 0 while unknown. */\n progress: number;\n /** Bumped on every retry, so the viewer remounts and loads again. */\n attempt: number;\n};\n\nexport type ShellEvent =\n /** The section came near the viewport (and WebGL works). */\n | { type: \"VISIBLE\" }\n /** The buyer asked: the button, the hero pill. Loads whatever the size. */\n | { type: \"REQUEST\" }\n | { type: \"PROGRESS\"; key: string; loaded: number; total: number }\n | { type: \"LOADED\"; key: string }\n | { type: \"FAILED\"; key: string }\n | { type: \"RETRY\" }\n | { type: \"NO_WEBGL\" }\n /** Another variant: another model, or the same one again. */\n | { type: \"MODEL_CHANGED\"; model: ShellModel; visible: boolean };\n\nfunction statusFor(model: ShellModel, visible: boolean): ShellStatus {\n if (needsClickToLoad(model.size)) return \"awaiting-click\";\n return visible ? \"loading\" : \"poster\";\n}\n\nexport function initialShellState(model: ShellModel): ShellState {\n return { status: statusFor(model, false), model, progress: 0, attempt: 0 };\n}\n\nexport function shellReducer(state: ShellState, event: ShellEvent): ShellState {\n switch (event.type) {\n case \"NO_WEBGL\":\n return state.status === \"ready\"\n ? state\n : { ...state, status: \"unsupported\" };\n\n case \"VISIBLE\":\n return state.status === \"poster\"\n ? { ...state, status: \"loading\", progress: 0 }\n : state;\n\n case \"REQUEST\":\n if (state.status === \"poster\" || state.status === \"awaiting-click\") {\n return { ...state, status: \"loading\", progress: 0 };\n }\n if (state.status === \"error\") {\n return {\n ...state,\n status: \"loading\",\n progress: 0,\n attempt: state.attempt + 1,\n };\n }\n return state;\n\n case \"RETRY\":\n return state.status === \"error\"\n ? {\n ...state,\n status: \"loading\",\n progress: 0,\n attempt: state.attempt + 1,\n }\n : state;\n\n case \"PROGRESS\": {\n if (state.status !== \"loading\" || event.key !== state.model.key)\n return state;\n const progress =\n event.total > 0\n ? Math.min(1, Math.max(0, event.loaded / event.total))\n : 0;\n return progress === state.progress ? state : { ...state, progress };\n }\n\n case \"LOADED\":\n if (state.status !== \"loading\" || event.key !== state.model.key)\n return state;\n return { ...state, status: \"ready\", progress: 1 };\n\n case \"FAILED\":\n if (state.status !== \"loading\" || event.key !== state.model.key)\n return state;\n return { ...state, status: \"error\" };\n\n case \"MODEL_CHANGED\": {\n if (event.model.key === state.model.key) {\n return event.model.size === state.model.size\n ? state\n : { ...state, model: event.model };\n }\n if (state.status === \"unsupported\")\n return { ...state, model: event.model };\n // The rule applies per variant: a big model asks again, whatever came before.\n return {\n status: statusFor(event.model, event.visible),\n model: event.model,\n progress: 0,\n attempt: 0,\n };\n }\n }\n}\n\n/** The viewer (and its download) exists only in these states. */\nexport function isViewerMounted(status: ShellStatus): boolean {\n return status === \"loading\" || status === \"ready\";\n}\n","/**\n * Styles of the 3D viewer, rendered as one React 19 `<style href precedence>`\n * element: hoisted to `<head>`, deduplicated, and part of the server render,\n * so the poster keeps its size before hydration and the subpath needs no CSS\n * import. Every rule is scoped to `[data-bitsnap-viewer3d]`.\n *\n * Theme: set the custom properties below on the viewer or an ancestor, or pass\n * `appearance` to `Product3DViewer`.\n * --bitsnap-viewer3d-background (#ffffff) frame and buttons\n * --bitsnap-viewer3d-foreground (#171717) text and icons\n * --bitsnap-viewer3d-muted (foreground at 70%) notes under the viewer\n * --bitsnap-viewer3d-border (#e5e5e5)\n * --bitsnap-viewer3d-accent (#0a7ea5) progress bar\n * --bitsnap-viewer3d-radius (0.75rem)\n */\nexport const VIEWER3D_STYLE_HREF = \"bitsnap-react-viewer3d\";\n\nconst S = \"[data-bitsnap-viewer3d]\";\nconst BG = \"var(--bitsnap-viewer3d-background,#ffffff)\";\nconst FG = \"var(--bitsnap-viewer3d-foreground,#171717)\";\nconst BORDER = \"var(--bitsnap-viewer3d-border,#e5e5e5)\";\nconst RADIUS = \"var(--bitsnap-viewer3d-radius,0.75rem)\";\n\nexport const VIEWER3D_CSS = `\n${S}{container-type:inline-size;display:flex;flex-direction:column;gap:.75rem;font-family:inherit;color:${FG}}\n${S} *{box-sizing:border-box}\n${S} .bsv3d-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n.bsv3d-frame{position:relative;display:flex;flex-direction:column;overflow:hidden;background:${BG};color:${FG};border:1px solid ${BORDER};border-radius:${RADIUS}}\n.bsv3d-frame[data-fullscreen]{position:fixed;inset:0;z-index:2147483000;width:100vw;height:100dvh;border:0;border-radius:0}\n.bsv3d-stage{position:relative;width:100%;aspect-ratio:4/3}\n.bsv3d-placeholder{width:100%;aspect-ratio:4/3}\n@container (min-width:48rem){${S} .bsv3d-stage,${S} .bsv3d-placeholder{aspect-ratio:16/11}}\n.bsv3d-frame[data-fullscreen] .bsv3d-stage{aspect-ratio:auto;flex:1;min-height:0}\n.bsv3d-canvas{position:absolute!important;inset:0}\n.bsv3d-poster{pointer-events:none;position:absolute;inset:0;display:grid;place-items:center;opacity:1}\n.bsv3d-poster[data-hidden]{opacity:0}\n.bsv3d-poster img{width:100%;height:100%;object-fit:contain;padding:6%;display:block}\n.bsv3d-poster svg{width:4rem;height:4rem;color:color-mix(in srgb,${FG} 30%,transparent)}\n.bsv3d-chip{pointer-events:none;display:inline-flex;align-items:center;gap:.5rem;border-radius:999px;padding:.5rem .875rem;font-size:.875rem;line-height:1.25rem;font-weight:500;background:color-mix(in srgb,${FG} 82%,transparent);color:${BG}}\n.bsv3d-chip svg{width:1rem;height:1rem;flex:none}\n.bsv3d-chip[data-small]{font-size:.75rem;line-height:1rem;padding:.375rem .75rem}\n.bsv3d-loading{pointer-events:none;position:absolute;inset:auto 0 0 0;display:flex;flex-direction:column;align-items:flex-start;gap:.5rem}\n.bsv3d-loading .bsv3d-chip{margin:0 .75rem}\n.bsv3d-bar{height:4px;width:100%;background:color-mix(in srgb,${FG} 10%,transparent)}\n.bsv3d-bar>div{height:100%;background:var(--bitsnap-viewer3d-accent,#0a7ea5)}\n.bsv3d-center{position:absolute;inset:0;display:grid;place-items:center;padding:1rem}\n.bsv3d-button{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;height:2.75rem;padding:0 1.25rem;border:1px solid ${BORDER};border-radius:${RADIUS};background:${BG};color:${FG};font:inherit;font-size:.875rem;font-weight:600;font-variant-numeric:tabular-nums;cursor:pointer;box-shadow:0 8px 20px -10px rgb(15 23 42/.45)}\n.bsv3d-button:hover{border-color:color-mix(in srgb,${FG} 40%,transparent)}\n.bsv3d-button svg{width:1rem;height:1rem}\n.bsv3d-button:disabled{opacity:.6;cursor:default}\n.bsv3d-alert{display:flex;max-width:20rem;flex-direction:column;align-items:center;gap:.75rem;border-radius:${RADIUS};background:${BG};padding:1rem 1.25rem;text-align:center;box-shadow:0 8px 20px -10px rgb(15 23 42/.45)}\n.bsv3d-alert p{margin:0;font-size:.875rem;font-weight:600}\n.bsv3d-alert .bsv3d-button{height:2.5rem;box-shadow:none}\n.bsv3d-unsupported{position:absolute;left:.75rem;bottom:.75rem}\n.bsv3d-hint{pointer-events:none;position:absolute;inset:auto 0 4rem 0;display:flex;justify-content:center;opacity:0}\n.bsv3d-hint[data-visible]{opacity:1}\n.bsv3d-controls{position:absolute;left:.75rem;right:.75rem;bottom:.75rem;display:flex;align-items:flex-end;justify-content:space-between;gap:.5rem}\n.bsv3d-controls>div:last-child{display:flex;flex:none;gap:.5rem}\n.bsv3d-icon{display:grid;place-items:center;width:2.5rem;height:2.5rem;padding:0;border-radius:999px;border:1px solid ${BORDER};background:color-mix(in srgb,${BG} 88%,transparent);color:${FG};cursor:pointer;font:inherit}\n.bsv3d-icon:hover{background:${BG};border-color:color-mix(in srgb,${FG} 35%,transparent)}\n.bsv3d-icon svg{width:1rem;height:1rem}\n.bsv3d-icon[data-wide]{width:auto;padding:0 1rem;font-size:.875rem;font-weight:600}\n.bsv3d-close{position:absolute;top:max(.75rem,env(safe-area-inset-top));right:.75rem}\n.bsv3d-close svg{width:1.25rem;height:1.25rem}\n${S} button:focus-visible,${S} a:focus-visible,.bsv3d-frame button:focus-visible{outline:2px solid ${FG};outline-offset:2px}\n.bsv3d-buybar{flex:none;border-top:1px solid ${BORDER};background:${BG};padding:.75rem 1rem max(.75rem,env(safe-area-inset-bottom))}\n.bsv3d-buybar-row{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap}\n.bsv3d-buybar-name{margin:0;font-weight:600;font-size:1rem}\n.bsv3d-buybar-price{margin:0;font-size:.875rem;font-variant-numeric:tabular-nums}\n.bsv3d-buybar .bsv3d-button{box-shadow:none;background:${FG};color:${BG};border-color:${FG}}\n.bsv3d-buybar-error{margin:.25rem 0 0;font-size:.875rem;color:#b91c1c}\n.bsv3d-notes{display:flex;flex-direction:column;gap:.75rem;font-size:.75rem;line-height:1.6;color:var(--bitsnap-viewer3d-muted,color-mix(in srgb,${FG} 70%,transparent))}\n.bsv3d-notes p{margin:0}\n.bsv3d-notes .bsv3d-facts-title{font-size:.875rem;font-weight:600;color:${FG}}\n.bsv3d-notes dl{display:flex;flex-wrap:wrap;gap:.5rem 1.5rem;margin:.375rem 0 0}\n.bsv3d-notes dl>div{display:flex;flex-direction:column}\n.bsv3d-notes dd{margin:0;font-size:.875rem;font-weight:500;color:${FG};font-variant-numeric:tabular-nums}\n.bsv3d-notes .bsv3d-links{display:flex;flex-wrap:wrap;align-items:baseline;gap:.25rem .75rem}\n.bsv3d-notes a{color:inherit;font-weight:500;text-decoration:underline;text-underline-offset:2px}\n@media (prefers-reduced-motion:no-preference){\n.bsv3d-poster{transition:opacity .5s cubic-bezier(.16,1,.3,1)}\n.bsv3d-hint{transition:opacity .3s}\n.bsv3d-bar>div{transition:width .2s}\n}\n`;\n","import { useCallback, useEffect, useState } from \"react\";\nimport { HOST } from \"../components/checkout/constants\";\nimport { getLocale } from \"../components/checkout/locale\";\nimport { getPanelConfig } from \"../panel/config\";\nimport {\n fetchProduct3D,\n pickProduct,\n pickVariant,\n resolveModel,\n type Product3DProduct,\n type Product3DVariant,\n} from \"./model\";\nimport type { Model3DView } from \"./types\";\n\nexport type UseProduct3DModelOptions = {\n /**\n * Project (shop) ID. Defaults to the one set with `setProjectID` from\n * `bitsnap-react`.\n */\n projectID?: string;\n /**\n * Origin of the Bitsnap backend. Defaults to the library host\n * (`https://bitsnap.pl`, or what `setCustomHost` had set). On a custom\n * domain pass the domain itself, or `\"\"` for same-origin requests.\n */\n host?: string;\n /** Locale of the product name. Defaults to the library locale. */\n locale?: string;\n};\n\nexport type Product3DStatus =\n /** Waiting for the product (also on the server and the first render). */\n | \"loading\"\n /** `model` is set. */\n | \"ready\"\n /** The product (or the chosen variant) has no 3D model, or the server has no 3D support. */\n | \"none\"\n /** The product could not be loaded; `retry()` asks again. */\n | \"error\";\n\nexport type UseProduct3DModelResult = {\n status: Product3DStatus;\n model?: Model3DView;\n /** The product as the public endpoint sent it (name, price, variants). */\n product?: Product3DProduct;\n /** The chosen variant, when `variantId` matches one. */\n variant?: Product3DVariant;\n error?: Error;\n retry: () => void;\n};\n\ntype Loaded =\n | { key: string; products: Product3DProduct[]; error?: undefined }\n | { key: string; products?: undefined; error: Error };\n\n/**\n * The public 3D model of a product (and variant). Fetches in the browser\n * only; switching `variantId` does not fetch again.\n */\nexport function useProduct3DModel(\n productId: string,\n variantId?: string,\n options: UseProduct3DModelOptions = {},\n): UseProduct3DModelResult {\n const projectID = options.projectID ?? getPanelConfig().projectID;\n const [host] = useState(() => options.host ?? HOST);\n const effectiveHost = options.host ?? host;\n const [locale] = useState(() => options.locale ?? getLocale());\n const effectiveLocale = options.locale ?? locale;\n const key = `${effectiveHost}|${projectID}|${productId}|${effectiveLocale}`;\n const [loaded, setLoaded] = useState<Loaded>();\n const [attempt, setAttempt] = useState(0);\n\n useEffect(() => {\n if (!productId) return;\n if (!projectID) {\n setLoaded({\n key,\n error: new Error(\n \"bitsnap-react/viewer3d: no project ID (pass projectID or call setProjectID)\",\n ),\n });\n return;\n }\n let cancelled = false;\n fetchProduct3D({\n projectID,\n host: effectiveHost,\n productId,\n locale: effectiveLocale,\n }).then(\n (products) => {\n if (!cancelled) setLoaded({ key, products });\n },\n (error: unknown) => {\n if (!cancelled)\n setLoaded({\n key,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n },\n );\n return () => {\n cancelled = true;\n };\n }, [key, attempt]);\n\n const retry = useCallback(() => setAttempt((value) => value + 1), []);\n\n if (!productId) return { status: \"none\", retry };\n if (loaded == null || loaded.key !== key) return { status: \"loading\", retry };\n if (loaded.error != null) return { status: \"error\", error: loaded.error, retry };\n const product = pickProduct(loaded.products, productId);\n if (product == null) return { status: \"none\", retry };\n // A variant id passed as `productId` chooses that variant.\n const chosen =\n variantId ?? (pickVariant(product, productId) != null ? productId : undefined);\n const variant = pickVariant(product, chosen);\n const model = resolveModel(product, chosen);\n return {\n status: model != null ? \"ready\" : \"none\",\n model,\n product,\n variant,\n retry,\n };\n}\n","import { withClientParam } from \"@/src/lib/client-header\";\nimport type { Model3DView } from \"./types\";\n\n/**\n * The public product data the 3D viewer reads:\n * `GET {host}/api/integrations/{projectID}/public-commerce/products?ids=…&include=model3d`,\n * the endpoint the cart already uses. Servers without 3D support ignore\n * `include` and send no `model3d`: the viewer then shows nothing.\n */\nexport type Product3DVariant = {\n id: string;\n name: string;\n /** Minor units (grosze, cents). */\n price: number;\n currency: string;\n availableQuantity?: number;\n priceType?: string;\n model3d?: Model3DView;\n};\n\nexport type Product3DProduct = {\n id: string;\n name: string;\n price: number;\n currency: string;\n availableQuantity?: number;\n priceType?: string;\n recurring?: unknown;\n model3d?: Model3DView;\n variants?: Product3DVariant[];\n};\n\nexport type Product3DQuery = {\n projectID: string;\n /** Origin of the Bitsnap backend (or of a custom domain), without a path. */\n host: string;\n productId: string;\n locale?: string;\n};\n\nexport class Product3DError extends Error {\n readonly status: number | undefined;\n\n constructor(message: string, status?: number) {\n super(message);\n this.name = \"Product3DError\";\n this.status = status;\n }\n}\n\nexport function buildProduct3DURL(query: Product3DQuery): string {\n const params = new URLSearchParams();\n params.set(\"ids\", query.productId);\n if (query.locale) params.set(\"locale\", query.locale);\n params.set(\"include\", \"model3d\");\n const host = query.host.replace(/\\/+$/, \"\");\n return `${host}/api/integrations/${encodeURIComponent(\n query.projectID,\n )}/public-commerce/products?${params.toString()}`;\n}\n\nfunction isModel(value: unknown): value is Model3DView {\n return (\n typeof value === \"object\" &&\n value != null &&\n typeof (value as Model3DView).previewUrl === \"string\" &&\n (value as Model3DView).previewUrl.length > 0 &&\n typeof (value as Model3DView).previewSize === \"number\"\n );\n}\n\n/** The product a request answered with: the exact id, else the one holding it as a variant. */\nexport function pickProduct(\n products: readonly Product3DProduct[],\n productId: string,\n): Product3DProduct | undefined {\n return (\n products.find((product) => product.id === productId) ??\n products.find((product) =>\n product.variants?.some((variant) => variant.id === productId),\n ) ??\n (products.length === 1 ? products[0] : undefined)\n );\n}\n\n/** `prodv2_<hash>` of a product or variant id (`prodv2_<hash>_<variant>`). */\nfunction baseProductID(id: string): string {\n return /^(prodv2_[^_]+)/.exec(id)?.[1] ?? id;\n}\n\n/**\n * The variant of `variantId`: its full id (`prodv2_X_red`), or the part after\n * `prodv2_X_` (`red`). The server may answer `prodv2_X` with an item whose id\n * is `prodv2_X_default`, so the base comes from the id itself.\n */\nexport function pickVariant(\n product: Product3DProduct,\n variantId: string | undefined,\n): Product3DVariant | undefined {\n if (!variantId) return undefined;\n const variants = product.variants ?? [];\n const full = `${baseProductID(product.id)}_${variantId}`;\n return (\n variants.find((variant) => variant.id === variantId) ??\n variants.find((variant) => variant.id === full)\n );\n}\n\n/**\n * The model to show: the chosen variant's (the server already gives a variant\n * the product's model when it has none of its own), else the product's, else\n * the first variant with one. A chosen variant without a model shows none.\n */\nexport function resolveModel(\n product: Product3DProduct,\n variantId?: string,\n): Model3DView | undefined {\n const variant = pickVariant(product, variantId);\n if (variant != null) return isModel(variant.model3d) ? variant.model3d : undefined;\n if (isModel(product.model3d)) return product.model3d;\n return product.variants?.map((item) => item.model3d).find(isModel);\n}\n\n/** Whether any variant or the product has a model (for a variant picker). */\nexport function hasAnyModel(product: Product3DProduct): boolean {\n return resolveModel(product) != null;\n}\n\nconst cache = new Map<string, Promise<Product3DProduct[]>>();\n\n/**\n * Loads the product with a credential-less `fetch`, once per URL per page\n * (several viewers of one product share the request). A failed request is\n * forgotten so a retry asks again.\n */\nexport function fetchProduct3D(query: Product3DQuery): Promise<Product3DProduct[]> {\n const url = withClientParam(buildProduct3DURL(query));\n let pending = cache.get(url);\n if (pending == null) {\n pending = (async () => {\n const response = await fetch(url, {\n method: \"GET\",\n credentials: \"omit\",\n headers: { Accept: \"application/json\" },\n });\n if (!response.ok) {\n throw new Product3DError(\n `Could not load the product (${response.status})`,\n response.status,\n );\n }\n const payload = (await response.json()) as { result?: unknown };\n return Array.isArray(payload?.result)\n ? (payload.result as Product3DProduct[])\n : [];\n })();\n cache.set(url, pending);\n pending.catch(() => cache.delete(url));\n }\n return pending;\n}\n\n/** @internal Tests start from an empty cache. */\nexport function clearProduct3DCache(): void {\n cache.clear();\n}\n"],"mappings":"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","names":["useState","VIEWER3D_COPY_PL","size","percent","count","VIEWER3D_COPY_EN","viewer3DCopy","locale","overrides","base","numberLocale","Box","Hand","Maximize2","Rotate3d","RotateCcw","X","useCallback","useEffect","useId","useReducer","useRef","useState","createPortal","MM_PER_UNIT","formatDimensions","dimensionsMm","unit","copy","locale","format","numberLocale","scale","mm","modelFactRows","facts","rows","formatModelSize","dimensions","useCallback","useEffect","useRef","useState","canUseNativeFullscreen","element","useViewerFullscreen","ref","mode","setMode","scrollRef","exit","enter","onChange","current","onKey","event","body","documentElement","previous","y","GESTURE_HINT_STORAGE_KEY","defaultStorage","hasSeenGestureHint","storage","markGestureHintSeen","statusFor","model","visible","needsClickToLoad","initialShellState","shellReducer","state","event","progress","isViewerMounted","status","VIEWER3D_STYLE_HREF","S","BG","FG","BORDER","RADIUS","VIEWER3D_CSS","jsx","jsxs","loadDefaultViewer","appearanceStyle","appearance","style","key","value","hasWebGL","canvas","useMediaQuery","query","matches","setMatches","useState","useEffect","media","update","usePageVisible","visible","setVisible","Model3DViewer","model","productName","locale","texts","decoderPath","reportHref","startSignal","renderFullscreenBar","hideNotes","id","className","loadViewer","copy","viewer3DCopy","shellModel","state","dispatch","useReducer","shellReducer","initialShellState","Viewer","setViewer","frameRef","useRef","stageRef","near","setNear","onScreen","setOnScreen","pageVisible","reducedMotion","coarsePointer","touchActive","setTouchActive","hint","setHint","resetSignal","setResetSignal","fullscreen","useViewerFullscreen","titleID","useId","themeStyle","element","nearObserver","entry","screenObserver","firstStart","mounted","isViewerMounted","cancelled","module","error","ready","hasSeenGestureHint","markGestureHintSeen","timer","GESTURE_HINT_MS","onPointerDown","event","interactive","onInteract","useCallback","onProgress","loaded","total","onLoaded","onError","sizeLabel","formatModelSize","numberLocale","percent","isFullscreen","motionAllowed","portal","node","createPortal","VIEWER3D_STYLE_HREF","VIEWER3D_CSS","Poster","Box","RotateCcw","Hand","Rotate3d","Maximize2","X","ModelNotes","src","alt","hidden","broken","setBroken","href","setHref","url","facts","modelFactRows","row","useCallback","useEffect","useState","Product3DError","message","status","buildProduct3DURL","query","params","isModel","value","pickProduct","products","productId","product","variant","baseProductID","id","pickVariant","variantId","variants","full","resolveModel","item","cache","fetchProduct3D","query","url","withClientParam","buildProduct3DURL","pending","response","Product3DError","payload","useProduct3DModel","productId","variantId","options","projectID","getPanelConfig","host","useState","HOST","effectiveHost","locale","getLocale","effectiveLocale","key","loaded","setLoaded","attempt","setAttempt","useEffect","cancelled","fetchProduct3D","products","error","retry","useCallback","value","product","pickProduct","chosen","pickVariant","variant","model","resolveModel","Fragment","jsx","jsxs","Product3DViewer","productId","variantId","projectID","host","locale","renderBuyBar","fallback","productUrl","onAddedToCart","viewer","result","useProduct3DModel","product","copy","viewer3DCopy","Model3DViewer","close","DefaultBuyBar","getPanelConfig","isCartable","variant","priceType","quantity","cartItemIdFor","onAdded","state","setState","useState","price","currency","canAdd","formatProductPrice","addProductToCart","HOST"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bitsnap-react",
3
- "version": "1.14.1",
3
+ "version": "1.16.0",
4
4
  "description": "This is Bitsnap React library for easy integration with any website which is using React framework",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -14,7 +14,7 @@
14
14
  "clean": "rimraf ./dist",
15
15
  "dev": "node scripts/write-version.mjs && tsup --watch",
16
16
  "dev:publish": "pnpm dev --env.publish",
17
- "test": "tsup src/components/checkout/appearance.test.ts src/components/checkout/texts.test.ts src/components/checkout/buy-error.test.ts src/components/checkout/cart-buy-error.test.tsx src/lib/appearance-core.test.ts src/lib/texts.test.ts src/components/returns/appearance.test.ts src/components/returns/texts.test.ts src/components/returns/errors.test.ts src/components/returns/money.test.ts src/components/returns/session-storage.test.ts src/components/returns/state-machine.test.ts src/components/returns/selection.test.ts src/components/returns/legacy.test.ts src/panel/returns-appearance.test.ts src/components/products/appearance.test.ts src/components/products/texts.test.ts src/components/products/format.test.ts src/components/products/fetch.test.ts src/components/products/useProducts.test.ts src/components/products/cart-target.test.ts src/components/checkout/cart-items.test.ts src/components/checkout/pending-order.test.ts src/components/checkout/quantity.test.ts src/components/checkout/cart-a11y.test.tsx src/components/checkout/payment-method.test.ts src/components/checkout/cart-payment-method.test.tsx src/course/logic.test.ts src/course/accent.test.ts src/course/texts.test.ts src/course/datasource.test.ts src/course/sanitize.test.ts src/course/VideoPlayer.test.tsx src/course/PanelCourse.test.tsx src/consent/core/cookie.test.ts src/consent/core/texts.test.ts src/consent/core/activate.test.ts src/consent/core/gcm.test.ts src/consent/core/contrast.test.ts src/consent/core/controller.test.ts src/consent/embed.test.ts src/consent/react.test.tsx src/consent/react-shown.test.tsx src/analytics/core.test.ts src/analytics/embed.test.ts src/analytics/instrument.test.tsx src/analytics/page-views.test.tsx src/analytics/visitor.test.ts src/components/checkout/visitor-header.test.ts src/components/products/impressions.test.ts src/components/products/ProductList.analytics.test.tsx src/components/checkout/cart-analytics.test.tsx src/components/checkout/apple-pay-analytics.test.tsx src/components/notifications/notifications-analytics.test.tsx src/components/returns/returns-analytics.test.tsx src/panel/panel-analytics.test.tsx src/course/course-analytics.test.tsx --format esm --out-dir .test-dist --no-config --external jsdom --silent && node --test --test-force-exit \".test-dist/**/*.test.mjs\"",
17
+ "test": "tsup src/components/checkout/appearance.test.ts src/components/checkout/texts.test.ts src/components/checkout/buy-error.test.ts src/components/checkout/cart-buy-error.test.tsx src/lib/appearance-core.test.ts src/lib/texts.test.ts src/components/returns/appearance.test.ts src/components/returns/texts.test.ts src/components/returns/errors.test.ts src/components/returns/money.test.ts src/components/returns/session-storage.test.ts src/components/returns/state-machine.test.ts src/components/returns/selection.test.ts src/components/returns/legacy.test.ts src/panel/returns-appearance.test.ts src/components/products/appearance.test.ts src/components/products/texts.test.ts src/components/products/format.test.ts src/components/products/fetch.test.ts src/components/products/useProducts.test.ts src/components/products/cart-target.test.ts src/components/checkout/cart-items.test.ts src/components/checkout/pending-order.test.ts src/components/checkout/quantity.test.ts src/components/checkout/cart-a11y.test.tsx src/components/checkout/payment-method.test.ts src/components/checkout/cart-payment-method.test.tsx src/course/logic.test.ts src/course/accent.test.ts src/course/texts.test.ts src/course/datasource.test.ts src/course/sanitize.test.ts src/course/VideoPlayer.test.tsx src/course/PanelCourse.test.tsx src/consent/core/cookie.test.ts src/consent/core/texts.test.ts src/consent/core/activate.test.ts src/consent/core/gcm.test.ts src/consent/core/contrast.test.ts src/consent/core/controller.test.ts src/consent/embed.test.ts src/consent/react.test.tsx src/consent/react-shown.test.tsx src/analytics/core.test.ts src/analytics/embed.test.ts src/analytics/instrument.test.tsx src/analytics/page-views.test.tsx src/analytics/visitor.test.ts src/components/checkout/visitor-header.test.ts src/components/products/impressions.test.ts src/components/products/ProductList.analytics.test.tsx src/components/checkout/cart-analytics.test.tsx src/components/checkout/apple-pay-analytics.test.tsx src/components/notifications/notifications-analytics.test.tsx src/components/returns/returns-analytics.test.tsx src/panel/panel-analytics.test.tsx src/course/course-analytics.test.tsx src/viewer3d/viewer3d.test.ts src/viewer3d/Model3DViewer.test.tsx src/panel/panel-products.test.tsx --format esm --out-dir .test-dist --no-config --external jsdom --silent && node --test --test-force-exit \".test-dist/**/*.test.mjs\"",
18
18
  "test:types": "tsc -p test/consumer/tsconfig.json",
19
19
  "test:package": "node test/consumer/verify-package.mjs"
20
20
  },
@@ -44,11 +44,15 @@
44
44
  "homepage": "https://github.com/emmems/bitsnap-react#readme",
45
45
  "devDependencies": {
46
46
  "@bufbuild/protoc-gen-es": "^2.10.0",
47
+ "@react-three/drei": "10.7.9",
48
+ "@react-three/fiber": "9.8.2",
47
49
  "@types/react": "^19.2.0",
48
50
  "@types/react-dom": "^19.2.0",
51
+ "@types/three": "0.187.0",
49
52
  "autoprefixer": "^10.4.20",
50
53
  "jsdom": "^30.1.3",
51
54
  "postcss": "^8.5.3",
55
+ "three": "0.187.0",
52
56
  "tsup": "^8.3.5",
53
57
  "typescript": "^5.6.3"
54
58
  },
@@ -101,7 +105,21 @@
101
105
  },
102
106
  "peerDependencies": {
103
107
  "react": "^19.2.0",
104
- "react-dom": "^19.2.0"
108
+ "react-dom": "^19.2.0",
109
+ "three": ">=0.160.0",
110
+ "@react-three/fiber": "^9.0.0",
111
+ "@react-three/drei": "^10.0.0"
112
+ },
113
+ "peerDependenciesMeta": {
114
+ "three": {
115
+ "optional": true
116
+ },
117
+ "@react-three/fiber": {
118
+ "optional": true
119
+ },
120
+ "@react-three/drei": {
121
+ "optional": true
122
+ }
105
123
  },
106
124
  "exports": {
107
125
  ".": {
@@ -198,6 +216,12 @@
198
216
  "default": "./dist/analytics.js"
199
217
  }
200
218
  },
219
+ "./viewer3d": {
220
+ "import": {
221
+ "types": "./dist/viewer3d.d.mts",
222
+ "default": "./dist/viewer3d.mjs"
223
+ }
224
+ },
201
225
  "./package.json": "./package.json"
202
226
  },
203
227
  "typesVersions": {
@@ -225,6 +249,9 @@
225
249
  ],
226
250
  "analytics": [
227
251
  "./dist/analytics.d.ts"
252
+ ],
253
+ "viewer3d": [
254
+ "./dist/viewer3d.d.mts"
228
255
  ]
229
256
  }
230
257
  }
@@ -1,2 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunk2OOQPXCQjs = require('./chunk-2OOQPXCQ.js');require('./chunk-GTOZ5BZX.js');require('./chunk-KOYBZORL.js');require('./chunk-5DBLZ3VL.js');require('./chunk-QQDZIVWY.js');var _chunkEJRI366Wjs = require('./chunk-EJRI366W.js');require('./chunk-PVJ2I46C.js');require('./chunk-W3RGQYPD.js');require('./chunk-JSDGZ4NY.js');exports.MARKETING_AGREEMENT_ID = _chunk2OOQPXCQjs.L; exports.bitsnapProjectID = _chunk2OOQPXCQjs.M; exports.default = _chunk2OOQPXCQjs.T; exports.getCartLines = _chunk2OOQPXCQjs.Q; exports.getCheckoutMethods = _chunk2OOQPXCQjs.U; exports.getCheckoutSelection = _chunk2OOQPXCQjs.P; exports.getLocale = _chunkEJRI366Wjs.m; exports.getProjectID = _chunk2OOQPXCQjs.O; exports.reconcileOrderOfLastPayment = _chunk2OOQPXCQjs.R; exports.setLocale = _chunkEJRI366Wjs.l; exports.setProjectID = _chunk2OOQPXCQjs.N; exports.useCartProvider = _chunk2OOQPXCQjs.S;
2
- //# sourceMappingURL=CartProvider-2RNAKU3U.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/emems/.t3/worktrees/bitsnap-react/dx/dist/CartProvider-2RNAKU3U.js"],"names":[],"mappings":"AAAA,+HAAsG,+BAA4B,+BAA4B,+BAA4B,+BAA4B,sDAA+C,+BAA4B,+BAA4B,+BAA4B,siBAAmQ","file":"/home/emems/.t3/worktrees/bitsnap-react/dx/dist/CartProvider-2RNAKU3U.js"}
@@ -1,2 +0,0 @@
1
- import{L as c,M as d,N as e,O as f,P as g,Q as h,R as i,S as j,T as k,U as l}from"./chunk-7WJSK6SJ.mjs";import"./chunk-4TZAGNEU.mjs";import"./chunk-KOVKUJAW.mjs";import"./chunk-FIWADPQX.mjs";import"./chunk-L7LZG6MR.mjs";import{l as a,m as b}from"./chunk-TBYY3RL2.mjs";import"./chunk-JZBU5SZJ.mjs";import"./chunk-MDCP5JNP.mjs";import"./chunk-U6FLIRIV.mjs";export{c as MARKETING_AGREEMENT_ID,d as bitsnapProjectID,k as default,h as getCartLines,l as getCheckoutMethods,g as getCheckoutSelection,b as getLocale,f as getProjectID,i as reconcileOrderOfLastPayment,a as setLocale,e as setProjectID,j as useCartProvider};
2
- //# sourceMappingURL=CartProvider-OSGG573S.mjs.map