bitsnap-react 1.15.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +8 -0
- package/README.md +132 -2
- package/dist/CartProvider-DGRZDTYC.mjs +2 -0
- package/dist/CartProvider-YVOHSMPE.js +2 -0
- package/dist/CartProvider-YVOHSMPE.js.map +1 -0
- package/dist/PanelModelFiles-NYCOFPLY.js +2 -0
- package/dist/PanelModelFiles-NYCOFPLY.js.map +1 -0
- package/dist/PanelModelFiles-RV7OHUUZ.mjs +2 -0
- package/dist/PanelModelFiles-RV7OHUUZ.mjs.map +1 -0
- package/dist/Viewer3D-2IDEH6W3.mjs +2 -0
- package/dist/Viewer3D-2IDEH6W3.mjs.map +1 -0
- package/dist/analytics.d.mts +2 -2
- package/dist/analytics.d.ts +2 -2
- package/dist/analytics.js +1 -1
- package/dist/analytics.js.map +1 -1
- package/dist/analytics.mjs +1 -1
- package/dist/catalog.d.mts +6 -2
- package/dist/catalog.d.ts +6 -2
- package/dist/catalog.js +1 -1
- package/dist/catalog.js.map +1 -1
- package/dist/catalog.mjs +1 -1
- package/dist/chunk-2NL5FCXC.mjs +4 -0
- package/dist/chunk-2NL5FCXC.mjs.map +1 -0
- package/dist/{chunk-PEVB3VL4.mjs → chunk-2UDAB2C5.mjs} +2 -2
- package/dist/{chunk-PEVB3VL4.mjs.map → chunk-2UDAB2C5.mjs.map} +1 -1
- package/dist/{chunk-7DG4UPWE.js → chunk-4BL7TLK3.js} +2 -2
- package/dist/chunk-4BL7TLK3.js.map +1 -0
- package/dist/chunk-4ETIDGYZ.mjs +2 -0
- package/dist/chunk-4ETIDGYZ.mjs.map +1 -0
- package/dist/chunk-555KFWGY.js +4 -0
- package/dist/chunk-555KFWGY.js.map +1 -0
- package/dist/chunk-5ED7FWNY.mjs +2 -0
- package/dist/chunk-5ED7FWNY.mjs.map +1 -0
- package/dist/chunk-5FZAROP6.js +2 -0
- package/dist/chunk-5FZAROP6.js.map +1 -0
- package/dist/chunk-5R6AGO3Z.mjs +2 -0
- package/dist/chunk-5R6AGO3Z.mjs.map +1 -0
- package/dist/chunk-6GCCNBEU.js +2 -0
- package/dist/chunk-6GCCNBEU.js.map +1 -0
- package/dist/chunk-6Q3VGPSF.js +2 -0
- package/dist/chunk-6Q3VGPSF.js.map +1 -0
- package/dist/chunk-6YIRRDCL.mjs +2 -0
- package/dist/chunk-6YIRRDCL.mjs.map +1 -0
- package/dist/chunk-7RXW6XFY.js +2 -0
- package/dist/chunk-7RXW6XFY.js.map +1 -0
- package/dist/chunk-A6VCP3A4.mjs +2 -0
- package/dist/chunk-A6VCP3A4.mjs.map +1 -0
- package/dist/chunk-BZXV77PT.mjs +2 -0
- package/dist/chunk-BZXV77PT.mjs.map +1 -0
- package/dist/{chunk-MG6VV5J2.js → chunk-C3BBJOVV.js} +2 -2
- package/dist/chunk-C3BBJOVV.js.map +1 -0
- package/dist/chunk-CUPG4B5W.mjs +2 -0
- package/dist/chunk-CUPG4B5W.mjs.map +1 -0
- package/dist/chunk-ESF5ZVVF.js +2 -0
- package/dist/chunk-ESF5ZVVF.js.map +1 -0
- package/dist/chunk-HKNWW37T.mjs +2 -0
- package/dist/chunk-HKNWW37T.mjs.map +1 -0
- package/dist/chunk-JSDGZ4NY.js.map +1 -1
- package/dist/chunk-KOYBZORL.js.map +1 -1
- package/dist/chunk-L7Q7OKM5.mjs +2 -0
- package/dist/chunk-L7Q7OKM5.mjs.map +1 -0
- package/dist/chunk-M2G74N43.mjs +2 -0
- package/dist/chunk-M2G74N43.mjs.map +1 -0
- package/dist/chunk-MIMQTH2G.js +2 -0
- package/dist/chunk-MIMQTH2G.js.map +1 -0
- package/dist/chunk-SYN5KU3O.js +2 -0
- package/dist/chunk-SYN5KU3O.js.map +1 -0
- package/dist/chunk-VNYHJT6V.mjs +2 -0
- package/dist/chunk-VNYHJT6V.mjs.map +1 -0
- package/dist/chunk-W3RGQYPD.js.map +1 -1
- package/dist/chunk-X3LVYIJR.mjs +2 -0
- package/dist/chunk-X3LVYIJR.mjs.map +1 -0
- package/dist/consent.js.map +1 -1
- package/dist/course.d.mts +3 -3
- package/dist/course.d.ts +3 -3
- package/dist/course.js +1 -1
- package/dist/course.js.map +1 -1
- package/dist/course.mjs +1 -1
- package/dist/course.mjs.map +1 -1
- package/dist/embed/analytics.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +41 -12
- package/dist/index.d.ts +41 -12
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/{instrument-BE8ktMUv.d.mts → instrument-eXaC8hc2.d.mts} +1 -1
- package/dist/{instrument-BE8ktMUv.d.ts → instrument-eXaC8hc2.d.ts} +1 -1
- package/dist/internal.js.map +1 -1
- package/dist/methods-3W34GRYL.js +2 -0
- package/dist/methods-3W34GRYL.js.map +1 -0
- package/dist/methods-LUJSKSQ4.mjs +2 -0
- package/dist/model-files-client-HHDXJDTS.mjs +2 -0
- package/dist/model-files-client-HHDXJDTS.mjs.map +1 -0
- package/dist/model-files-client-P4PORZJ6.js +2 -0
- package/dist/model-files-client-P4PORZJ6.js.map +1 -0
- package/dist/models.d.mts +2 -0
- package/dist/models.d.ts +2 -0
- package/dist/models.js +1 -1
- package/dist/models.js.map +1 -1
- package/dist/models.mjs +1 -1
- package/dist/models.mjs.map +1 -1
- package/dist/returns.d.mts +19 -10
- package/dist/returns.d.ts +19 -10
- package/dist/returns.js +1 -1
- package/dist/returns.js.map +1 -1
- package/dist/returns.mjs +1 -1
- package/dist/{texts-tQtAGJCT.d.mts → texts-LGhuQfA9.d.mts} +28 -3
- package/dist/{texts-CIEFbJTN.d.ts → texts-m6XQGZ6w.d.ts} +28 -3
- package/dist/types-ClFCVzk_.d.ts +121 -0
- package/dist/types-D6LsoycW.d.mts +121 -0
- package/dist/viewer3d.css +2 -0
- package/dist/viewer3d.css.map +1 -0
- package/dist/viewer3d.d.mts +318 -0
- package/dist/viewer3d.d.ts +318 -0
- package/dist/viewer3d.js +2 -0
- package/dist/viewer3d.js.map +1 -0
- package/dist/viewer3d.mjs +63 -0
- package/dist/viewer3d.mjs.map +1 -0
- package/package.json +43 -16
- package/dist/CartProvider-64QEJ7A7.js +0 -2
- package/dist/CartProvider-64QEJ7A7.js.map +0 -1
- package/dist/CartProvider-XKK7A3C2.mjs +0 -2
- package/dist/chunk-2TLWMYXW.mjs +0 -2
- package/dist/chunk-2TLWMYXW.mjs.map +0 -1
- package/dist/chunk-7DG4UPWE.js.map +0 -1
- package/dist/chunk-7TLJKYZD.mjs +0 -2
- package/dist/chunk-7TLJKYZD.mjs.map +0 -1
- package/dist/chunk-AZQOW73L.mjs +0 -4
- package/dist/chunk-AZQOW73L.mjs.map +0 -1
- package/dist/chunk-DY2S42Q6.js +0 -2
- package/dist/chunk-DY2S42Q6.js.map +0 -1
- package/dist/chunk-FGB5FJCI.js +0 -2
- package/dist/chunk-FGB5FJCI.js.map +0 -1
- package/dist/chunk-GLAJPUMA.js +0 -2
- package/dist/chunk-GLAJPUMA.js.map +0 -1
- package/dist/chunk-H4WAQQVO.js +0 -2
- package/dist/chunk-H4WAQQVO.js.map +0 -1
- package/dist/chunk-MG6VV5J2.js.map +0 -1
- package/dist/chunk-Q3DSK66F.mjs +0 -2
- package/dist/chunk-Q3DSK66F.mjs.map +0 -1
- package/dist/chunk-RWEP6IUC.mjs +0 -2
- package/dist/chunk-RWEP6IUC.mjs.map +0 -1
- package/dist/chunk-S4Z4O46O.mjs +0 -2
- package/dist/chunk-S4Z4O46O.mjs.map +0 -1
- package/dist/chunk-VY6CZVVA.js +0 -4
- package/dist/chunk-VY6CZVVA.js.map +0 -1
- package/dist/chunk-XZYCQ655.js +0 -2
- package/dist/chunk-XZYCQ655.js.map +0 -1
- package/dist/chunk-ZIWQ57GY.mjs +0 -2
- package/dist/chunk-ZIWQ57GY.mjs.map +0 -1
- package/dist/methods-NUMVR53L.js +0 -2
- package/dist/methods-NUMVR53L.js.map +0 -1
- package/dist/methods-YKZZ6OVT.mjs +0 -2
- package/dist/types-DP1vxo5E.d.mts +0 -53
- package/dist/types-u8VwmC3j.d.ts +0 -53
- /package/dist/{CartProvider-XKK7A3C2.mjs.map → CartProvider-DGRZDTYC.mjs.map} +0 -0
- /package/dist/{methods-YKZZ6OVT.mjs.map → methods-LUJSKSQ4.mjs.map} +0 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode, CSSProperties, ComponentType } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* What the 3D viewer needs about one ready model. The Bitsnap backend sends it
|
|
6
|
+
* as `model3d` on a product and on each variant of
|
|
7
|
+
* `GET /api/integrations/{projectID}/public-commerce/products?include=model3d`.
|
|
8
|
+
* Public data only: no keys, no asset id, never the original file.
|
|
9
|
+
*/
|
|
10
|
+
type Model3DUnit = "meters" | "centimeters" | "millimeters" | "inches";
|
|
11
|
+
type Model3DFacts = {
|
|
12
|
+
/** Bytes of the original file. */
|
|
13
|
+
fileSize: number;
|
|
14
|
+
triangleCount: number;
|
|
15
|
+
/** x, y, z in millimetres; empty when unknown. */
|
|
16
|
+
dimensionsMm: number[];
|
|
17
|
+
/** The unit the merchant made the model in; dimensions are shown in it. */
|
|
18
|
+
unit: Model3DUnit;
|
|
19
|
+
};
|
|
20
|
+
type Model3DView = {
|
|
21
|
+
/** Display copy (GLB) on the Bitsnap file host. */
|
|
22
|
+
previewUrl: string;
|
|
23
|
+
/** Bytes of the display copy; over 10 MB it loads only on a click. */
|
|
24
|
+
previewSize: number;
|
|
25
|
+
thumbnailUrl?: string;
|
|
26
|
+
/** The product does not sell the file: the viewer shows the "illustrative" note. */
|
|
27
|
+
illustrative: boolean;
|
|
28
|
+
/** Only when the merchant turned the model facts on. */
|
|
29
|
+
facts?: Model3DFacts;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The public product data the 3D viewer reads:
|
|
34
|
+
* `GET {host}/api/integrations/{projectID}/public-commerce/products?ids=…&include=model3d`,
|
|
35
|
+
* the endpoint the cart already uses. Servers without 3D support ignore
|
|
36
|
+
* `include` and send no `model3d`: the viewer then shows nothing.
|
|
37
|
+
*/
|
|
38
|
+
type Product3DVariant = {
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
/** Minor units (grosze, cents). */
|
|
42
|
+
price: number;
|
|
43
|
+
currency: string;
|
|
44
|
+
availableQuantity?: number;
|
|
45
|
+
priceType?: string;
|
|
46
|
+
model3d?: Model3DView;
|
|
47
|
+
};
|
|
48
|
+
type Product3DProduct = {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
price: number;
|
|
52
|
+
currency: string;
|
|
53
|
+
availableQuantity?: number;
|
|
54
|
+
priceType?: string;
|
|
55
|
+
recurring?: unknown;
|
|
56
|
+
model3d?: Model3DView;
|
|
57
|
+
variants?: Product3DVariant[];
|
|
58
|
+
};
|
|
59
|
+
type Product3DQuery = {
|
|
60
|
+
projectID: string;
|
|
61
|
+
/** Origin of the Bitsnap backend (or of a custom domain), without a path. */
|
|
62
|
+
host: string;
|
|
63
|
+
productId: string;
|
|
64
|
+
locale?: string;
|
|
65
|
+
};
|
|
66
|
+
declare class Product3DError extends Error {
|
|
67
|
+
readonly status: number | undefined;
|
|
68
|
+
constructor(message: string, status?: number);
|
|
69
|
+
}
|
|
70
|
+
declare function buildProduct3DURL(query: Product3DQuery): string;
|
|
71
|
+
/**
|
|
72
|
+
* The model to show: the chosen variant's (the server already gives a variant
|
|
73
|
+
* the product's model when it has none of its own), else the product's, else
|
|
74
|
+
* the first variant with one. A chosen variant without a model shows none.
|
|
75
|
+
*/
|
|
76
|
+
declare function resolveModel(product: Product3DProduct, variantId?: string): Model3DView | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Loads the product with a credential-less `fetch`, once per URL per page
|
|
79
|
+
* (several viewers of one product share the request). A failed request is
|
|
80
|
+
* forgotten so a retry asks again.
|
|
81
|
+
*/
|
|
82
|
+
declare function fetchProduct3D(query: Product3DQuery): Promise<Product3DProduct[]>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Every string of the 3D viewer. Polish is the default, English for `en*`
|
|
86
|
+
* locales; pass `texts` to `Product3DViewer` to override any of them.
|
|
87
|
+
*/
|
|
88
|
+
type Viewer3DCopy = {
|
|
89
|
+
sectionLabel: string;
|
|
90
|
+
show: (size: string) => string;
|
|
91
|
+
heroPill: string;
|
|
92
|
+
heroPillWithSize: (size: string) => string;
|
|
93
|
+
loading: string;
|
|
94
|
+
loadingProgress: (percent: number) => string;
|
|
95
|
+
error: string;
|
|
96
|
+
retry: string;
|
|
97
|
+
unsupported: string;
|
|
98
|
+
hintDrag: string;
|
|
99
|
+
hintTap: string;
|
|
100
|
+
touchDone: string;
|
|
101
|
+
reset: string;
|
|
102
|
+
fullscreen: string;
|
|
103
|
+
closeFullscreen: string;
|
|
104
|
+
disclaimer: string;
|
|
105
|
+
report: string;
|
|
106
|
+
factsTitle: string;
|
|
107
|
+
factsFormat: string;
|
|
108
|
+
factsFileSize: string;
|
|
109
|
+
factsTriangles: string;
|
|
110
|
+
factsDimensions: string;
|
|
111
|
+
triangles: (count: string) => string;
|
|
112
|
+
licence: string;
|
|
113
|
+
licenceShow: string;
|
|
114
|
+
licenceOpen: string;
|
|
115
|
+
licenceClose: string;
|
|
116
|
+
licenceDefaultName: string;
|
|
117
|
+
units: Record<Model3DUnit, string>;
|
|
118
|
+
/** Fullscreen bar: add to the cart. */
|
|
119
|
+
addToCart: string;
|
|
120
|
+
addingToCart: string;
|
|
121
|
+
addedToCart: string;
|
|
122
|
+
addToCartError: string;
|
|
123
|
+
};
|
|
124
|
+
declare const VIEWER3D_COPY_PL: Viewer3DCopy;
|
|
125
|
+
declare const VIEWER3D_COPY_EN: Viewer3DCopy;
|
|
126
|
+
|
|
127
|
+
type Viewer3DProps = {
|
|
128
|
+
url: string;
|
|
129
|
+
/** Draco decoder folder; default: three's decoder on jsDelivr for the installed revision. */
|
|
130
|
+
decoderPath?: string;
|
|
131
|
+
/** Bytes the server reported; the progress total when the response has none. */
|
|
132
|
+
expectedSize: number;
|
|
133
|
+
/** Bumped by the shell on retry; a failed download is not reused. */
|
|
134
|
+
attempt: number;
|
|
135
|
+
/** Rotation may run: on screen, tab visible, no reduced motion. */
|
|
136
|
+
motionAllowed: boolean;
|
|
137
|
+
/** The buyer can drag (on a phone only after a tap, so the page scrolls). */
|
|
138
|
+
interactive: boolean;
|
|
139
|
+
/** Wheel and pinch zoom: full screen and active touch only, so the page keeps its scroll. */
|
|
140
|
+
allowZoom: boolean;
|
|
141
|
+
/** Bumped by "Reset widoku". */
|
|
142
|
+
resetSignal: number;
|
|
143
|
+
onProgress: (loaded: number, total: number) => void;
|
|
144
|
+
/** The first frame with the model is on screen. */
|
|
145
|
+
onLoaded: () => void;
|
|
146
|
+
onError: (error: unknown) => void;
|
|
147
|
+
/** The buyer dragged or zoomed (hides the gesture hint). */
|
|
148
|
+
onInteract: () => void;
|
|
149
|
+
className?: string;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/** Theme of the viewer; each value sets one `--bitsnap-viewer3d-*` property. */
|
|
153
|
+
type Viewer3DAppearance = {
|
|
154
|
+
background?: string;
|
|
155
|
+
foreground?: string;
|
|
156
|
+
muted?: string;
|
|
157
|
+
border?: string;
|
|
158
|
+
accent?: string;
|
|
159
|
+
radius?: string;
|
|
160
|
+
};
|
|
161
|
+
type Model3DViewerProps = {
|
|
162
|
+
model: Model3DView;
|
|
163
|
+
/** The product name: the alt text of the poster. */
|
|
164
|
+
productName: string;
|
|
165
|
+
/** `pl-PL` (default) or an `en*` locale. */
|
|
166
|
+
locale?: string;
|
|
167
|
+
/** Overrides of any viewer string. */
|
|
168
|
+
texts?: Partial<Viewer3DCopy>;
|
|
169
|
+
appearance?: Viewer3DAppearance;
|
|
170
|
+
/**
|
|
171
|
+
* Draco decoder folder (trailing slash). Default: three's decoder files on
|
|
172
|
+
* jsDelivr for the installed `three` revision.
|
|
173
|
+
*/
|
|
174
|
+
decoderPath?: string;
|
|
175
|
+
/**
|
|
176
|
+
* "Report this model" link (DSA notice form); the viewer adds the page URL
|
|
177
|
+
* as `url`. Absent = no link.
|
|
178
|
+
*/
|
|
179
|
+
reportHref?: string;
|
|
180
|
+
/** Bump to start loading now, whatever the size (e.g. from a "View in 3D" button). */
|
|
181
|
+
startSignal?: number;
|
|
182
|
+
/**
|
|
183
|
+
* The bar at the bottom of the full screen view (name, price, buy button).
|
|
184
|
+
* `close` leaves full screen. Absent = no bar.
|
|
185
|
+
*/
|
|
186
|
+
renderFullscreenBar?: (args: {
|
|
187
|
+
close: () => void;
|
|
188
|
+
}) => ReactNode;
|
|
189
|
+
/** Hide the notes under the viewer (disclaimer, report link, model facts). */
|
|
190
|
+
hideNotes?: boolean;
|
|
191
|
+
id?: string;
|
|
192
|
+
className?: string;
|
|
193
|
+
style?: CSSProperties;
|
|
194
|
+
/** @internal Tests replace the three viewer. */
|
|
195
|
+
loadViewer?: () => Promise<{
|
|
196
|
+
default: ComponentType<Viewer3DProps>;
|
|
197
|
+
}>;
|
|
198
|
+
};
|
|
199
|
+
/**
|
|
200
|
+
* The 3D viewer of one model, without data fetching (see `Product3DViewer`
|
|
201
|
+
* for the product-id version). No three import: the poster, the states and
|
|
202
|
+
* the controls live here; `Viewer3D` is loaded with `import()` in an effect
|
|
203
|
+
* once the model may load, so the server render and the page's main chunk
|
|
204
|
+
* never touch three.
|
|
205
|
+
*/
|
|
206
|
+
declare function Model3DViewer({ model, productName, locale, texts, appearance, decoderPath, reportHref, startSignal, renderFullscreenBar, hideNotes, id, className, style, loadViewer, }: Model3DViewerProps): react_jsx_runtime.JSX.Element;
|
|
207
|
+
|
|
208
|
+
type UseProduct3DModelOptions = {
|
|
209
|
+
/**
|
|
210
|
+
* Project (shop) ID. Defaults to the one set with `setProjectID` from
|
|
211
|
+
* `bitsnap-react`.
|
|
212
|
+
*/
|
|
213
|
+
projectID?: string;
|
|
214
|
+
/**
|
|
215
|
+
* Origin of the Bitsnap backend. Defaults to the library host
|
|
216
|
+
* (`https://bitsnap.pl`, or what `setCustomHost` had set). On a custom
|
|
217
|
+
* domain pass the domain itself, or `""` for same-origin requests.
|
|
218
|
+
*/
|
|
219
|
+
host?: string;
|
|
220
|
+
/** Locale of the product name. Defaults to the library locale. */
|
|
221
|
+
locale?: string;
|
|
222
|
+
};
|
|
223
|
+
type Product3DStatus =
|
|
224
|
+
/** Waiting for the product (also on the server and the first render). */
|
|
225
|
+
"loading"
|
|
226
|
+
/** `model` is set. */
|
|
227
|
+
| "ready"
|
|
228
|
+
/** The product (or the chosen variant) has no 3D model, or the server has no 3D support. */
|
|
229
|
+
| "none"
|
|
230
|
+
/** The product could not be loaded; `retry()` asks again. */
|
|
231
|
+
| "error";
|
|
232
|
+
type UseProduct3DModelResult = {
|
|
233
|
+
status: Product3DStatus;
|
|
234
|
+
model?: Model3DView;
|
|
235
|
+
/** The product as the public endpoint sent it (name, price, variants). */
|
|
236
|
+
product?: Product3DProduct;
|
|
237
|
+
/** The chosen variant, when `variantId` matches one. */
|
|
238
|
+
variant?: Product3DVariant;
|
|
239
|
+
error?: Error;
|
|
240
|
+
retry: () => void;
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
243
|
+
* The public 3D model of a product (and variant). Fetches in the browser
|
|
244
|
+
* only; switching `variantId` does not fetch again.
|
|
245
|
+
*/
|
|
246
|
+
declare function useProduct3DModel(productId: string, variantId?: string, options?: UseProduct3DModelOptions): UseProduct3DModelResult;
|
|
247
|
+
|
|
248
|
+
type Product3DBuyBarArgs = {
|
|
249
|
+
product: Product3DProduct;
|
|
250
|
+
variant?: Product3DVariant;
|
|
251
|
+
/** Leaves full screen (e.g. before the page shows its own error or dialog). */
|
|
252
|
+
close: () => void;
|
|
253
|
+
};
|
|
254
|
+
type Product3DViewerProps = UseProduct3DModelOptions & Omit<Model3DViewerProps, "model" | "productName" | "renderFullscreenBar" | "loadViewer"> & {
|
|
255
|
+
/** Bitsnap product ID (`prodv2_…`), or a variant ID. */
|
|
256
|
+
productId: string;
|
|
257
|
+
/** The variant the page shows; switching it swaps the model in place. */
|
|
258
|
+
variantId?: string;
|
|
259
|
+
/**
|
|
260
|
+
* The bar of the full screen view. Default: name, price and an
|
|
261
|
+
* "Add to cart" button that uses the Bitsnap cart (loaded on the first
|
|
262
|
+
* click). Return `null` for no bar.
|
|
263
|
+
*/
|
|
264
|
+
renderBuyBar?: (args: Product3DBuyBarArgs) => ReactNode;
|
|
265
|
+
/** Rendered while loading, when there is no model, and on error. Default: nothing. */
|
|
266
|
+
fallback?: ReactNode;
|
|
267
|
+
/** Product page URL stored with the cart item (default buy bar). */
|
|
268
|
+
productUrl?: string;
|
|
269
|
+
/** Called after the default buy bar added the product. */
|
|
270
|
+
onAddedToCart?: (args: {
|
|
271
|
+
product: Product3DProduct;
|
|
272
|
+
variant?: Product3DVariant;
|
|
273
|
+
}) => void;
|
|
274
|
+
/** @internal Tests replace the three viewer. */
|
|
275
|
+
loadViewer?: Model3DViewerProps["loadViewer"];
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* The 3D viewer of a Bitsnap product: loads the product's public model and
|
|
279
|
+
* shows it (auto-rotate, click-to-load over 10 MB, reduced motion, full screen
|
|
280
|
+
* with a buy bar, gesture hint). Renders `fallback` (nothing by default) when
|
|
281
|
+
* the product has no ready model or the server has no 3D support.
|
|
282
|
+
*
|
|
283
|
+
* Needs the optional peer dependencies `three`, `@react-three/fiber` and
|
|
284
|
+
* `@react-three/drei`; they load only once the model may be shown.
|
|
285
|
+
*/
|
|
286
|
+
declare function Product3DViewer({ productId, variantId, projectID, host, locale, renderBuyBar, fallback, productUrl, onAddedToCart, ...viewer }: Product3DViewerProps): react_jsx_runtime.JSX.Element;
|
|
287
|
+
/** Whether the default bar may add the item straight to the cart. */
|
|
288
|
+
declare function isCartable(product: Product3DProduct, variant: Product3DVariant | undefined): boolean;
|
|
289
|
+
/** The cart id: the chosen variant, else the first (default) variant, else the product. */
|
|
290
|
+
declare function cartItemIdFor(product: Product3DProduct, variant: Product3DVariant | undefined): string;
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Shared numbers of the 3D viewer. No three import: the shell, the hook and
|
|
294
|
+
* the tests use them.
|
|
295
|
+
*/
|
|
296
|
+
/**
|
|
297
|
+
* Display copies up to this size load on their own when the viewer scrolls
|
|
298
|
+
* into view; bigger ones wait for "Pokaż model 3D (24 MB)".
|
|
299
|
+
*/
|
|
300
|
+
declare const AUTO_LOAD_MAX_BYTES: number;
|
|
301
|
+
/** True when the model must wait for the buyer's click. */
|
|
302
|
+
declare function needsClickToLoad(previewSize: number): boolean;
|
|
303
|
+
/**
|
|
304
|
+
* Default Draco decoder: three's own decoder files on jsDelivr, for the
|
|
305
|
+
* `three` revision the page has installed (`REVISION` "187" → three@0.187.0),
|
|
306
|
+
* so the decoder always matches the loader. jsDelivr answers with
|
|
307
|
+
* `Access-Control-Allow-Origin: *`, which the decoder worker needs on any
|
|
308
|
+
* domain. Pass `decoderPath` to self-host (copy
|
|
309
|
+
* `three/examples/jsm/libs/draco/gltf/` to your site, e.g. `/draco/`).
|
|
310
|
+
*/
|
|
311
|
+
declare function defaultDecoderPath(revision: string): string;
|
|
312
|
+
/**
|
|
313
|
+
* "24 MB", "4,2 MB", "820 kB": the size the click-to-load button shows.
|
|
314
|
+
* Decimal for small values only, in the locale's style.
|
|
315
|
+
*/
|
|
316
|
+
declare function formatModelSize(bytes: number, locale?: string): string;
|
|
317
|
+
|
|
318
|
+
export { AUTO_LOAD_MAX_BYTES, type Model3DFacts, type Model3DUnit, type Model3DView, Model3DViewer, type Model3DViewerProps, type Product3DBuyBarArgs, Product3DError, type Product3DProduct, type Product3DStatus, type Product3DVariant, Product3DViewer, type Product3DViewerProps, type UseProduct3DModelOptions, type UseProduct3DModelResult, VIEWER3D_COPY_EN, VIEWER3D_COPY_PL, type Viewer3DAppearance, type Viewer3DCopy, buildProduct3DURL, cartItemIdFor, defaultDecoderPath, fetchProduct3D, formatModelSize, isCartable, needsClickToLoad, resolveModel, useProduct3DModel };
|
package/dist/viewer3d.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkJSDGZ4NYjs = require('./chunk-JSDGZ4NY.js');var e=_chunkJSDGZ4NYjs.a.call(void 0, ()=>{throw new Error("bitsnap-react/viewer3d is ESM only: use import, not require")});exports. default = e();
|
|
2
|
+
//# sourceMappingURL=viewer3d.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/emems/web/bitsnap/bitsnap/bitsnap-react/dist/viewer3d.js","../src/viewer3d/index.ts"],"names":["require_viewer3d","__commonJSMin"],"mappings":"AAAA,+HAAuC,ICAvCA,CAAAA,CAAAC,gCAAAA,CAAA,CAAA,EAAA,CAAA,MAAM,IAAI,KAAA,CAAM,6DAA6D,CAAA,CAAA,CAAA,CAAA,SAAA,UAAA,CAAA,CAAA,CAAA","file":"/home/emems/web/bitsnap/bitsnap/bitsnap-react/dist/viewer3d.js","sourcesContent":[null,"throw new Error(\"bitsnap-react/viewer3d is ESM only: use import, not require\");"]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import{a as it,b as oe,e as xe,g as st,h as O}from"./chunk-5ED7FWNY.mjs";import{e as De,f as Pe}from"./chunk-M2G74N43.mjs";import{b as _}from"./chunk-CUPG4B5W.mjs";import{c as he,e as j}from"./chunk-X3LVYIJR.mjs";import"./chunk-2UDAB2C5.mjs";import{f as we}from"./chunk-VNYHJT6V.mjs";import"./chunk-MDCP5JNP.mjs";import"./chunk-U6FLIRIV.mjs";import{useState as Mt}from"react";var Se={sectionLabel:"Model 3D",show:e=>`Poka\u017C model 3D (${e})`,heroPill:"Zobacz w 3D",heroPillWithSize:e=>`Zobacz w 3D (${e})`,loading:"Wczytywanie modelu 3D\u2026",loadingProgress:e=>`Wczytywanie modelu 3D: ${e}%`,error:"Nie uda\u0142o si\u0119 wczyta\u0107 modelu 3D",retry:"Spr\xF3buj ponownie",unsupported:"Ta przegl\u0105darka nie wy\u015Bwietli modelu 3D.",hintDrag:"Przeci\u0105gnij, aby obr\xF3ci\u0107",hintTap:"Dotknij, aby obraca\u0107",touchDone:"Gotowe",reset:"Reset widoku",fullscreen:"Pe\u0142ny ekran",closeFullscreen:"Zamknij pe\u0142ny ekran",disclaimer:"Model 3D jest pogl\u0105dowy; kolory i detale mog\u0105 si\u0119 r\xF3\u017Cni\u0107 od produktu.",report:"Zg\u0142o\u015B ten model",factsTitle:"Szczeg\xF3\u0142y modelu",factsFormat:"Format",factsFileSize:"Rozmiar pliku",factsTriangles:"Tr\xF3jk\u0105ty",factsDimensions:"Wymiary",triangles:e=>e,licence:"Licencja",licenceShow:"Warunki licencji",licenceOpen:"Otw\xF3rz licencj\u0119",licenceClose:"Zamknij",licenceDefaultName:"Licencja sprzedawcy",units:{meters:"m",centimeters:"cm",millimeters:"mm",inches:"in"},addToCart:"Dodaj do koszyka",addingToCart:"Dodawanie\u2026",addedToCart:"Dodano do koszyka",addToCartError:"Nie uda\u0142o si\u0119 doda\u0107 do koszyka. Spr\xF3buj ponownie."},Ee={sectionLabel:"3D model",show:e=>`Show 3D model (${e})`,heroPill:"View in 3D",heroPillWithSize:e=>`View in 3D (${e})`,loading:"Loading the 3D model\u2026",loadingProgress:e=>`Loading the 3D model: ${e}%`,error:"The 3D model could not be loaded",retry:"Try again",unsupported:"This browser cannot show the 3D model.",hintDrag:"Drag to rotate",hintTap:"Tap to rotate",touchDone:"Done",reset:"Reset view",fullscreen:"Full screen",closeFullscreen:"Close full screen",disclaimer:"The 3D model is illustrative; colours and details may differ from the product.",report:"Report this model",factsTitle:"Model details",factsFormat:"Format",factsFileSize:"File size",factsTriangles:"Triangles",factsDimensions:"Dimensions",triangles:e=>e,licence:"Licence",licenceShow:"Licence terms",licenceOpen:"Open the licence",licenceClose:"Close",licenceDefaultName:"Seller's licence",units:{meters:"m",centimeters:"cm",millimeters:"mm",inches:"in"},addToCart:"Add to cart",addingToCart:"Adding\u2026",addedToCart:"Added to cart",addToCartError:"Could not add to the cart. Try again."};function H(e,t){let r=e?.toLowerCase().startsWith("en")?Ee:Se;return t?{...r,...t}:r}function z(e){return e?.toLowerCase().startsWith("en")?"en-GB":"pl-PL"}import{Box as _e,Hand as Ae,Maximize2 as pt,Rotate3d as mt,RotateCcw as Ue,X as ft}from"lucide-react";import{useCallback as W,useEffect as h,useId as gt,useReducer as bt,useRef as ie,useState as P}from"react";import{createPortal as vt}from"react-dom";var at={meters:1e3,centimeters:10,millimeters:1,inches:25.4};function dt(e,t,r,o){if(e.length!==3)return;let i=new Intl.NumberFormat(z(o),{maximumFractionDigits:t==="millimeters"?0:2}),m=at[t]??1e3;return`${e.map(a=>i.format(a/m)).join(" \xD7 ")} ${r.units[t]}`}function ke(e,t,r){let o=[{label:t.factsFormat,value:"GLB"}];e.fileSize>0&&o.push({label:t.factsFileSize,value:O(e.fileSize,z(r))}),e.triangleCount>0&&o.push({label:t.factsTriangles,value:t.triangles(new Intl.NumberFormat(z(r)).format(e.triangleCount))});let i=dt(e.dimensionsMm,e.unit,t,r);return i&&o.push({label:t.factsDimensions,value:i}),o}import{useCallback as Me,useEffect as B,useRef as lt,useState as ct}from"react";function ut(e){return e!=null&&typeof e.requestFullscreen=="function"&&document.fullscreenEnabled===!0}function Ve(e){let[t,r]=ct(null),o=lt(0),i=Me(()=>{if(document.fullscreenElement!=null){document.exitFullscreen().catch(()=>r(null));return}r(null)},[]),m=Me(()=>{let a=e.current;if(o.current=window.scrollY,ut(a)){a.requestFullscreen({navigationUI:"hide"}).then(()=>r("native")).catch(()=>r("overlay"));return}r("overlay")},[e]);return B(()=>{let a=()=>{document.fullscreenElement==null&&r(d=>d==="native"?null:d)};return document.addEventListener("fullscreenchange",a),()=>document.removeEventListener("fullscreenchange",a)},[]),B(()=>{if(t!=="native")return;let a=d=>{d.key==="Escape"&&document.fullscreenElement!=null&&document.exitFullscreen().catch(()=>r(null))};return window.addEventListener("keydown",a),()=>window.removeEventListener("keydown",a)},[t]),B(()=>{if(t!=="overlay")return;let{body:a,documentElement:d}=document,p={overflow:a.style.overflow,rootOverflow:d.style.overflow};a.style.overflow="hidden",d.style.overflow="hidden";let f=u=>{u.key==="Escape"&&r(null)};return window.addEventListener("keydown",f),()=>{window.removeEventListener("keydown",f),a.style.overflow=p.overflow,d.style.overflow=p.rootOverflow}},[t]),B(()=>{if(t==null&&o.current>0){let a=o.current;o.current=0,requestAnimationFrame(()=>window.scrollTo({top:a,behavior:"instant"}))}},[t]),{mode:t,isFullscreen:t!=null,enter:m,exit:i}}var Ce="bitsnap:viewer3d:gesture-hint-seen";function Te(){try{return typeof window>"u"?void 0:window.localStorage}catch{return}}function Re(e=Te()){try{return e?.getItem(Ce)==="1"}catch{return!1}}function Le(e=Te()){try{e?.setItem(Ce,"1")}catch{}}function Ne(e,t){return oe(e.size)?"awaiting-click":t?"loading":"poster"}function $e(e){return{status:Ne(e,!1),model:e,progress:0,attempt:0}}function ze(e,t){switch(t.type){case"NO_WEBGL":return e.status==="ready"?e:{...e,status:"unsupported"};case"VISIBLE":return e.status==="poster"?{...e,status:"loading",progress:0}:e;case"REQUEST":return e.status==="poster"||e.status==="awaiting-click"?{...e,status:"loading",progress:0}:e.status==="error"?{...e,status:"loading",progress:0,attempt:e.attempt+1}:e;case"RETRY":return e.status==="error"?{...e,status:"loading",progress:0,attempt:e.attempt+1}:e;case"PROGRESS":{if(e.status!=="loading"||t.key!==e.model.key)return e;let r=t.total>0?Math.min(1,Math.max(0,t.loaded/t.total)):0;return r===e.progress?e:{...e,progress:r}}case"LOADED":return e.status!=="loading"||t.key!==e.model.key?e:{...e,status:"ready",progress:1};case"FAILED":return e.status!=="loading"||t.key!==e.model.key?e:{...e,status:"error"};case"MODEL_CHANGED":return t.model.key===e.model.key?t.model.size===e.model.size?e:{...e,model:t.model}:e.status==="unsupported"?{...e,model:t.model}:{status:Ne(t.model,t.visible),model:t.model,progress:0,attempt:0}}}function Fe(e){return e==="loading"||e==="ready"}var Ie="bitsnap-react-viewer3d",T="[data-bitsnap-viewer3d]",k="var(--bitsnap-viewer3d-background,#ffffff)",g="var(--bitsnap-viewer3d-foreground,#171717)",G="var(--bitsnap-viewer3d-border,#e5e5e5)",ne="var(--bitsnap-viewer3d-radius,0.75rem)",Oe=`
|
|
2
|
+
${T}{container-type:inline-size;display:flex;flex-direction:column;gap:.75rem;font-family:inherit;color:${g}}
|
|
3
|
+
${T} *{box-sizing:border-box}
|
|
4
|
+
${T} .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}
|
|
5
|
+
.bsv3d-frame{position:relative;display:flex;flex-direction:column;overflow:hidden;background:${k};color:${g};border:1px solid ${G};border-radius:${ne}}
|
|
6
|
+
.bsv3d-frame[data-fullscreen]{position:fixed;inset:0;z-index:2147483000;width:100vw;height:100dvh;border:0;border-radius:0}
|
|
7
|
+
.bsv3d-stage{position:relative;width:100%;aspect-ratio:4/3}
|
|
8
|
+
.bsv3d-placeholder{width:100%;aspect-ratio:4/3}
|
|
9
|
+
@container (min-width:48rem){${T} .bsv3d-stage,${T} .bsv3d-placeholder{aspect-ratio:16/11}}
|
|
10
|
+
.bsv3d-frame[data-fullscreen] .bsv3d-stage{aspect-ratio:auto;flex:1;min-height:0}
|
|
11
|
+
.bsv3d-canvas{position:absolute!important;inset:0}
|
|
12
|
+
.bsv3d-poster{pointer-events:none;position:absolute;inset:0;display:grid;place-items:center;opacity:1}
|
|
13
|
+
.bsv3d-poster[data-hidden]{opacity:0}
|
|
14
|
+
.bsv3d-poster img{width:100%;height:100%;object-fit:contain;padding:6%;display:block}
|
|
15
|
+
.bsv3d-poster svg{width:4rem;height:4rem;color:color-mix(in srgb,${g} 30%,transparent)}
|
|
16
|
+
.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,${g} 82%,transparent);color:${k}}
|
|
17
|
+
.bsv3d-chip svg{width:1rem;height:1rem;flex:none}
|
|
18
|
+
.bsv3d-chip[data-small]{font-size:.75rem;line-height:1rem;padding:.375rem .75rem}
|
|
19
|
+
.bsv3d-loading{pointer-events:none;position:absolute;inset:auto 0 0 0;display:flex;flex-direction:column;align-items:flex-start;gap:.5rem}
|
|
20
|
+
.bsv3d-loading .bsv3d-chip{margin:0 .75rem}
|
|
21
|
+
.bsv3d-bar{height:4px;width:100%;background:color-mix(in srgb,${g} 10%,transparent)}
|
|
22
|
+
.bsv3d-bar>div{height:100%;background:var(--bitsnap-viewer3d-accent,#0a7ea5)}
|
|
23
|
+
.bsv3d-center{position:absolute;inset:0;display:grid;place-items:center;padding:1rem}
|
|
24
|
+
.bsv3d-button{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;height:2.75rem;padding:0 1.25rem;border:1px solid ${G};border-radius:${ne};background:${k};color:${g};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)}
|
|
25
|
+
.bsv3d-button:hover{border-color:color-mix(in srgb,${g} 40%,transparent)}
|
|
26
|
+
.bsv3d-button svg{width:1rem;height:1rem}
|
|
27
|
+
.bsv3d-button:disabled{opacity:.6;cursor:default}
|
|
28
|
+
.bsv3d-alert{display:flex;max-width:20rem;flex-direction:column;align-items:center;gap:.75rem;border-radius:${ne};background:${k};padding:1rem 1.25rem;text-align:center;box-shadow:0 8px 20px -10px rgb(15 23 42/.45)}
|
|
29
|
+
.bsv3d-alert p{margin:0;font-size:.875rem;font-weight:600}
|
|
30
|
+
.bsv3d-alert .bsv3d-button{height:2.5rem;box-shadow:none}
|
|
31
|
+
.bsv3d-unsupported{position:absolute;left:.75rem;bottom:.75rem}
|
|
32
|
+
.bsv3d-hint{pointer-events:none;position:absolute;inset:auto 0 4rem 0;display:flex;justify-content:center;opacity:0}
|
|
33
|
+
.bsv3d-hint[data-visible]{opacity:1}
|
|
34
|
+
.bsv3d-controls{position:absolute;left:.75rem;right:.75rem;bottom:.75rem;display:flex;align-items:flex-end;justify-content:space-between;gap:.5rem}
|
|
35
|
+
.bsv3d-controls>div:last-child{display:flex;flex:none;gap:.5rem}
|
|
36
|
+
.bsv3d-icon{display:grid;place-items:center;width:2.5rem;height:2.5rem;padding:0;border-radius:999px;border:1px solid ${G};background:color-mix(in srgb,${k} 88%,transparent);color:${g};cursor:pointer;font:inherit}
|
|
37
|
+
.bsv3d-icon:hover{background:${k};border-color:color-mix(in srgb,${g} 35%,transparent)}
|
|
38
|
+
.bsv3d-icon svg{width:1rem;height:1rem}
|
|
39
|
+
.bsv3d-icon[data-wide]{width:auto;padding:0 1rem;font-size:.875rem;font-weight:600}
|
|
40
|
+
.bsv3d-close{position:absolute;top:max(.75rem,env(safe-area-inset-top));right:.75rem}
|
|
41
|
+
.bsv3d-close svg{width:1.25rem;height:1.25rem}
|
|
42
|
+
${T} button:focus-visible,${T} a:focus-visible,.bsv3d-frame button:focus-visible{outline:2px solid ${g};outline-offset:2px}
|
|
43
|
+
.bsv3d-buybar{flex:none;border-top:1px solid ${G};background:${k};padding:.75rem 1rem max(.75rem,env(safe-area-inset-bottom))}
|
|
44
|
+
.bsv3d-buybar-row{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap}
|
|
45
|
+
.bsv3d-buybar-name{margin:0;font-weight:600;font-size:1rem}
|
|
46
|
+
.bsv3d-buybar-price{margin:0;font-size:.875rem;font-variant-numeric:tabular-nums}
|
|
47
|
+
.bsv3d-buybar .bsv3d-button{box-shadow:none;background:${g};color:${k};border-color:${g}}
|
|
48
|
+
.bsv3d-buybar-error{margin:.25rem 0 0;font-size:.875rem;color:#b91c1c}
|
|
49
|
+
.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,${g} 70%,transparent))}
|
|
50
|
+
.bsv3d-notes p{margin:0}
|
|
51
|
+
.bsv3d-notes .bsv3d-facts-title{font-size:.875rem;font-weight:600;color:${g}}
|
|
52
|
+
.bsv3d-notes dl{display:flex;flex-wrap:wrap;gap:.5rem 1.5rem;margin:.375rem 0 0}
|
|
53
|
+
.bsv3d-notes dl>div{display:flex;flex-direction:column}
|
|
54
|
+
.bsv3d-notes dd{margin:0;font-size:.875rem;font-weight:500;color:${g};font-variant-numeric:tabular-nums}
|
|
55
|
+
.bsv3d-notes .bsv3d-links{display:flex;flex-wrap:wrap;align-items:baseline;gap:.25rem .75rem}
|
|
56
|
+
.bsv3d-notes a{color:inherit;font-weight:500;text-decoration:underline;text-underline-offset:2px}
|
|
57
|
+
@media (prefers-reduced-motion:no-preference){
|
|
58
|
+
.bsv3d-poster{transition:opacity .5s cubic-bezier(.16,1,.3,1)}
|
|
59
|
+
.bsv3d-hint{transition:opacity .3s}
|
|
60
|
+
.bsv3d-bar>div{transition:width .2s}
|
|
61
|
+
}
|
|
62
|
+
`;import{jsx as n,jsxs as b}from"react/jsx-runtime";var yt=()=>import("./Viewer3D-2IDEH6W3.mjs");function ht(e){let t={};if(e==null)return t;for(let[r,o]of Object.entries(e))o&&(t[`--bitsnap-viewer3d-${r}`]=o);return t}function wt(){try{let e=document.createElement("canvas");return(e.getContext("webgl2")??e.getContext("webgl"))!=null}catch{return!1}}function je(e){let[t,r]=P(!1);return h(()=>{if(typeof window.matchMedia!="function")return;let o=window.matchMedia(e),i=()=>r(o.matches);return i(),o.addEventListener?.("change",i),()=>o.removeEventListener?.("change",i)},[e]),t}function Dt(){let[e,t]=P(!0);return h(()=>{let r=()=>t(document.visibilityState!=="hidden");return r(),document.addEventListener("visibilitychange",r),()=>document.removeEventListener("visibilitychange",r)},[]),e}function se({model:e,productName:t,locale:r,texts:o,appearance:i,decoderPath:m,reportHref:a,startSignal:d,renderFullscreenBar:p,hideNotes:f,id:u,className:w,style:M,loadViewer:x=yt}){let l=H(r,o),V={key:e.previewUrl,size:e.previewSize},[c,v]=bt(ze,V,$e),[D,C]=P(null),X=ie(null),pe=ie(null),[J,me]=P(!1),[q,fe]=P(!1),Qe=Dt(),Ye=je("(prefers-reduced-motion: reduce)"),R=je("(pointer: coarse)"),[L,A]=P(!1),[ee,U]=P(!1),[Ze,Ke]=P(0),S=Ve(X),ge=gt(),be=ht(i);h(()=>{wt()||v({type:"NO_WEBGL"})},[]),h(()=>{let s=pe.current;if(s==null||typeof IntersectionObserver>"u"){me(!0),fe(!0);return}let y=new IntersectionObserver(([re])=>me(re?.isIntersecting??!1),{rootMargin:"200px 0px"}),ye=new IntersectionObserver(([re])=>fe(re?.isIntersecting??!1),{threshold:.05});return y.observe(s),ye.observe(s),()=>{y.disconnect(),ye.disconnect()}},[]),h(()=>{J&&v({type:"VISIBLE"})},[J,c.status]),h(()=>{v({type:"MODEL_CHANGED",model:V,visible:J})},[V.key,V.size]);let Xe=ie(d);h(()=>{d==null||d===Xe.current||v({type:"REQUEST"})},[d]);let te=Fe(c.status);h(()=>{if(!te||D!=null)return;let s=!1;return x().then(y=>{s||C(()=>y.default)},y=>{console.warn("[bitsnap-react/viewer3d] the viewer could not be loaded; are three, @react-three/fiber and @react-three/drei installed?",y),s||v({type:"FAILED",key:c.model.key})}),()=>{s=!0}},[te,D,c.model.key,c.attempt]);let N=c.status==="ready";h(()=>{if(!N||Re())return;Le(),U(!0);let s=setTimeout(()=>U(!1),xe);return()=>clearTimeout(s)},[N]),h(()=>{if(!L)return;let s=y=>{X.current?.contains(y.target)||A(!1)};return document.addEventListener("pointerdown",s),()=>document.removeEventListener("pointerdown",s)},[L]),h(()=>{!q&&!S.isFullscreen&&A(!1)},[q,S.isFullscreen]);let Je=!R||L||S.isFullscreen,qe=W(()=>U(!1),[]),$=c.model.key,et=W((s,y)=>v({type:"PROGRESS",key:$,loaded:s,total:y}),[$]),tt=W(()=>v({type:"LOADED",key:$}),[$]),rt=W(s=>{console.warn("[bitsnap-react/viewer3d] model failed",s),v({type:"FAILED",key:$})},[$]),ot=O(e.previewSize,z(r)),I=Math.round(c.progress*100),E=S.isFullscreen,ve=!Ye&&Qe&&(q||E),nt=s=>S.mode==="overlay"?vt(s,document.body):s;return b("section",{id:u,"aria-labelledby":ge,"data-bitsnap-viewer3d":"",className:w,style:{...be,...M},children:[n("style",{href:Ie,precedence:"default",children:Oe}),n("h2",{id:ge,className:"bsv3d-sr",children:l.sectionLabel}),S.mode==="overlay"&&n("div",{"aria-hidden":"true",className:"bsv3d-placeholder"}),nt(b("div",{ref:X,"data-viewer3d-frame":"","data-state":c.status,"data-motion":ve?"on":"off","data-fullscreen":E?"":void 0,className:"bsv3d-frame",style:be,onClick:()=>{N&&R&&!L&&(A(!0),U(!1))},children:[b("div",{ref:pe,className:"bsv3d-stage",children:[te&&D!=null&&n(D,{className:"bsv3d-canvas",url:c.model.key,decoderPath:m,expectedSize:c.model.size,attempt:c.attempt,motionAllowed:ve,interactive:Je,allowZoom:E||R&&L,resetSignal:Ze,onProgress:et,onLoaded:tt,onError:rt,onInteract:qe},`${c.model.key}#${c.attempt}`),n(Pt,{src:e.thumbnailUrl,alt:t,hidden:N}),c.status==="loading"&&b("div",{className:"bsv3d-loading",children:[n("span",{className:"bsv3d-chip","data-small":"","aria-hidden":"true",children:I>0?l.loadingProgress(I):l.loading}),n("div",{className:"bsv3d-bar",children:n("div",{style:{width:`${Math.max(I,3)}%`}})})]}),c.status==="awaiting-click"&&n("div",{className:"bsv3d-center",children:b("button",{type:"button",className:"bsv3d-button","data-viewer3d-show":"",onClick:s=>{s.stopPropagation(),v({type:"REQUEST"})},children:[n(_e,{"aria-hidden":"true"}),l.show(ot)]})}),c.status==="error"&&n("div",{className:"bsv3d-center",children:b("div",{role:"alert",className:"bsv3d-alert",children:[n("p",{children:l.error}),b("button",{type:"button",className:"bsv3d-button","data-viewer3d-retry":"",onClick:s=>{s.stopPropagation(),v({type:"RETRY"})},children:[n(Ue,{"aria-hidden":"true"}),l.retry]})]})}),c.status==="unsupported"&&n("p",{className:"bsv3d-chip bsv3d-unsupported","data-small":"",children:l.unsupported}),N&&n("div",{"aria-hidden":!ee,className:"bsv3d-hint","data-visible":ee?"":void 0,children:b("span",{className:"bsv3d-chip",children:[R?n(Ae,{"aria-hidden":"true"}):n(mt,{"aria-hidden":"true"}),R&&!E?l.hintTap:l.hintDrag]})}),N&&b("div",{className:"bsv3d-controls",children:[n("div",{children:R&&!E&&(L?n("button",{type:"button",className:"bsv3d-icon","data-wide":"",onClick:s=>{s.stopPropagation(),A(!1)},children:l.touchDone}):!ee&&b("span",{className:"bsv3d-chip","data-small":"",children:[n(Ae,{"aria-hidden":"true"}),l.hintTap]}))}),b("div",{children:[n("button",{type:"button","aria-label":l.reset,title:l.reset,className:"bsv3d-icon",onClick:s=>{s.stopPropagation(),Ke(y=>y+1)},children:n(Ue,{"aria-hidden":"true"})}),!E&&n("button",{type:"button","aria-label":l.fullscreen,title:l.fullscreen,className:"bsv3d-icon","data-viewer3d-fullscreen":"",onClick:s=>{s.stopPropagation(),S.enter()},children:n(pt,{"aria-hidden":"true"})})]})]}),E&&n("button",{type:"button","aria-label":l.closeFullscreen,title:l.closeFullscreen,className:"bsv3d-icon bsv3d-close",onClick:s=>{s.stopPropagation(),S.exit()},children:n(ft,{"aria-hidden":"true"})}),n("p",{className:"bsv3d-sr","aria-live":"polite",children:c.status==="loading"?I>0?l.loadingProgress(I):l.loading:c.status==="error"?l.error:""})]}),E&&p!=null&&n("div",{className:"bsv3d-buybar",onClick:s=>s.stopPropagation(),children:p({close:S.exit})})]})),!f&&n(xt,{model:e,copy:l,locale:r,reportHref:a})]})}function Pt({src:e,alt:t,hidden:r}){let[o,i]=P(!1);return n("div",{"aria-hidden":r,className:"bsv3d-poster","data-hidden":r?"":void 0,children:e!=null&&!o?n("img",{src:e,alt:t,decoding:"async",loading:"lazy",onError:()=>i(!0)}):n(_e,{"aria-hidden":"true",strokeWidth:1.25})})}function xt({model:e,copy:t,locale:r,reportHref:o}){let[i,m]=P(o);h(()=>{if(o==null){m(void 0);return}try{let d=new URL(o,window.location.href);d.searchParams.has("url")||d.searchParams.set("url",window.location.href),m(d.toString())}catch{m(o)}},[o]);let a=e.facts!=null?ke(e.facts,t,r):[];return!e.illustrative&&i==null&&a.length===0?null:b("div",{className:"bsv3d-notes",children:[a.length>0&&b("div",{children:[n("p",{className:"bsv3d-facts-title",children:t.factsTitle}),n("dl",{children:a.map(d=>b("div",{children:[n("dt",{children:d.label}),n("dd",{children:d.value})]},d.label))})]}),(e.illustrative||i!=null)&&b("p",{className:"bsv3d-links",children:[e.illustrative&&n("span",{children:t.disclaimer}),i!=null&&n("a",{href:i,children:t.report})]})]})}import{useCallback as Et,useEffect as kt,useState as Z}from"react";var Q=class extends Error{status;constructor(t,r){super(t),this.name="Product3DError",this.status=r}};function He(e){let t=new URLSearchParams;return t.set("ids",e.productId),e.locale&&t.set("locale",e.locale),t.set("include","model3d"),`${e.host.replace(/\/+$/,"")}/api/integrations/${encodeURIComponent(e.projectID)}/public-commerce/products?${t.toString()}`}function ae(e){return typeof e=="object"&&e!=null&&typeof e.previewUrl=="string"&&e.previewUrl.length>0&&typeof e.previewSize=="number"}function Be(e,t){return e.find(r=>r.id===t)??e.find(r=>r.variants?.some(o=>o.id===t))??(e.length===1?e[0]:void 0)}function St(e){return/^(prodv2_[^_]+)/.exec(e)?.[1]??e}function Y(e,t){if(!t)return;let r=e.variants??[],o=`${St(e.id)}_${t}`;return r.find(i=>i.id===t)??r.find(i=>i.id===o)}function le(e,t){let r=Y(e,t);return r!=null?ae(r.model3d)?r.model3d:void 0:ae(e.model3d)?e.model3d:e.variants?.map(o=>o.model3d).find(ae)}var de=new Map;function ce(e){let t=he(He(e)),r=de.get(t);return r==null&&(r=(async()=>{let o=await fetch(t,{method:"GET",credentials:"omit",headers:{Accept:"application/json"}});if(!o.ok)throw new Q(`Could not load the product (${o.status})`,o.status);let i=await o.json();return Array.isArray(i?.result)?i.result:[]})(),de.set(t,r),r.catch(()=>de.delete(t))),r}function ue(e,t,r={}){let o=r.projectID??_().projectID,[i]=Z(()=>r.host??j),m=r.host??i,[a]=Z(()=>r.locale??we()),d=r.locale??a,p=`${m}|${o}|${e}|${d}`,[f,u]=Z(),[w,M]=Z(0);kt(()=>{if(!e)return;if(!o){u({key:p,error:new Error("bitsnap-react/viewer3d: no project ID (pass projectID or call setProjectID)")});return}let D=!1;return ce({projectID:o,host:m,productId:e,locale:d}).then(C=>{D||u({key:p,products:C})},C=>{D||u({key:p,error:C instanceof Error?C:new Error(String(C))})}),()=>{D=!0}},[p,w]);let x=Et(()=>M(D=>D+1),[]);if(!e)return{status:"none",retry:x};if(f==null||f.key!==p)return{status:"loading",retry:x};if(f.error!=null)return{status:"error",error:f.error,retry:x};let l=Be(f.products,e);if(l==null)return{status:"none",retry:x};let V=t??(Y(l,e)!=null?e:void 0),c=Y(l,V),v=le(l,V);return{status:v!=null?"ready":"none",model:v,product:l,variant:c,retry:x}}import{Fragment as Tt,jsx as F,jsxs as K}from"react/jsx-runtime";function Vt({productId:e,variantId:t,projectID:r,host:o,locale:i,renderBuyBar:m,fallback:a=null,productUrl:d,onAddedToCart:p,...f}){let u=ue(e,t,{projectID:r,host:o,locale:i});if(u.status!=="ready"||u.model==null||u.product==null)return F(Tt,{children:a});let w=u.product,M=H(i,f.texts);return F(se,{...f,locale:i,model:u.model,productName:u.variant?.name?`${w.name} \u2013 ${u.variant.name}`:w.name,renderFullscreenBar:({close:x})=>m!=null?m({product:w,variant:u.variant,close:x}):F(Ct,{product:w,variant:u.variant,copy:M,locale:i,projectID:r??_().projectID,host:o,productUrl:d,onAdded:p})})}function Ge(e,t){if(e.recurring!=null)return!1;let r=t?.priceType??e.priceType;if(r!=null&&r!=="one_time")return!1;let o=t?.availableQuantity??e.availableQuantity;return o==null||o>0}function We(e,t){return t?.id??e.variants?.[0]?.id??e.id}function Ct({product:e,variant:t,copy:r,locale:o,projectID:i,host:m,productUrl:a,onAdded:d}){let[p,f]=Mt("idle"),u=t?.price??e.price,w=t?.currency??e.currency,M=i!=null&&Ge(e,t);return K("div",{children:[K("div",{className:"bsv3d-buybar-row",children:[K("div",{children:[K("p",{className:"bsv3d-buybar-name",children:[e.name,t?.name?` \u2013 ${t.name}`:""]}),F("p",{className:"bsv3d-buybar-price",children:Pe(u,w,o)})]}),M&&F("button",{type:"button",className:"bsv3d-button","data-viewer3d-add":"",disabled:p==="adding","aria-live":"polite",onClick:async()=>{f("adding");try{await De({id:e.id,cartItemId:We(e,t),name:t?.name?`${e.name} \u2013 ${t.name}`:e.name,price:u,currency:w},{projectID:i,host:m??j,showCart:!1,url:a??(typeof window<"u"?window.location.href:void 0)}),f("added"),d?.({product:e,variant:t})}catch{f("error")}},children:p==="adding"?r.addingToCart:p==="added"?r.addedToCart:r.addToCart})]}),p==="error"&&F("p",{className:"bsv3d-buybar-error",role:"alert",children:r.addToCartError})]})}export{it as AUTO_LOAD_MAX_BYTES,se as Model3DViewer,Q as Product3DError,Vt as Product3DViewer,Ee as VIEWER3D_COPY_EN,Se as VIEWER3D_COPY_PL,He as buildProduct3DURL,We as cartItemIdFor,st as defaultDecoderPath,ce as fetchProduct3D,O as formatModelSize,Ge as isCartable,oe as needsClickToLoad,le as resolveModel,ue as useProduct3DModel};
|
|
63
|
+
//# sourceMappingURL=viewer3d.mjs.map
|