'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var events = require('../../dist/events-d0566a2e.cjs.dev.js'); var React = require('react'); var THREE = require('three'); var reactNative = require('react-native'); var expoGl = require('expo-gl'); var itsFine = require('its-fine'); var jsxRuntime = require('react/jsx-runtime'); var expoAsset = require('expo-asset'); var fs = require('expo-file-system'); var base64Js = require('base64-js'); var buffer = require('buffer'); require('react-reconciler/constants'); require('zustand'); require('suspend-react'); require('react-reconciler'); require('scheduler'); function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var React__namespace = /*#__PURE__*/_interopNamespace(React); var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE); var fs__namespace = /*#__PURE__*/_interopNamespace(fs); /** * A native canvas which accepts threejs elements as children. * @see https://docs.pmnd.rs/react-three-fiber/api/canvas */ const CanvasImpl = /*#__PURE__*/React__namespace.forwardRef(({ children, style, gl, events: events$1 = events.createPointerEvents, shadows, linear, flat, legacy, orthographic, frameloop, performance, raycaster, camera, scene, onPointerMissed, onCreated, ...props }, forwardedRef) => { // Create a known catalogue of Threejs-native elements // This will include the entire THREE namespace by default, users can extend // their own elements by using the createRoot API instead React__namespace.useMemo(() => events.extend(THREE__namespace), []); const Bridge = itsFine.useContextBridge(); const [{ width, height, top, left }, setSize] = React__namespace.useState({ width: 0, height: 0, top: 0, left: 0 }); const [canvas, setCanvas] = React__namespace.useState(null); const [bind, setBind] = React__namespace.useState(); React__namespace.useImperativeHandle(forwardedRef, () => viewRef.current); const handlePointerMissed = events.useMutableCallback(onPointerMissed); const [block, setBlock] = React__namespace.useState(false); const [error, setError] = React__namespace.useState(undefined); // Suspend this component if block is a promise (2nd run) if (block) throw block; // Throw exception outwards if anything within canvas throws if (error) throw error; const viewRef = React__namespace.useRef(null); const root = React__namespace.useRef(null); const [antialias, setAntialias] = React__namespace.useState(true); const onLayout = React__namespace.useCallback(e => { const { width, height, x, y } = e.nativeEvent.layout; setSize({ width, height, top: y, left: x }); }, []); // Called on context create or swap // https://github.com/pmndrs/react-three-fiber/pull/2297 const onContextCreate = React__namespace.useCallback(context => { const listeners = new Map(); const canvas = { style: {}, width: context.drawingBufferWidth, height: context.drawingBufferHeight, clientWidth: context.drawingBufferWidth, clientHeight: context.drawingBufferHeight, getContext: (_, { antialias = false }) => { setAntialias(antialias); return context; }, addEventListener(type, listener) { let callbacks = listeners.get(type); if (!callbacks) { callbacks = []; listeners.set(type, callbacks); } callbacks.push(listener); }, removeEventListener(type, listener) { const callbacks = listeners.get(type); if (callbacks) { const index = callbacks.indexOf(listener); if (index !== -1) callbacks.splice(index, 1); } }, dispatchEvent(event) { Object.assign(event, { target: this }); const callbacks = listeners.get(event.type); if (callbacks) { for (const callback of callbacks) { callback(event); } } }, setPointerCapture() { // TODO }, releasePointerCapture() { // TODO } }; // TODO: this is wrong but necessary to trick controls // @ts-ignore canvas.ownerDocument = canvas; canvas.getRootNode = () => canvas; root.current = events.createRoot(canvas); setCanvas(canvas); function handleTouch(gestureEvent, type) { gestureEvent.persist(); canvas.dispatchEvent(Object.assign(gestureEvent.nativeEvent, { type, offsetX: gestureEvent.nativeEvent.locationX, offsetY: gestureEvent.nativeEvent.locationY, pointerType: 'touch', pointerId: gestureEvent.nativeEvent.identifier })); return true; } const responder = reactNative.PanResponder.create({ onStartShouldSetPanResponder: () => true, onMoveShouldSetPanResponder: () => true, onMoveShouldSetPanResponderCapture: () => true, onPanResponderTerminationRequest: () => true, onStartShouldSetPanResponderCapture: e => handleTouch(e, 'pointercapture'), onPanResponderStart: e => handleTouch(e, 'pointerdown'), onPanResponderMove: e => handleTouch(e, 'pointermove'), onPanResponderEnd: (e, state) => { handleTouch(e, 'pointerup'); if (Math.hypot(state.dx, state.dy) < 20) handleTouch(e, 'click'); }, onPanResponderRelease: e => handleTouch(e, 'pointerleave'), onPanResponderTerminate: e => handleTouch(e, 'lostpointercapture'), onPanResponderReject: e => handleTouch(e, 'lostpointercapture') }); setBind(responder.panHandlers); }, []); if (root.current && width > 0 && height > 0) { root.current.configure({ gl, events: events$1, shadows, linear, flat, legacy, orthographic, frameloop, performance, raycaster, camera, scene, // expo-gl can only render at native dpr/resolution // https://github.com/expo/expo-three/issues/39 dpr: reactNative.PixelRatio.get(), size: { width, height, top, left }, // Pass mutable reference to onPointerMissed so it's free to update onPointerMissed: (...args) => handlePointerMissed.current == null ? void 0 : handlePointerMissed.current(...args), // Overwrite onCreated to apply RN bindings onCreated: state => { // Bind render to RN bridge const context = state.gl.getContext(); const renderFrame = state.gl.render.bind(state.gl); state.gl.render = (scene, camera) => { renderFrame(scene, camera); context.endFrameEXP(); }; return onCreated == null ? void 0 : onCreated(state); } }); root.current.render( /*#__PURE__*/jsxRuntime.jsx(Bridge, { children: /*#__PURE__*/jsxRuntime.jsx(events.ErrorBoundary, { set: setError, children: /*#__PURE__*/jsxRuntime.jsx(React__namespace.Suspense, { fallback: /*#__PURE__*/jsxRuntime.jsx(events.Block, { set: setBlock }), children: children != null ? children : null }) }) })); } React__namespace.useEffect(() => { if (canvas) { return () => events.unmountComponentAtNode(canvas); } }, [canvas]); return /*#__PURE__*/jsxRuntime.jsx(reactNative.View, { ...props, ref: viewRef, onLayout: onLayout, style: { flex: 1, ...style }, ...bind, children: width > 0 && /*#__PURE__*/jsxRuntime.jsx(expoGl.GLView, { msaaSamples: antialias ? 4 : 0, onContextCreate: onContextCreate, style: reactNative.StyleSheet.absoluteFill }) }); }); /** * A native canvas which accepts threejs elements as children. * @see https://docs.pmnd.rs/react-three-fiber/api/canvas */ const Canvas = /*#__PURE__*/React__namespace.forwardRef(function CanvasWrapper(props, ref) { return /*#__PURE__*/jsxRuntime.jsx(itsFine.FiberProvider, { children: /*#__PURE__*/jsxRuntime.jsx(CanvasImpl, { ...props, ref: ref }) }); }); /** Default R3F event manager for react-native */ function createTouchEvents(store) { const { handlePointer } = events.createEvents(store); const handleTouch = (event, name) => { event.persist() // Apply offset ; event.nativeEvent.offsetX = event.nativeEvent.locationX; event.nativeEvent.offsetY = event.nativeEvent.locationY; // Emulate DOM event const callback = handlePointer(name); callback(event.nativeEvent); return true; }; const responder = reactNative.PanResponder.create({ onStartShouldSetPanResponder: () => true, onMoveShouldSetPanResponder: () => true, onMoveShouldSetPanResponderCapture: () => true, onPanResponderTerminationRequest: () => true, onStartShouldSetPanResponderCapture: e => handleTouch(e, 'onPointerCapture'), onPanResponderStart: e => handleTouch(e, 'onPointerDown'), onPanResponderMove: e => handleTouch(e, 'onPointerMove'), onPanResponderEnd: (e, state) => { handleTouch(e, 'onPointerUp'); if (Math.hypot(state.dx, state.dy) < 20) handleTouch(e, 'onClick'); }, onPanResponderRelease: e => handleTouch(e, 'onPointerLeave'), onPanResponderTerminate: e => handleTouch(e, 'onLostPointerCapture'), onPanResponderReject: e => handleTouch(e, 'onLostPointerCapture') }); return { priority: 1, enabled: true, compute(event, state, previous) { // https://github.com/pmndrs/react-three-fiber/pull/782 // Events trigger outside of canvas when moved, use offsetX/Y by default and allow overrides state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1); state.raycaster.setFromCamera(state.pointer, state.camera); }, connected: undefined, handlers: responder.panHandlers, update: () => { var _internal$lastEvent; const { events, internal } = store.getState(); if ((_internal$lastEvent = internal.lastEvent) != null && _internal$lastEvent.current && events.handlers) { handlePointer('onPointerMove')(internal.lastEvent.current); } }, connect: () => { const { set, events } = store.getState(); events.disconnect == null ? void 0 : events.disconnect(); set(state => ({ events: { ...state.events, connected: true } })); }, disconnect: () => { const { set } = store.getState(); set(state => ({ events: { ...state.events, connected: false } })); } }; } // http://stackoverflow.com/questions/105034 function uuidv4() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { const r = Math.random() * 16 | 0, v = c == 'x' ? r : r & 0x3 | 0x8; return v.toString(16); }); } async function getAsset(input) { if (typeof input === 'string') { var _NativeModules$BlobMo; // Don't process storage if (input.startsWith('file:')) return input; // Unpack Blobs from react-native BlobManager // https://github.com/facebook/react-native/issues/22681#issuecomment-523258955 if (input.startsWith('blob:') || input.startsWith((_NativeModules$BlobMo = reactNative.NativeModules.BlobModule) == null ? void 0 : _NativeModules$BlobMo.BLOB_URI_SCHEME)) { const blob = await new Promise((res, rej) => { const xhr = new XMLHttpRequest(); xhr.open('GET', input); xhr.responseType = 'blob'; xhr.onload = () => res(xhr.response); xhr.onerror = rej; xhr.send(); }); const data = await new Promise((res, rej) => { const reader = new FileReader(); reader.onload = () => res(reader.result); reader.onerror = rej; reader.readAsText(blob); }); input = `data:${blob.type};base64,${data}`; } // Create safe URI for JSI serialization if (input.startsWith('data:')) { const [header, data] = input.split(';base64,'); const [, type] = header.split('/'); const uri = fs__namespace.cacheDirectory + uuidv4() + `.${type}`; await fs__namespace.writeAsStringAsync(uri, data, { encoding: fs__namespace.EncodingType.Base64 }); return uri; } } // Download bundler module or external URL const asset = await expoAsset.Asset.fromModule(input).downloadAsync(); let uri = asset.localUri || asset.uri; // Unpack assets in Android Release Mode if (!uri.includes(':')) { const file = `${fs__namespace.cacheDirectory}ExponentAsset-${asset.hash}.${asset.type}`; await fs__namespace.copyAsync({ from: uri, to: file }); uri = file; } return uri; } function polyfills() { // Patch Blob for ArrayBuffer and URL if unsupported // https://github.com/facebook/react-native/pull/39276 // https://github.com/pmndrs/react-three-fiber/issues/3058 if (reactNative.Platform.OS !== 'web') { try { const blob = new Blob([new ArrayBuffer(4)]); const url = URL.createObjectURL(blob); URL.revokeObjectURL(url); } catch (_) { const BlobManager = require('react-native/Libraries/Blob/BlobManager.js'); const createObjectURL = URL.createObjectURL; URL.createObjectURL = function (blob) { if (blob.data._base64) { return `data:${blob.type};base64,${blob.data._base64}`; } return createObjectURL(blob); }; const createFromParts = BlobManager.createFromParts; BlobManager.createFromParts = function (parts, options) { parts = parts.map(part => { if (part instanceof ArrayBuffer || ArrayBuffer.isView(part)) { part = base64Js.fromByteArray(new Uint8Array(part)); } return part; }); const blob = createFromParts(parts, options); // Always enable slow but safe path for iOS (previously for Android unauth) // https://github.com/pmndrs/react-three-fiber/issues/3075 // if (!NativeModules.BlobModule?.BLOB_URI_SCHEME) { blob.data._base64 = ''; for (const part of parts) { var _data$_base, _data; blob.data._base64 += (_data$_base = (_data = part.data) == null ? void 0 : _data._base64) != null ? _data$_base : part; } // } return blob; }; } } // Don't pre-process urls, let expo-asset generate an absolute URL const extractUrlBase = THREE__namespace.LoaderUtils.extractUrlBase.bind(THREE__namespace.LoaderUtils); THREE__namespace.LoaderUtils.extractUrlBase = url => typeof url === 'string' ? extractUrlBase(url) : './'; // There's no Image in native, so create a data texture instead THREE__namespace.TextureLoader.prototype.load = function load(url, onLoad, onProgress, onError) { if (this.path && typeof url === 'string') url = this.path + url; const texture = new THREE__namespace.Texture(); getAsset(url).then(async uri => { // https://github.com/expo/expo-three/pull/266 const { width, height } = await new Promise((res, rej) => reactNative.Image.getSize(uri, (width, height) => res({ width, height }), rej)); texture.image = { // Special case for EXGLImageUtils::loadImage data: { localUri: uri }, width, height }; texture.flipY = true; // Since expo-gl@12.4.0 texture.needsUpdate = true; // Force non-DOM upload for EXGL texImage2D // @ts-expect-error texture.isDataTexture = true; onLoad == null ? void 0 : onLoad(texture); }).catch(onError); return texture; }; // Fetches assets via FS THREE__namespace.FileLoader.prototype.load = function load(url, onLoad, onProgress, onError) { if (this.path && typeof url === 'string') url = this.path + url; this.manager.itemStart(url); getAsset(url).then(async uri => { const base64 = await fs__namespace.readAsStringAsync(uri, { encoding: fs__namespace.EncodingType.Base64 }); const data = buffer.Buffer.from(base64, 'base64'); onLoad == null ? void 0 : onLoad(data.buffer); }).catch(error => { onError == null ? void 0 : onError(error); this.manager.itemError(url); }).finally(() => { this.manager.itemEnd(url); }); }; } if (reactNative.Platform.OS !== 'web') polyfills(); exports.ReactThreeFiber = events.threeTypes; exports._roots = events.roots; exports.act = events.act; exports.addAfterEffect = events.addAfterEffect; exports.addEffect = events.addEffect; exports.addTail = events.addTail; exports.advance = events.advance; exports.applyProps = events.applyProps; exports.buildGraph = events.buildGraph; exports.context = events.context; exports.createEvents = events.createEvents; exports.createPointerEvents = events.createPointerEvents; exports.createPortal = events.createPortal; exports.createRoot = events.createRoot; exports.dispose = events.dispose; exports.extend = events.extend; exports.flushGlobalEffects = events.flushGlobalEffects; exports.flushSync = events.flushSync; exports.getRootState = events.getRootState; exports.invalidate = events.invalidate; exports.reconciler = events.reconciler; exports.render = events.render; exports.unmountComponentAtNode = events.unmountComponentAtNode; exports.useFrame = events.useFrame; exports.useGraph = events.useGraph; exports.useInstanceHandle = events.useInstanceHandle; exports.useLoader = events.useLoader; exports.useStore = events.useStore; exports.useThree = events.useThree; exports.Canvas = Canvas; exports.events = createTouchEvents;