spine-expo-usedom 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TheSacredLipton
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # spine-expo-usedom
2
+
3
+ Run **Spine Web Components** in React Native (iOS/Android) using Expo's **DOM Components** (`'use dom'`).
4
+
5
+ > ⚠️ **Note**: This package relies on Expo DOM Components, so it only supports **iOS** and **Android**. Web (react-native-web) is not supported.
6
+ > Requires **Expo SDK 52** or higher.
7
+
8
+ ## 🚀 Features
9
+
10
+ - **Expo DOM Components**: Seamlessly use Web technologies (WebGL, etc.) within native apps.
11
+ - **Spine Web Components**: Play Spine animations using the official web components.
12
+
13
+ ## 📦 Installation
14
+
15
+ ```bash
16
+ npm install spine-expo-usedom
17
+ ```
18
+
19
+ ## 💻 Usage
20
+
21
+ ### 1. Place Spine Assets
22
+ Place your Spine assets (`.json` or `.skel`, `.atlas`, `.png`) in the `public` folder of your Expo project.
23
+
24
+ Example structure:
25
+ ```
26
+ my-app/
27
+ ├── public/
28
+ │ └── spineboy/
29
+ │ ├── spineboy-pro.json
30
+ │ ├── spineboy.atlas
31
+ │ └── spineboy.png
32
+ ├── App.tsx
33
+ └── ...
34
+ ```
35
+
36
+ ### 2. Use the Component
37
+
38
+ ```tsx
39
+ import SpineView from 'spine-expo-usedom';
40
+ import { View } from 'react-native';
41
+
42
+ export default function App() {
43
+ return (
44
+ <View style={{ flex: 1 }}>
45
+ <SpineView
46
+ skeleton="/spineboy/spineboy-pro.json"
47
+ atlas="/spineboy/spineboy.atlas"
48
+ animation="run"
49
+ skin="default"
50
+ fit="contain"
51
+ dom={{ style: { width: '100%', height: '100%' } }}
52
+ />
53
+ </View>
54
+ );
55
+ }
56
+ ```
57
+
58
+ ## 🔧 Props
59
+
60
+ | Prop | Type | Default | Description |
61
+ | ----------------------- | --------------------------------------------- | ------------ | ------------------------------------------------------------ |
62
+ | `skeleton` | `string` | **Required** | Path to the skeleton data file (`.json` or `.skel`). |
63
+ | `atlas` | `string` | **Required** | Path to the atlas file (`.atlas`). |
64
+ | `animation` | `string` | `undefined` | Name of the animation to play. |
65
+ | `skin` | `string` | `undefined` | Name of the skin to use. |
66
+ | `fit` | `'cover' \| 'contain' \| 'loading' \| 'none'` | `undefined` | How the skeleton should fit into the viewport. |
67
+ | `debug` | `boolean` | `false` | Whether to show debug information (bones, regions, etc.). |
68
+ | `preserveDrawingBuffer` | `boolean` | `true` | Whether to preserve the drawing buffer. |
69
+ | `dom` | `DOMProps` | `undefined` | Props passed to the underlying Expo DOM Component container. |
70
+
71
+ ## 📝 License
72
+
73
+ This project is licensed under the MIT License.
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ 'use dom';
3
+
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = SpineView;
8
+ var _react = _interopRequireWildcard(require("react"));
9
+ require("@esotericsoftware/spine-webcomponents");
10
+ var _jsxRuntime = require("react/jsx-runtime");
11
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
12
+ function SpineView({
13
+ dom,
14
+ skeleton,
15
+ atlas,
16
+ skin,
17
+ preserveDrawingBuffer = true,
18
+ ...rest
19
+ }) {
20
+ // window.location.origin を使って絶対パスを生成
21
+ // process.env.EXPO_BASE_URL が "/" で始まらない場合を考慮してパスを結合
22
+ const origin = typeof window !== 'undefined' ? window.location.origin : '';
23
+
24
+ // URLが相対パスの場合(/で始まる場合)、originを付与する処理を入れると親切かも
25
+ const getAbsolutePath = path => {
26
+ if (!path) return path;
27
+ if (path.startsWith('http')) return path;
28
+ if (path.startsWith('/')) return `${origin}${path}`;
29
+ return `${origin}/${path}`;
30
+ };
31
+ const absoluteSkeleton = getAbsolutePath(skeleton);
32
+ const absoluteAtlas = getAbsolutePath(atlas);
33
+ (0, _react.useEffect)(() => {
34
+ console.log('Current URL:', window.location.href);
35
+ console.log('Spine assets paths (absolute):', {
36
+ skeleton: absoluteSkeleton,
37
+ atlas: absoluteAtlas
38
+ });
39
+ }, []);
40
+
41
+ // skin="default" の場合、Spine Web Components でエラーになる場合があるため除外する
42
+ // また、React 19以降ではCustom Elementのプロパティとして渡される際、文字列のままだと
43
+ // コンポーネント内部で配列として扱われた時に1文字ずつ処理されてしまうため、明示的に配列化する
44
+ const skinProp = !skin || skin === 'default' ? undefined : skin.split(',');
45
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
46
+ style: {
47
+ width: '100%',
48
+ height: '100vh',
49
+ display: 'flex',
50
+ justifyContent: 'center',
51
+ alignItems: 'center',
52
+ overflow: 'hidden'
53
+ },
54
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("spine-skeleton", {
55
+ skeleton: absoluteSkeleton,
56
+ atlas: absoluteAtlas,
57
+ skin: skinProp,
58
+ "preserve-drawing-buffer": preserveDrawingBuffer,
59
+ style: {
60
+ width: '100%',
61
+ height: '100%'
62
+ },
63
+ ...rest
64
+ })
65
+ });
66
+ }
67
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Object","defineProperty","exports","value","default","SpineView","_react","_interopRequireWildcard","require","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","has","get","set","hasOwnProperty","call","getOwnPropertyDescriptor","dom","skeleton","atlas","skin","preserveDrawingBuffer","rest","origin","window","location","getAbsolutePath","path","startsWith","absoluteSkeleton","absoluteAtlas","useEffect","console","log","href","skinProp","undefined","split","jsx","style","width","height","display","justifyContent","alignItems","overflow","children"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ 'use dom';
3
+
4
+ import React, { useEffect } from 'react';
5
+ import '@esotericsoftware/spine-webcomponents';
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ export default function SpineView({
8
+ dom,
9
+ skeleton,
10
+ atlas,
11
+ skin,
12
+ preserveDrawingBuffer = true,
13
+ ...rest
14
+ }) {
15
+ // window.location.origin を使って絶対パスを生成
16
+ // process.env.EXPO_BASE_URL が "/" で始まらない場合を考慮してパスを結合
17
+ const origin = typeof window !== 'undefined' ? window.location.origin : '';
18
+
19
+ // URLが相対パスの場合(/で始まる場合)、originを付与する処理を入れると親切かも
20
+ const getAbsolutePath = path => {
21
+ if (!path) return path;
22
+ if (path.startsWith('http')) return path;
23
+ if (path.startsWith('/')) return `${origin}${path}`;
24
+ return `${origin}/${path}`;
25
+ };
26
+ const absoluteSkeleton = getAbsolutePath(skeleton);
27
+ const absoluteAtlas = getAbsolutePath(atlas);
28
+ useEffect(() => {
29
+ console.log('Current URL:', window.location.href);
30
+ console.log('Spine assets paths (absolute):', {
31
+ skeleton: absoluteSkeleton,
32
+ atlas: absoluteAtlas
33
+ });
34
+ }, []);
35
+
36
+ // skin="default" の場合、Spine Web Components でエラーになる場合があるため除外する
37
+ // また、React 19以降ではCustom Elementのプロパティとして渡される際、文字列のままだと
38
+ // コンポーネント内部で配列として扱われた時に1文字ずつ処理されてしまうため、明示的に配列化する
39
+ const skinProp = !skin || skin === 'default' ? undefined : skin.split(',');
40
+ return /*#__PURE__*/_jsx("div", {
41
+ style: {
42
+ width: '100%',
43
+ height: '100vh',
44
+ display: 'flex',
45
+ justifyContent: 'center',
46
+ alignItems: 'center',
47
+ overflow: 'hidden'
48
+ },
49
+ children: /*#__PURE__*/_jsx("spine-skeleton", {
50
+ skeleton: absoluteSkeleton,
51
+ atlas: absoluteAtlas,
52
+ skin: skinProp,
53
+ "preserve-drawing-buffer": preserveDrawingBuffer,
54
+ style: {
55
+ width: '100%',
56
+ height: '100%'
57
+ },
58
+ ...rest
59
+ })
60
+ });
61
+ }
62
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["React","useEffect","jsx","_jsx","SpineView","dom","skeleton","atlas","skin","preserveDrawingBuffer","rest","origin","window","location","getAbsolutePath","path","startsWith","absoluteSkeleton","absoluteAtlas","console","log","href","skinProp","undefined","split","style","width","height","display","justifyContent","alignItems","overflow","children"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";AAAA,SAAS;;AAET,OAAOA,KAAK,IAAIC,SAAS,QAAQ,OAAO;AACxC,OAAO,uCAAuC;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAwB/C,eAAe,SAASC,SAASA,CAAC;EAC9BC,GAAG;EACHC,QAAQ;EACRC,KAAK;EACLC,IAAI;EACJC,qBAAqB,GAAG,IAAI;EAC5B,GAAGC;AACS,CAAC,EAAE;EACf;EACA;EACA,MAAMC,MAAM,GAAG,OAAOC,MAAM,KAAK,WAAW,GAAGA,MAAM,CAACC,QAAQ,CAACF,MAAM,GAAG,EAAE;;EAE1E;EACA,MAAMG,eAAe,GAAIC,IAAY,IAAK;IACtC,IAAI,CAACA,IAAI,EAAE,OAAOA,IAAI;IACtB,IAAIA,IAAI,CAACC,UAAU,CAAC,MAAM,CAAC,EAAE,OAAOD,IAAI;IACxC,IAAIA,IAAI,CAACC,UAAU,CAAC,GAAG,CAAC,EAAE,OAAO,GAAGL,MAAM,GAAGI,IAAI,EAAE;IACnD,OAAO,GAAGJ,MAAM,IAAII,IAAI,EAAE;EAC9B,CAAC;EAED,MAAME,gBAAgB,GAAGH,eAAe,CAACR,QAAQ,CAAC;EAClD,MAAMY,aAAa,GAAGJ,eAAe,CAACP,KAAK,CAAC;EAE5CN,SAAS,CAAC,MAAM;IACZkB,OAAO,CAACC,GAAG,CAAC,cAAc,EAAER,MAAM,CAACC,QAAQ,CAACQ,IAAI,CAAC;IACjDF,OAAO,CAACC,GAAG,CAAC,gCAAgC,EAAE;MAAEd,QAAQ,EAAEW,gBAAgB;MAAEV,KAAK,EAAEW;IAAc,CAAC,CAAC;EACvG,CAAC,EAAE,EAAE,CAAC;;EAEN;EACA;EACA;EACA,MAAMI,QAAQ,GAAI,CAACd,IAAI,IAAIA,IAAI,KAAK,SAAS,GAAIe,SAAS,GAAGf,IAAI,CAACgB,KAAK,CAAC,GAAG,CAAC;EAE5E,oBACIrB,IAAA;IAAKsB,KAAK,EAAE;MAAEC,KAAK,EAAE,MAAM;MAAEC,MAAM,EAAE,OAAO;MAAEC,OAAO,EAAE,MAAM;MAAEC,cAAc,EAAE,QAAQ;MAAEC,UAAU,EAAE,QAAQ;MAAEC,QAAQ,EAAE;IAAS,CAAE;IAAAC,QAAA,eAEhI7B,IAAA;MACIG,QAAQ,EAAEW,gBAAiB;MAC3BV,KAAK,EAAEW,aAAc;MACrBV,IAAI,EAAEc,QAAS;MACf,2BAAyBb,qBAAsB;MAC/CgB,KAAK,EAAE;QAAEC,KAAK,EAAE,MAAM;QAAEC,MAAM,EAAE;MAAO,CAAE;MAAA,GACrCjB;IAAI,CACX;EAAC,CACD,CAAC;AAEd","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import '@esotericsoftware/spine-webcomponents';
3
+ export interface SpineViewProps {
4
+ dom?: import('expo/dom').DOMProps;
5
+ /** Path to the skeleton data file (.json or .skel) */
6
+ skeleton: string;
7
+ /** Path to the atlas file (.atlas) */
8
+ atlas: string;
9
+ /** Name of the animation to play */
10
+ animation?: string;
11
+ /** Name of the skin to use */
12
+ skin?: string;
13
+ /** How the skeleton should fit into the viewport */
14
+ fit?: 'cover' | 'contain' | 'loading' | 'none';
15
+ /** Whether to show debug information */
16
+ debug?: boolean;
17
+ /** Whether to preserve the drawing buffer */
18
+ preserveDrawingBuffer?: boolean;
19
+ /** Raw assets data for embedding */
20
+ rawData?: string;
21
+ /** Any other attributes for spine-skeleton */
22
+ [key: string]: any;
23
+ }
24
+ export default function SpineView({ dom, skeleton, atlas, skin, preserveDrawingBuffer, ...rest }: SpineViewProps): React.JSX.Element;
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAoB,MAAM,OAAO,CAAC;AACzC,OAAO,uCAAuC,CAAC;AAE/C,MAAM,WAAW,cAAc;IAC3B,GAAG,CAAC,EAAE,OAAO,UAAU,EAAE,QAAQ,CAAC;IAClC,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IAC/C,wCAAwC;IACxC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,6CAA6C;IAC7C,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAC9B,GAAG,EACH,QAAQ,EACR,KAAK,EACL,IAAI,EACJ,qBAA4B,EAC5B,GAAG,IAAI,EACV,EAAE,cAAc,qBAuChB"}
package/package.json ADDED
@@ -0,0 +1,97 @@
1
+ {
2
+ "name": "spine-expo-usedom",
3
+ "version": "0.1.0",
4
+ "description": "Spine player for Expo",
5
+ "main": "lib/commonjs/index.js",
6
+ "module": "lib/module/index.js",
7
+ "types": "lib/typescript/index.d.ts",
8
+ "react-native": "src/index.tsx",
9
+ "source": "src/index.tsx",
10
+ "files": [
11
+ "src",
12
+ "lib",
13
+ "android",
14
+ "ios",
15
+ "cpp",
16
+ "*.podspec",
17
+ "!lib/typescript/example",
18
+ "!ios/build",
19
+ "!android/build",
20
+ "!android/gradle",
21
+ "!android/gradlew",
22
+ "!android/gradlew.bat",
23
+ "!android/local.properties",
24
+ "!**/__tests__",
25
+ "!**/__fixtures__",
26
+ "!**/__mocks__",
27
+ "!**/.*"
28
+ ],
29
+ "scripts": {
30
+ "start": "cd example && npx expo start",
31
+ "lint": "eslint \"**/*.{js,ts,tsx}\"",
32
+ "prepare": "bob build",
33
+ "build": "bob build"
34
+ },
35
+ "keywords": [
36
+ "react-native",
37
+ "expo",
38
+ "spine",
39
+ "animation",
40
+ "use dom",
41
+ "web-components"
42
+ ],
43
+ "author": {
44
+ "name": "TheSacredLipton",
45
+ "url": "https://www.npmjs.com/~thesacredlipton"
46
+ },
47
+ "license": "MIT",
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://github.com/TheSacredLipton/expo-spine-usedom.git"
51
+ },
52
+ "bugs": {
53
+ "url": "https://github.com/TheSacredLipton/expo-spine-usedom/issues"
54
+ },
55
+ "homepage": "https://github.com/TheSacredLipton/expo-spine-usedom#readme",
56
+ "publishConfig": {
57
+ "registry": "https://registry.npmjs.org/"
58
+ },
59
+ "devDependencies": {
60
+ "@types/react": "~19.1.0",
61
+ "eslint": "^9.25.0",
62
+ "eslint-config-expo": "~10.0.0",
63
+ "expo": "~54.0.29",
64
+ "react": "19.1.0",
65
+ "react-native": "0.81.5",
66
+ "react-native-builder-bob": "^0.30.0",
67
+ "typescript": "~5.9.2"
68
+ },
69
+ "peerDependencies": {
70
+ "expo": "*",
71
+ "react": "*"
72
+ },
73
+ "react-native-builder-bob": {
74
+ "source": "src",
75
+ "output": "lib",
76
+ "targets": [
77
+ "commonjs",
78
+ "module",
79
+ [
80
+ "typescript",
81
+ {
82
+ "project": "tsconfig.build.json"
83
+ }
84
+ ]
85
+ ]
86
+ },
87
+ "eslintConfig": {
88
+ "root": true,
89
+ "extends": [
90
+ "expo",
91
+ "prettier"
92
+ ]
93
+ },
94
+ "dependencies": {
95
+ "@esotericsoftware/spine-webcomponents": "^4.2.96"
96
+ }
97
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,74 @@
1
+ 'use dom';
2
+
3
+ import React, { useEffect } from 'react';
4
+ import '@esotericsoftware/spine-webcomponents';
5
+
6
+ export interface SpineViewProps {
7
+ dom?: import('expo/dom').DOMProps;
8
+ /** Path to the skeleton data file (.json or .skel) */
9
+ skeleton: string;
10
+ /** Path to the atlas file (.atlas) */
11
+ atlas: string;
12
+ /** Name of the animation to play */
13
+ animation?: string;
14
+ /** Name of the skin to use */
15
+ skin?: string;
16
+ /** How the skeleton should fit into the viewport */
17
+ fit?: 'cover' | 'contain' | 'loading' | 'none';
18
+ /** Whether to show debug information */
19
+ debug?: boolean;
20
+ /** Whether to preserve the drawing buffer */
21
+ preserveDrawingBuffer?: boolean;
22
+ /** Raw assets data for embedding */
23
+ rawData?: string;
24
+ /** Any other attributes for spine-skeleton */
25
+ [key: string]: any;
26
+ }
27
+
28
+ export default function SpineView({
29
+ dom,
30
+ skeleton,
31
+ atlas,
32
+ skin,
33
+ preserveDrawingBuffer = true,
34
+ ...rest
35
+ }: SpineViewProps) {
36
+ // window.location.origin を使って絶対パスを生成
37
+ // process.env.EXPO_BASE_URL が "/" で始まらない場合を考慮してパスを結合
38
+ const origin = typeof window !== 'undefined' ? window.location.origin : '';
39
+
40
+ // URLが相対パスの場合(/で始まる場合)、originを付与する処理を入れると親切かも
41
+ const getAbsolutePath = (path: string) => {
42
+ if (!path) return path;
43
+ if (path.startsWith('http')) return path;
44
+ if (path.startsWith('/')) return `${origin}${path}`;
45
+ return `${origin}/${path}`;
46
+ };
47
+
48
+ const absoluteSkeleton = getAbsolutePath(skeleton);
49
+ const absoluteAtlas = getAbsolutePath(atlas);
50
+
51
+ useEffect(() => {
52
+ console.log('Current URL:', window.location.href);
53
+ console.log('Spine assets paths (absolute):', { skeleton: absoluteSkeleton, atlas: absoluteAtlas });
54
+ }, []);
55
+
56
+ // skin="default" の場合、Spine Web Components でエラーになる場合があるため除外する
57
+ // また、React 19以降ではCustom Elementのプロパティとして渡される際、文字列のままだと
58
+ // コンポーネント内部で配列として扱われた時に1文字ずつ処理されてしまうため、明示的に配列化する
59
+ const skinProp = (!skin || skin === 'default') ? undefined : skin.split(',');
60
+
61
+ return (
62
+ <div style={{ width: '100%', height: '100vh', display: 'flex', justifyContent: 'center', alignItems: 'center', overflow: 'hidden' }}>
63
+ {/* @ts-ignore: Custom element */}
64
+ <spine-skeleton
65
+ skeleton={absoluteSkeleton}
66
+ atlas={absoluteAtlas}
67
+ skin={skinProp}
68
+ preserve-drawing-buffer={preserveDrawingBuffer}
69
+ style={{ width: '100%', height: '100%' }}
70
+ {...rest}
71
+ />
72
+ </div>
73
+ );
74
+ }