anim-3d-obj 2.0.2 → 2.0.5
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/dist/index.cjs +293 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +3 -6
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +52 -12
- package/dist/index.d.ts +52 -12
- package/dist/index.js +270 -27
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,35 +1,303 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var React = require('react');
|
|
3
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
7
|
|
|
8
|
+
function _interopNamespace(e) {
|
|
9
|
+
if (e && e.__esModule) return e;
|
|
10
|
+
var n = Object.create(null);
|
|
11
|
+
if (e) {
|
|
12
|
+
Object.keys(e).forEach(function (k) {
|
|
13
|
+
if (k !== 'default') {
|
|
14
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return e[k]; }
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
27
|
+
|
|
5
28
|
// src/components/Obj.tsx
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
perspectiveOrigin = "50% 50%",
|
|
12
|
-
rotation,
|
|
13
|
-
className,
|
|
14
|
-
style,
|
|
15
|
-
global,
|
|
16
|
-
children
|
|
17
|
-
}) => {
|
|
18
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19
|
-
"div",
|
|
20
|
-
{
|
|
21
|
-
className,
|
|
22
|
-
style: {
|
|
23
|
-
perspective,
|
|
24
|
-
perspectiveOrigin,
|
|
25
|
-
...style
|
|
26
|
-
},
|
|
27
|
-
"data-anim-3d-obj": true,
|
|
28
|
-
children
|
|
29
|
-
}
|
|
29
|
+
|
|
30
|
+
// src/keyframes.ts
|
|
31
|
+
function ensureStyleTag() {
|
|
32
|
+
let tag = document.getElementById(
|
|
33
|
+
"anim3d-keyframes"
|
|
30
34
|
);
|
|
31
|
-
|
|
35
|
+
if (!tag) {
|
|
36
|
+
tag = document.createElement("style");
|
|
37
|
+
tag.id = "anim3d-keyframes";
|
|
38
|
+
document.head.appendChild(tag);
|
|
39
|
+
}
|
|
40
|
+
return tag;
|
|
41
|
+
}
|
|
42
|
+
function inject(css) {
|
|
43
|
+
if (typeof document === "undefined") return;
|
|
44
|
+
const tag = ensureStyleTag();
|
|
45
|
+
tag.appendChild(document.createTextNode(css));
|
|
46
|
+
}
|
|
47
|
+
function builtInKeyframes(name, cfg) {
|
|
48
|
+
const hi = cfg.degreesHi ?? 15;
|
|
49
|
+
const lo = cfg.degreesLow ?? -15;
|
|
50
|
+
switch (name) {
|
|
51
|
+
case "Y360":
|
|
52
|
+
return `@keyframes Y360 { from { transform: rotateY(0deg) } to { transform: rotateY(360deg) } }`;
|
|
53
|
+
case "X360":
|
|
54
|
+
return `@keyframes X360 { from { transform: rotateX(0deg) } to { transform: rotateX(360deg) } }`;
|
|
55
|
+
case "Z360":
|
|
56
|
+
return `@keyframes Z360 { from { transform: rotateZ(0deg) } to { transform: rotateZ(360deg) } }`;
|
|
57
|
+
case "rockY":
|
|
58
|
+
return `@keyframes rockY { 0%{ transform: rotateY(${lo}deg) } 50%{ transform: rotateY(${hi}deg) } 100%{ transform: rotateY(${lo}deg) } }`;
|
|
59
|
+
case "rockX":
|
|
60
|
+
return `@keyframes rockX { 0%{ transform: rotateX(${lo}deg) } 50%{ transform: rotateX(${hi}deg) } 100%{ transform: rotateX(${lo}deg) } }`;
|
|
61
|
+
default:
|
|
62
|
+
return "";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function resolveAnimation(cfg) {
|
|
66
|
+
if (!cfg) return null;
|
|
67
|
+
const name = cfg.name;
|
|
68
|
+
const builtIn = builtInKeyframes(name, cfg);
|
|
69
|
+
if (builtIn) {
|
|
70
|
+
const marker = `/*kf-${name}*/`;
|
|
71
|
+
if (typeof document !== "undefined") {
|
|
72
|
+
const tag = ensureStyleTag();
|
|
73
|
+
if (!tag.innerHTML.includes(marker)) {
|
|
74
|
+
inject(`${builtIn}
|
|
75
|
+
${marker}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return name;
|
|
79
|
+
}
|
|
80
|
+
return name;
|
|
81
|
+
}
|
|
82
|
+
function toAnimationShorthand(cfg) {
|
|
83
|
+
const name = resolveAnimation(cfg);
|
|
84
|
+
if (!cfg || !name) return null;
|
|
85
|
+
const dur = (cfg.duration ?? 10) + "s";
|
|
86
|
+
const delay = (cfg.delay ?? 0) + "s";
|
|
87
|
+
const iter = cfg.iterationCount ?? "infinite";
|
|
88
|
+
const dir = cfg.direction ?? "normal";
|
|
89
|
+
const timing = cfg.timing ?? "linear";
|
|
90
|
+
const fill = cfg.fillMode ?? "forwards";
|
|
91
|
+
const play = cfg.animationPlayState ?? "running";
|
|
92
|
+
return `${name} ${dur} ${timing} ${delay} ${iter} ${dir} ${fill} ${play}`;
|
|
93
|
+
}
|
|
94
|
+
function faceTransform3D(name, w, h, d) {
|
|
95
|
+
const hw = w / 2;
|
|
96
|
+
const hh = h / 2;
|
|
97
|
+
const hd = d / 2;
|
|
98
|
+
switch (name) {
|
|
99
|
+
case "front":
|
|
100
|
+
return `translate(-50%, -50%) translateZ(${hd}px)`;
|
|
101
|
+
case "back":
|
|
102
|
+
return `translate(-50%, -50%) rotateY(180deg) translateZ(${hd}px)`;
|
|
103
|
+
case "left":
|
|
104
|
+
return `translate(-50%, -50%) rotateY(-90deg) translateZ(${hw}px)`;
|
|
105
|
+
case "right":
|
|
106
|
+
return `translate(-50%, -50%) rotateY(90deg) translateZ(${hw}px)`;
|
|
107
|
+
case "top":
|
|
108
|
+
return `translate(-50%, -50%) rotateX(90deg) translateZ(${hh}px)`;
|
|
109
|
+
case "bottom":
|
|
110
|
+
return `translate(-50%, -50%) rotateX(-90deg) translateZ(${hh}px)`;
|
|
111
|
+
case "top_front":
|
|
112
|
+
return `translate(-50%, -50%) rotateX(45deg) translateZ(${hh}px)`;
|
|
113
|
+
case "top_rear":
|
|
114
|
+
return `translate(-50%, -50%) rotateX(135deg) translateZ(${hh}px)`;
|
|
115
|
+
case "bottom_front":
|
|
116
|
+
return `translate(-50%, -50%) rotateX(-45deg) translateZ(${hh}px)`;
|
|
117
|
+
case "bottom_rear":
|
|
118
|
+
return `translate(-50%, -50%) rotateX(-135deg) translateZ(${hh}px)`;
|
|
119
|
+
default:
|
|
120
|
+
return `translate(-50%, -50%) translateZ(${hd}px)`;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function faceTransformFlat(name, w, _h, d) {
|
|
124
|
+
const total = 2 * d + 2 * w;
|
|
125
|
+
const halfTotal = total / 2;
|
|
126
|
+
let cx;
|
|
127
|
+
switch (name) {
|
|
128
|
+
case "left":
|
|
129
|
+
cx = d / 2;
|
|
130
|
+
break;
|
|
131
|
+
case "front":
|
|
132
|
+
cx = d + w / 2;
|
|
133
|
+
break;
|
|
134
|
+
case "right":
|
|
135
|
+
cx = d + w + d / 2;
|
|
136
|
+
break;
|
|
137
|
+
case "back":
|
|
138
|
+
cx = d + w + d + w / 2;
|
|
139
|
+
break;
|
|
140
|
+
case "top":
|
|
141
|
+
case "top_front":
|
|
142
|
+
case "top_rear":
|
|
143
|
+
cx = d + w / 2;
|
|
144
|
+
return `translate(-50%, -50%) translateX(${cx - halfTotal}px) translateY(-${_h}px)`;
|
|
145
|
+
case "bottom":
|
|
146
|
+
case "bottom_front":
|
|
147
|
+
case "bottom_rear":
|
|
148
|
+
cx = d + w / 2;
|
|
149
|
+
return `translate(-50%, -50%) translateX(${cx - halfTotal}px) translateY(${_h}px)`;
|
|
150
|
+
default:
|
|
151
|
+
cx = d + w / 2;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
const offsetX = cx - halfTotal;
|
|
155
|
+
return `translate(-50%, -50%) translateX(${offsetX}px)`;
|
|
156
|
+
}
|
|
157
|
+
function parseCssText(css) {
|
|
158
|
+
if (!css) return {};
|
|
159
|
+
const style = {};
|
|
160
|
+
css.split(";").forEach((rule) => {
|
|
161
|
+
const [prop, ...rest] = rule.split(":");
|
|
162
|
+
if (!prop || rest.length === 0) return;
|
|
163
|
+
const key = prop.trim().replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
164
|
+
style[key] = rest.join(":").trim();
|
|
165
|
+
});
|
|
166
|
+
return style;
|
|
167
|
+
}
|
|
168
|
+
function faceDimensions(name, w, h, d) {
|
|
169
|
+
switch (name) {
|
|
170
|
+
case "left":
|
|
171
|
+
case "right":
|
|
172
|
+
return { width: d, height: h };
|
|
173
|
+
case "top":
|
|
174
|
+
case "bottom":
|
|
175
|
+
case "top_front":
|
|
176
|
+
case "top_rear":
|
|
177
|
+
case "bottom_front":
|
|
178
|
+
case "bottom_rear":
|
|
179
|
+
return { width: w, height: d };
|
|
180
|
+
default:
|
|
181
|
+
return { width: w, height: h };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
var DEFAULT_FACE_NAMES = [
|
|
185
|
+
"front",
|
|
186
|
+
"back",
|
|
187
|
+
"left",
|
|
188
|
+
"right",
|
|
189
|
+
"top",
|
|
190
|
+
"bottom"
|
|
191
|
+
];
|
|
192
|
+
var Obj = React__namespace.memo(
|
|
193
|
+
({
|
|
194
|
+
width = 160,
|
|
195
|
+
height = 160,
|
|
196
|
+
depth = 150,
|
|
197
|
+
perspective = 600,
|
|
198
|
+
perspectiveOrigin = "50% 50%",
|
|
199
|
+
faces,
|
|
200
|
+
global: globalDef,
|
|
201
|
+
anim1,
|
|
202
|
+
anim2,
|
|
203
|
+
showCenterDiv = false,
|
|
204
|
+
flat = false,
|
|
205
|
+
transitionDuration = 1,
|
|
206
|
+
className,
|
|
207
|
+
style
|
|
208
|
+
}) => {
|
|
209
|
+
const w = typeof width === "number" ? width : parseFloat(width);
|
|
210
|
+
const h = typeof height === "number" ? height : parseFloat(height);
|
|
211
|
+
const d = typeof depth === "number" ? depth : parseFloat(depth);
|
|
212
|
+
const animation1 = toAnimationShorthand(anim1) ?? void 0;
|
|
213
|
+
const animation2 = toAnimationShorthand(anim2) ?? void 0;
|
|
214
|
+
const faceList = faces && faces.length > 0 ? faces : DEFAULT_FACE_NAMES.map((name) => ({ name }));
|
|
215
|
+
const transitionCss = `transform ${transitionDuration}s ease-in-out`;
|
|
216
|
+
const renderFace = (face, i) => {
|
|
217
|
+
const dims = faceDimensions(face.name, w, h, d);
|
|
218
|
+
const transform = flat ? faceTransformFlat(face.name, w, h, d) : faceTransform3D(face.name, w, h, d);
|
|
219
|
+
const globalStyle = parseCssText(globalDef?.css);
|
|
220
|
+
const faceInlineStyle = parseCssText(face.css);
|
|
221
|
+
const mergedStyle = {
|
|
222
|
+
...globalStyle,
|
|
223
|
+
...globalDef?.style ?? {},
|
|
224
|
+
...faceInlineStyle,
|
|
225
|
+
...face.style ?? {},
|
|
226
|
+
width: dims.width,
|
|
227
|
+
height: dims.height,
|
|
228
|
+
transform,
|
|
229
|
+
transition: transitionCss
|
|
230
|
+
};
|
|
231
|
+
const body = face.body ?? globalDef?.body ?? null;
|
|
232
|
+
const faceClassName = [
|
|
233
|
+
"anim3d-face",
|
|
234
|
+
face.className
|
|
235
|
+
].filter(Boolean).join(" ");
|
|
236
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
237
|
+
"div",
|
|
238
|
+
{
|
|
239
|
+
className: faceClassName,
|
|
240
|
+
style: mergedStyle,
|
|
241
|
+
children: body
|
|
242
|
+
},
|
|
243
|
+
face.name + "-" + i
|
|
244
|
+
);
|
|
245
|
+
};
|
|
246
|
+
const cssVars = {
|
|
247
|
+
"--obj-w": w + "px",
|
|
248
|
+
"--obj-h": h + "px",
|
|
249
|
+
"--obj-d": d + "px"
|
|
250
|
+
};
|
|
251
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
252
|
+
"div",
|
|
253
|
+
{
|
|
254
|
+
className: ["anim3d-stage", className].filter(Boolean).join(" "),
|
|
255
|
+
style: {
|
|
256
|
+
perspective: flat ? "none" : perspective,
|
|
257
|
+
perspectiveOrigin,
|
|
258
|
+
...cssVars,
|
|
259
|
+
...style
|
|
260
|
+
},
|
|
261
|
+
"data-anim-3d-obj": true,
|
|
262
|
+
role: "img",
|
|
263
|
+
"aria-label": "3D object",
|
|
264
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
265
|
+
"div",
|
|
266
|
+
{
|
|
267
|
+
className: "anim3d-wrapper",
|
|
268
|
+
style: {
|
|
269
|
+
...cssVars,
|
|
270
|
+
animation: flat ? "none" : animation1,
|
|
271
|
+
transformStyle: "preserve-3d",
|
|
272
|
+
transition: transitionCss
|
|
273
|
+
},
|
|
274
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
275
|
+
"div",
|
|
276
|
+
{
|
|
277
|
+
className: "anim3d-wrapper",
|
|
278
|
+
style: {
|
|
279
|
+
...cssVars,
|
|
280
|
+
animation: flat ? "none" : animation2,
|
|
281
|
+
transformStyle: "preserve-3d",
|
|
282
|
+
transition: transitionCss
|
|
283
|
+
},
|
|
284
|
+
children: [
|
|
285
|
+
showCenterDiv && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "anim3d-center" }),
|
|
286
|
+
faceList.map(renderFace)
|
|
287
|
+
]
|
|
288
|
+
}
|
|
289
|
+
)
|
|
290
|
+
}
|
|
291
|
+
)
|
|
292
|
+
}
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
Obj.displayName = "Obj";
|
|
32
297
|
|
|
33
298
|
exports.Obj = Obj;
|
|
299
|
+
exports.default = Obj;
|
|
300
|
+
exports.resolveAnimation = resolveAnimation;
|
|
301
|
+
exports.toAnimationShorthand = toAnimationShorthand;
|
|
34
302
|
//# sourceMappingURL=index.cjs.map
|
|
35
303
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Obj.tsx"],"names":["jsx"],"mappings":";;;;;AAmBO,IAAM,MAA0B,CAAC;AAAA,EACrC,KAAA,GAAQ,OAAA;AAAA,EACR,MAAA,GAAS,OAAA;AAAA,EACT,KAAA,GAAQ,OAAA;AAAA,EACR,WAAA,GAAc,GAAA;AAAA,EACd,iBAAA,GAAoB,SAAA;AAAA,EACpB,QAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA;AACH,CAAA,KAAM;AAEH,EAAA,uBACGA,cAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACE,SAAA;AAAA,MACA,KAAA,EAAO;AAAA,QACJ,WAAA;AAAA,QACA,iBAAA;AAAA,QACA,GAAG;AAAA,OACN;AAAA,MACA,kBAAA,EAAgB,IAAA;AAAA,MAGf;AAAA;AAAA,GACJ;AAEN","file":"index.cjs","sourcesContent":["import * as React from \"react\";\nimport \"./../styles/obj.css\";\n\nexport type ObjProps = {\n width?: string | number;\n height?: string | number;\n depth?: string | number;\n perspective?: string | number;\n perspectiveOrigin?: string;\n rotation?: string; // e.g., \"x 1s linear infinite\"\n className?: string;\n style?: React.CSSProperties;\n global?: {\n css?: string;\n body?: string;\n };\n children?: React.ReactNode;\n};\n\nexport const Obj: React.FC<ObjProps> = ({\n width = \"160px\",\n height = \"160px\",\n depth = \"150px\",\n perspective = 500,\n perspectiveOrigin = \"50% 50%\",\n rotation,\n className,\n style,\n global,\n children,\n}) => {\n // … your existing DOM/CSS 3D layout & animations\n return (\n <div\n className={className}\n style={{\n perspective,\n perspectiveOrigin,\n ...style,\n }}\n data-anim-3d-obj\n >\n {/* faces, wrappers, animations… */}\n {children}\n </div>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/keyframes.ts","../src/components/Obj.tsx"],"names":["React","jsx","jsxs"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { AnimationConfig } from \"./types\";\n\n/** Create (or reuse) a <style> tag for dynamic keyframes */\nfunction ensureStyleTag(): HTMLStyleElement {\n let tag = document.getElementById(\n \"anim3d-keyframes\"\n ) as HTMLStyleElement | null;\n if (!tag) {\n tag = document.createElement(\"style\");\n tag.id = \"anim3d-keyframes\";\n document.head.appendChild(tag);\n }\n return tag;\n}\n\nfunction inject(css: string) {\n if (typeof document === \"undefined\") return; // SSR\n const tag = ensureStyleTag();\n tag.appendChild(document.createTextNode(css));\n}\n\n/** Keyframes text for built-ins */\nfunction builtInKeyframes(name: string, cfg: AnimationConfig) {\n const hi = cfg.degreesHi ?? 15;\n const lo = cfg.degreesLow ?? -15;\n switch (name) {\n case \"Y360\":\n return `@keyframes Y360 { from { transform: rotateY(0deg) } to { transform: rotateY(360deg) } }`;\n case \"X360\":\n return `@keyframes X360 { from { transform: rotateX(0deg) } to { transform: rotateX(360deg) } }`;\n case \"Z360\":\n return `@keyframes Z360 { from { transform: rotateZ(0deg) } to { transform: rotateZ(360deg) } }`;\n case \"rockY\":\n return `@keyframes rockY { 0%{ transform: rotateY(${lo}deg) } 50%{ transform: rotateY(${hi}deg) } 100%{ transform: rotateY(${lo}deg) } }`;\n case \"rockX\":\n return `@keyframes rockX { 0%{ transform: rotateX(${lo}deg) } 50%{ transform: rotateX(${hi}deg) } 100%{ transform: rotateX(${lo}deg) } }`;\n default:\n // Custom names: let authors supply their own @keyframes in global CSS with that name.\n return \"\";\n }\n}\n\n/** Returns a concrete animation-name and ensures keyframes exist (for built-ins) */\nexport function resolveAnimation(cfg?: AnimationConfig): string | null {\n if (!cfg) return null;\n const name = cfg.name;\n const builtIn = builtInKeyframes(name, cfg);\n if (builtIn) {\n // Ensure single injection per built-in name\n const marker = `/*kf-${name}*/`;\n if (typeof document !== \"undefined\") {\n const tag = ensureStyleTag();\n if (!tag.innerHTML.includes(marker)) {\n inject(`${builtIn}\\n${marker}`);\n }\n }\n return name; // use built-in name as animation-name\n }\n // custom: use author-provided @keyframes by name\n return name;\n}\n\n/** Build the full CSS animation shorthand from a config and resolved name */\nexport function toAnimationShorthand(cfg?: AnimationConfig): string | null {\n const name = resolveAnimation(cfg);\n if (!cfg || !name) return null;\n const dur = (cfg.duration ?? 10) + \"s\";\n const delay = (cfg.delay ?? 0) + \"s\";\n const iter = cfg.iterationCount ?? \"infinite\";\n const dir = cfg.direction ?? \"normal\";\n const timing = cfg.timing ?? \"linear\";\n const fill = cfg.fillMode ?? \"forwards\";\n const play = cfg.animationPlayState ?? \"running\";\n // name duration timing delay iteration-count direction fill-mode play-state\n return `${name} ${dur} ${timing} ${delay} ${iter} ${dir} ${fill} ${play}`;\n}\n","import * as React from \"react\";\nimport type {\n ObjProps,\n FaceDef,\n FaceName,\n GlobalDef,\n} from \"../types\";\nimport { toAnimationShorthand } from \"../keyframes\";\nimport \"../styles/obj.css\";\n\n// Re-export the canonical ObjProps from types.ts\nexport type { ObjProps } from \"../types\";\n\n/* ------------------------------------------------------------------ */\n/* Face transform — 3D cuboid positions */\n/* ------------------------------------------------------------------ */\n\nfunction faceTransform3D(\n name: string,\n w: number,\n h: number,\n d: number\n): string {\n const hw = w / 2;\n const hh = h / 2;\n const hd = d / 2;\n\n switch (name as FaceName) {\n case \"front\":\n return `translate(-50%, -50%) translateZ(${hd}px)`;\n case \"back\":\n return `translate(-50%, -50%) rotateY(180deg) translateZ(${hd}px)`;\n case \"left\":\n return `translate(-50%, -50%) rotateY(-90deg) translateZ(${hw}px)`;\n case \"right\":\n return `translate(-50%, -50%) rotateY(90deg) translateZ(${hw}px)`;\n case \"top\":\n return `translate(-50%, -50%) rotateX(90deg) translateZ(${hh}px)`;\n case \"bottom\":\n return `translate(-50%, -50%) rotateX(-90deg) translateZ(${hh}px)`;\n case \"top_front\":\n return `translate(-50%, -50%) rotateX(45deg) translateZ(${hh}px)`;\n case \"top_rear\":\n return `translate(-50%, -50%) rotateX(135deg) translateZ(${hh}px)`;\n case \"bottom_front\":\n return `translate(-50%, -50%) rotateX(-45deg) translateZ(${hh}px)`;\n case \"bottom_rear\":\n return `translate(-50%, -50%) rotateX(-135deg) translateZ(${hh}px)`;\n default:\n return `translate(-50%, -50%) translateZ(${hd}px)`;\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Face transform — flat (unfolded) positions */\n/* */\n/* Layout order: … | left | front | right | back | … */\n/* Centered on the midpoint of the full row. */\n/* ------------------------------------------------------------------ */\n\n/** Ordered face names for the flat row (left-to-right) */\nconst FLAT_ORDER: FaceName[] = [\"left\", \"front\", \"right\", \"back\"];\n\n/**\n * Returns the flat-layout transform for a face.\n *\n * Side faces (left, right) have a rendered width of `d` (depth).\n * Front/back faces have a rendered width of `w`.\n * Row order: left(d) | front(w) | right(d) | back(w)\n * Total row width = 2d + 2w. We centre the row on 0.\n */\nfunction faceTransformFlat(\n name: string,\n w: number,\n _h: number,\n d: number\n): string {\n // Total row width\n const total = 2 * d + 2 * w;\n const halfTotal = total / 2;\n\n // Cumulative left-edge x positions (relative to row start = 0)\n // left : 0 width d\n // front : d width w\n // right : d + w width d\n // back : d + w + d width w\n let cx: number; // centre-x of this face in the row\n\n switch (name as FaceName) {\n case \"left\":\n cx = d / 2;\n break;\n case \"front\":\n cx = d + w / 2;\n break;\n case \"right\":\n cx = d + w + d / 2;\n break;\n case \"back\":\n cx = d + w + d + w / 2;\n break;\n case \"top\":\n case \"top_front\":\n case \"top_rear\":\n // Top faces slide upward out of the way\n cx = d + w / 2;\n return `translate(-50%, -50%) translateX(${cx - halfTotal}px) translateY(-${_h}px)`;\n case \"bottom\":\n case \"bottom_front\":\n case \"bottom_rear\":\n cx = d + w / 2;\n return `translate(-50%, -50%) translateX(${cx - halfTotal}px) translateY(${_h}px)`;\n default:\n cx = d + w / 2;\n break;\n }\n\n // Shift so the row is centred on x=0\n const offsetX = cx - halfTotal;\n return `translate(-50%, -50%) translateX(${offsetX}px)`;\n}\n\n/* ------------------------------------------------------------------ */\n/* Parse a legacy CSS text string into a CSSProperties object */\n/* ------------------------------------------------------------------ */\n\nfunction parseCssText(css?: string): React.CSSProperties {\n if (!css) return {};\n const style: Record<string, string> = {};\n css.split(\";\").forEach((rule) => {\n const [prop, ...rest] = rule.split(\":\");\n if (!prop || rest.length === 0) return;\n const key = prop\n .trim()\n .replace(/-([a-z])/g, (_, c) => c.toUpperCase());\n style[key] = rest.join(\":\").trim();\n });\n return style as React.CSSProperties;\n}\n\n/* ------------------------------------------------------------------ */\n/* Resolve face dimensions for non-standard faces */\n/* ------------------------------------------------------------------ */\n\nfunction faceDimensions(\n name: string,\n w: number,\n h: number,\n d: number\n): { width: number; height: number } {\n switch (name as FaceName) {\n case \"left\":\n case \"right\":\n return { width: d, height: h };\n case \"top\":\n case \"bottom\":\n case \"top_front\":\n case \"top_rear\":\n case \"bottom_front\":\n case \"bottom_rear\":\n return { width: w, height: d };\n default:\n return { width: w, height: h };\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Default 6-sided cube when no faces are provided */\n/* ------------------------------------------------------------------ */\n\nconst DEFAULT_FACE_NAMES: FaceName[] = [\n \"front\",\n \"back\",\n \"left\",\n \"right\",\n \"top\",\n \"bottom\",\n];\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport const Obj: React.FC<ObjProps> = React.memo(\n ({\n width = 160,\n height = 160,\n depth = 150,\n perspective = 600,\n perspectiveOrigin = \"50% 50%\",\n faces,\n global: globalDef,\n anim1,\n anim2,\n showCenterDiv = false,\n flat = false,\n transitionDuration = 1,\n className,\n style,\n }) => {\n const w = typeof width === \"number\" ? width : parseFloat(width);\n const h = typeof height === \"number\" ? height : parseFloat(height);\n const d = typeof depth === \"number\" ? depth : parseFloat(depth);\n\n // Resolve animation shorthands\n const animation1 = toAnimationShorthand(anim1) ?? undefined;\n const animation2 = toAnimationShorthand(anim2) ?? undefined;\n\n // Determine which faces to render\n const faceList: FaceDef[] =\n faces && faces.length > 0\n ? faces\n : DEFAULT_FACE_NAMES.map((name) => ({ name }));\n\n const transitionCss = `transform ${transitionDuration}s ease-in-out`;\n\n // Merge global defaults into each face\n const renderFace = (face: FaceDef, i: number) => {\n const dims = faceDimensions(face.name, w, h, d);\n const transform = flat\n ? faceTransformFlat(face.name, w, h, d)\n : faceTransform3D(face.name, w, h, d);\n\n const globalStyle = parseCssText(globalDef?.css);\n const faceInlineStyle = parseCssText(face.css);\n\n const mergedStyle: React.CSSProperties = {\n ...globalStyle,\n ...(globalDef?.style ?? {}),\n ...faceInlineStyle,\n ...(face.style ?? {}),\n width: dims.width,\n height: dims.height,\n transform,\n transition: transitionCss,\n };\n\n const body = face.body ?? globalDef?.body ?? null;\n const faceClassName = [\n \"anim3d-face\",\n face.className,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n key={face.name + \"-\" + i}\n className={faceClassName}\n style={mergedStyle}\n >\n {body}\n </div>\n );\n };\n\n const cssVars = {\n \"--obj-w\": w + \"px\",\n \"--obj-h\": h + \"px\",\n \"--obj-d\": d + \"px\",\n } as React.CSSProperties;\n\n return (\n <div\n className={[\"anim3d-stage\", className].filter(Boolean).join(\" \")}\n style={{\n perspective: flat ? \"none\" : perspective,\n perspectiveOrigin,\n ...cssVars,\n ...style,\n }}\n data-anim-3d-obj\n role=\"img\"\n aria-label=\"3D object\"\n >\n {/* Outer animation wrapper (anim1) */}\n <div\n className=\"anim3d-wrapper\"\n style={{\n ...cssVars,\n animation: flat ? \"none\" : animation1,\n transformStyle: \"preserve-3d\",\n transition: transitionCss,\n }}\n >\n {/* Inner animation wrapper (anim2) */}\n <div\n className=\"anim3d-wrapper\"\n style={{\n ...cssVars,\n animation: flat ? \"none\" : animation2,\n transformStyle: \"preserve-3d\",\n transition: transitionCss,\n }}\n >\n {showCenterDiv && <div className=\"anim3d-center\" />}\n {faceList.map(renderFace)}\n </div>\n </div>\n </div>\n );\n }\n);\n\nObj.displayName = \"Obj\";\n"]}
|
package/dist/index.css
CHANGED
|
@@ -3,14 +3,12 @@
|
|
|
3
3
|
position: relative;
|
|
4
4
|
width: max-content;
|
|
5
5
|
height: max-content;
|
|
6
|
-
perspective: 600px;
|
|
7
|
-
perspective-origin: 50% 50%;
|
|
8
6
|
}
|
|
9
7
|
.anim3d-wrapper {
|
|
10
8
|
position: relative;
|
|
11
9
|
transform-style: preserve-3d;
|
|
12
|
-
width: var(--obj-w);
|
|
13
|
-
height: var(--obj-h);
|
|
10
|
+
width: var(--obj-w, 160px);
|
|
11
|
+
height: var(--obj-h, 160px);
|
|
14
12
|
}
|
|
15
13
|
.anim3d-center {
|
|
16
14
|
position: absolute;
|
|
@@ -21,13 +19,12 @@
|
|
|
21
19
|
background: #f00;
|
|
22
20
|
transform: translate(-50%, -50%);
|
|
23
21
|
z-index: 10;
|
|
22
|
+
pointer-events: none;
|
|
24
23
|
}
|
|
25
24
|
.anim3d-face {
|
|
26
25
|
position: absolute;
|
|
27
26
|
left: 50%;
|
|
28
27
|
top: 50%;
|
|
29
|
-
width: var(--obj-w);
|
|
30
|
-
height: var(--obj-h);
|
|
31
28
|
transform-style: preserve-3d;
|
|
32
29
|
display: flex;
|
|
33
30
|
align-items: center;
|
package/dist/index.css.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/styles/obj.css"],"sourcesContent":[".anim3d-stage {\n position: relative;\n width: max-content;\n height: max-content;\n
|
|
1
|
+
{"version":3,"sources":["../src/styles/obj.css"],"sourcesContent":[".anim3d-stage {\n position: relative;\n width: max-content;\n height: max-content;\n /* perspective is set inline via props */\n}\n\n.anim3d-wrapper {\n position: relative;\n transform-style: preserve-3d;\n width: var(--obj-w, 160px);\n height: var(--obj-h, 160px);\n}\n\n.anim3d-center {\n position: absolute;\n left: 50%;\n top: 50%;\n width: 2px;\n height: 2px;\n background: #f00;\n transform: translate(-50%, -50%);\n z-index: 10;\n pointer-events: none;\n}\n\n.anim3d-face {\n position: absolute;\n left: 50%;\n top: 50%;\n transform-style: preserve-3d;\n display: flex;\n align-items: center;\n justify-content: center;\n backface-visibility: visible;\n box-sizing: border-box;\n /* width/height/transform set inline per face */\n}\n"],"mappings":";AAAA,CAAC;AACE,YAAU;AACV,SAAO;AACP,UAAQ;AAEX;AAEA,CAAC;AACE,YAAU;AACV,mBAAiB;AACjB,SAAO,IAAI,OAAO,EAAE;AACpB,UAAQ,IAAI,OAAO,EAAE;AACxB;AAEA,CAAC;AACE,YAAU;AACV,QAAM;AACN,OAAK;AACL,SAAO;AACP,UAAQ;AACR,cAAY;AACZ,aAAW,UAAU,IAAI,EAAE;AAC3B,WAAS;AACT,kBAAgB;AACnB;AAEA,CAAC;AACE,YAAU;AACV,QAAM;AACN,OAAK;AACL,mBAAiB;AACjB,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,uBAAqB;AACrB,cAAY;AAEf;","names":[]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,20 +1,60 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
3
|
|
|
4
|
+
type AnimationDirection = "normal" | "reverse" | "alternate" | "alternate-reverse";
|
|
5
|
+
type AnimationFill = "none" | "forwards" | "backwards" | "both";
|
|
6
|
+
type AnimationPlayState = "running" | "paused";
|
|
7
|
+
type TimingFn = "linear" | "ease" | "ease-in" | "ease-out" | "ease-in-out" | string;
|
|
8
|
+
type BuiltInAnimName = "Y360" | "X360" | "Z360" | "rockY" | "rockX";
|
|
9
|
+
type AnimationConfig = {
|
|
10
|
+
name: BuiltInAnimName | string;
|
|
11
|
+
degreesHi?: number;
|
|
12
|
+
degreesLow?: number;
|
|
13
|
+
duration?: number;
|
|
14
|
+
delay?: number;
|
|
15
|
+
iterationCount?: number | "infinite";
|
|
16
|
+
direction?: AnimationDirection;
|
|
17
|
+
timing?: TimingFn;
|
|
18
|
+
fillMode?: AnimationFill;
|
|
19
|
+
animationPlayState?: AnimationPlayState;
|
|
20
|
+
};
|
|
21
|
+
type FaceName = "front" | "back" | "left" | "right" | "top" | "bottom" | "top_rear" | "top_front" | "bottom_rear" | "bottom_front";
|
|
22
|
+
type FaceDef = {
|
|
23
|
+
name: FaceName | string;
|
|
24
|
+
css?: string;
|
|
25
|
+
style?: CSSProperties;
|
|
26
|
+
body?: ReactNode | string;
|
|
27
|
+
className?: string;
|
|
28
|
+
};
|
|
29
|
+
type GlobalDef = {
|
|
30
|
+
css?: string;
|
|
31
|
+
style?: CSSProperties;
|
|
32
|
+
body?: ReactNode | string;
|
|
33
|
+
};
|
|
3
34
|
type ObjProps = {
|
|
4
|
-
width?:
|
|
5
|
-
height?:
|
|
6
|
-
depth?:
|
|
7
|
-
perspective?:
|
|
35
|
+
width?: number;
|
|
36
|
+
height?: number;
|
|
37
|
+
depth?: number;
|
|
38
|
+
perspective?: number;
|
|
8
39
|
perspectiveOrigin?: string;
|
|
9
|
-
|
|
40
|
+
faces?: FaceDef[];
|
|
41
|
+
global?: GlobalDef;
|
|
42
|
+
anim1?: AnimationConfig;
|
|
43
|
+
anim2?: AnimationConfig;
|
|
44
|
+
showCenterDiv?: boolean;
|
|
45
|
+
/** When true, faces unfold from 3D cuboid into a flat side-by-side row */
|
|
46
|
+
flat?: boolean;
|
|
47
|
+
/** Seconds for the fold/unfold transition (default 1) */
|
|
48
|
+
transitionDuration?: number;
|
|
10
49
|
className?: string;
|
|
11
|
-
style?:
|
|
12
|
-
global?: {
|
|
13
|
-
css?: string;
|
|
14
|
-
body?: string;
|
|
15
|
-
};
|
|
16
|
-
children?: React.ReactNode;
|
|
50
|
+
style?: CSSProperties;
|
|
17
51
|
};
|
|
52
|
+
|
|
18
53
|
declare const Obj: React.FC<ObjProps>;
|
|
19
54
|
|
|
20
|
-
|
|
55
|
+
/** Returns a concrete animation-name and ensures keyframes exist (for built-ins) */
|
|
56
|
+
declare function resolveAnimation(cfg?: AnimationConfig): string | null;
|
|
57
|
+
/** Build the full CSS animation shorthand from a config and resolved name */
|
|
58
|
+
declare function toAnimationShorthand(cfg?: AnimationConfig): string | null;
|
|
59
|
+
|
|
60
|
+
export { type AnimationConfig, type AnimationDirection, type AnimationFill, type AnimationPlayState, type BuiltInAnimName, type FaceDef, type FaceName, type GlobalDef, Obj, type ObjProps, type TimingFn, Obj as default, resolveAnimation, toAnimationShorthand };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,20 +1,60 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
3
|
|
|
4
|
+
type AnimationDirection = "normal" | "reverse" | "alternate" | "alternate-reverse";
|
|
5
|
+
type AnimationFill = "none" | "forwards" | "backwards" | "both";
|
|
6
|
+
type AnimationPlayState = "running" | "paused";
|
|
7
|
+
type TimingFn = "linear" | "ease" | "ease-in" | "ease-out" | "ease-in-out" | string;
|
|
8
|
+
type BuiltInAnimName = "Y360" | "X360" | "Z360" | "rockY" | "rockX";
|
|
9
|
+
type AnimationConfig = {
|
|
10
|
+
name: BuiltInAnimName | string;
|
|
11
|
+
degreesHi?: number;
|
|
12
|
+
degreesLow?: number;
|
|
13
|
+
duration?: number;
|
|
14
|
+
delay?: number;
|
|
15
|
+
iterationCount?: number | "infinite";
|
|
16
|
+
direction?: AnimationDirection;
|
|
17
|
+
timing?: TimingFn;
|
|
18
|
+
fillMode?: AnimationFill;
|
|
19
|
+
animationPlayState?: AnimationPlayState;
|
|
20
|
+
};
|
|
21
|
+
type FaceName = "front" | "back" | "left" | "right" | "top" | "bottom" | "top_rear" | "top_front" | "bottom_rear" | "bottom_front";
|
|
22
|
+
type FaceDef = {
|
|
23
|
+
name: FaceName | string;
|
|
24
|
+
css?: string;
|
|
25
|
+
style?: CSSProperties;
|
|
26
|
+
body?: ReactNode | string;
|
|
27
|
+
className?: string;
|
|
28
|
+
};
|
|
29
|
+
type GlobalDef = {
|
|
30
|
+
css?: string;
|
|
31
|
+
style?: CSSProperties;
|
|
32
|
+
body?: ReactNode | string;
|
|
33
|
+
};
|
|
3
34
|
type ObjProps = {
|
|
4
|
-
width?:
|
|
5
|
-
height?:
|
|
6
|
-
depth?:
|
|
7
|
-
perspective?:
|
|
35
|
+
width?: number;
|
|
36
|
+
height?: number;
|
|
37
|
+
depth?: number;
|
|
38
|
+
perspective?: number;
|
|
8
39
|
perspectiveOrigin?: string;
|
|
9
|
-
|
|
40
|
+
faces?: FaceDef[];
|
|
41
|
+
global?: GlobalDef;
|
|
42
|
+
anim1?: AnimationConfig;
|
|
43
|
+
anim2?: AnimationConfig;
|
|
44
|
+
showCenterDiv?: boolean;
|
|
45
|
+
/** When true, faces unfold from 3D cuboid into a flat side-by-side row */
|
|
46
|
+
flat?: boolean;
|
|
47
|
+
/** Seconds for the fold/unfold transition (default 1) */
|
|
48
|
+
transitionDuration?: number;
|
|
10
49
|
className?: string;
|
|
11
|
-
style?:
|
|
12
|
-
global?: {
|
|
13
|
-
css?: string;
|
|
14
|
-
body?: string;
|
|
15
|
-
};
|
|
16
|
-
children?: React.ReactNode;
|
|
50
|
+
style?: CSSProperties;
|
|
17
51
|
};
|
|
52
|
+
|
|
18
53
|
declare const Obj: React.FC<ObjProps>;
|
|
19
54
|
|
|
20
|
-
|
|
55
|
+
/** Returns a concrete animation-name and ensures keyframes exist (for built-ins) */
|
|
56
|
+
declare function resolveAnimation(cfg?: AnimationConfig): string | null;
|
|
57
|
+
/** Build the full CSS animation shorthand from a config and resolved name */
|
|
58
|
+
declare function toAnimationShorthand(cfg?: AnimationConfig): string | null;
|
|
59
|
+
|
|
60
|
+
export { type AnimationConfig, type AnimationDirection, type AnimationFill, type AnimationPlayState, type BuiltInAnimName, type FaceDef, type FaceName, type GlobalDef, Obj, type ObjProps, type TimingFn, Obj as default, resolveAnimation, toAnimationShorthand };
|
package/dist/index.js
CHANGED
|
@@ -1,33 +1,276 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
3
|
|
|
3
4
|
// src/components/Obj.tsx
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
perspectiveOrigin = "50% 50%",
|
|
10
|
-
rotation,
|
|
11
|
-
className,
|
|
12
|
-
style,
|
|
13
|
-
global,
|
|
14
|
-
children
|
|
15
|
-
}) => {
|
|
16
|
-
return /* @__PURE__ */ jsx(
|
|
17
|
-
"div",
|
|
18
|
-
{
|
|
19
|
-
className,
|
|
20
|
-
style: {
|
|
21
|
-
perspective,
|
|
22
|
-
perspectiveOrigin,
|
|
23
|
-
...style
|
|
24
|
-
},
|
|
25
|
-
"data-anim-3d-obj": true,
|
|
26
|
-
children
|
|
27
|
-
}
|
|
5
|
+
|
|
6
|
+
// src/keyframes.ts
|
|
7
|
+
function ensureStyleTag() {
|
|
8
|
+
let tag = document.getElementById(
|
|
9
|
+
"anim3d-keyframes"
|
|
28
10
|
);
|
|
29
|
-
|
|
11
|
+
if (!tag) {
|
|
12
|
+
tag = document.createElement("style");
|
|
13
|
+
tag.id = "anim3d-keyframes";
|
|
14
|
+
document.head.appendChild(tag);
|
|
15
|
+
}
|
|
16
|
+
return tag;
|
|
17
|
+
}
|
|
18
|
+
function inject(css) {
|
|
19
|
+
if (typeof document === "undefined") return;
|
|
20
|
+
const tag = ensureStyleTag();
|
|
21
|
+
tag.appendChild(document.createTextNode(css));
|
|
22
|
+
}
|
|
23
|
+
function builtInKeyframes(name, cfg) {
|
|
24
|
+
const hi = cfg.degreesHi ?? 15;
|
|
25
|
+
const lo = cfg.degreesLow ?? -15;
|
|
26
|
+
switch (name) {
|
|
27
|
+
case "Y360":
|
|
28
|
+
return `@keyframes Y360 { from { transform: rotateY(0deg) } to { transform: rotateY(360deg) } }`;
|
|
29
|
+
case "X360":
|
|
30
|
+
return `@keyframes X360 { from { transform: rotateX(0deg) } to { transform: rotateX(360deg) } }`;
|
|
31
|
+
case "Z360":
|
|
32
|
+
return `@keyframes Z360 { from { transform: rotateZ(0deg) } to { transform: rotateZ(360deg) } }`;
|
|
33
|
+
case "rockY":
|
|
34
|
+
return `@keyframes rockY { 0%{ transform: rotateY(${lo}deg) } 50%{ transform: rotateY(${hi}deg) } 100%{ transform: rotateY(${lo}deg) } }`;
|
|
35
|
+
case "rockX":
|
|
36
|
+
return `@keyframes rockX { 0%{ transform: rotateX(${lo}deg) } 50%{ transform: rotateX(${hi}deg) } 100%{ transform: rotateX(${lo}deg) } }`;
|
|
37
|
+
default:
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function resolveAnimation(cfg) {
|
|
42
|
+
if (!cfg) return null;
|
|
43
|
+
const name = cfg.name;
|
|
44
|
+
const builtIn = builtInKeyframes(name, cfg);
|
|
45
|
+
if (builtIn) {
|
|
46
|
+
const marker = `/*kf-${name}*/`;
|
|
47
|
+
if (typeof document !== "undefined") {
|
|
48
|
+
const tag = ensureStyleTag();
|
|
49
|
+
if (!tag.innerHTML.includes(marker)) {
|
|
50
|
+
inject(`${builtIn}
|
|
51
|
+
${marker}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return name;
|
|
55
|
+
}
|
|
56
|
+
return name;
|
|
57
|
+
}
|
|
58
|
+
function toAnimationShorthand(cfg) {
|
|
59
|
+
const name = resolveAnimation(cfg);
|
|
60
|
+
if (!cfg || !name) return null;
|
|
61
|
+
const dur = (cfg.duration ?? 10) + "s";
|
|
62
|
+
const delay = (cfg.delay ?? 0) + "s";
|
|
63
|
+
const iter = cfg.iterationCount ?? "infinite";
|
|
64
|
+
const dir = cfg.direction ?? "normal";
|
|
65
|
+
const timing = cfg.timing ?? "linear";
|
|
66
|
+
const fill = cfg.fillMode ?? "forwards";
|
|
67
|
+
const play = cfg.animationPlayState ?? "running";
|
|
68
|
+
return `${name} ${dur} ${timing} ${delay} ${iter} ${dir} ${fill} ${play}`;
|
|
69
|
+
}
|
|
70
|
+
function faceTransform3D(name, w, h, d) {
|
|
71
|
+
const hw = w / 2;
|
|
72
|
+
const hh = h / 2;
|
|
73
|
+
const hd = d / 2;
|
|
74
|
+
switch (name) {
|
|
75
|
+
case "front":
|
|
76
|
+
return `translate(-50%, -50%) translateZ(${hd}px)`;
|
|
77
|
+
case "back":
|
|
78
|
+
return `translate(-50%, -50%) rotateY(180deg) translateZ(${hd}px)`;
|
|
79
|
+
case "left":
|
|
80
|
+
return `translate(-50%, -50%) rotateY(-90deg) translateZ(${hw}px)`;
|
|
81
|
+
case "right":
|
|
82
|
+
return `translate(-50%, -50%) rotateY(90deg) translateZ(${hw}px)`;
|
|
83
|
+
case "top":
|
|
84
|
+
return `translate(-50%, -50%) rotateX(90deg) translateZ(${hh}px)`;
|
|
85
|
+
case "bottom":
|
|
86
|
+
return `translate(-50%, -50%) rotateX(-90deg) translateZ(${hh}px)`;
|
|
87
|
+
case "top_front":
|
|
88
|
+
return `translate(-50%, -50%) rotateX(45deg) translateZ(${hh}px)`;
|
|
89
|
+
case "top_rear":
|
|
90
|
+
return `translate(-50%, -50%) rotateX(135deg) translateZ(${hh}px)`;
|
|
91
|
+
case "bottom_front":
|
|
92
|
+
return `translate(-50%, -50%) rotateX(-45deg) translateZ(${hh}px)`;
|
|
93
|
+
case "bottom_rear":
|
|
94
|
+
return `translate(-50%, -50%) rotateX(-135deg) translateZ(${hh}px)`;
|
|
95
|
+
default:
|
|
96
|
+
return `translate(-50%, -50%) translateZ(${hd}px)`;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function faceTransformFlat(name, w, _h, d) {
|
|
100
|
+
const total = 2 * d + 2 * w;
|
|
101
|
+
const halfTotal = total / 2;
|
|
102
|
+
let cx;
|
|
103
|
+
switch (name) {
|
|
104
|
+
case "left":
|
|
105
|
+
cx = d / 2;
|
|
106
|
+
break;
|
|
107
|
+
case "front":
|
|
108
|
+
cx = d + w / 2;
|
|
109
|
+
break;
|
|
110
|
+
case "right":
|
|
111
|
+
cx = d + w + d / 2;
|
|
112
|
+
break;
|
|
113
|
+
case "back":
|
|
114
|
+
cx = d + w + d + w / 2;
|
|
115
|
+
break;
|
|
116
|
+
case "top":
|
|
117
|
+
case "top_front":
|
|
118
|
+
case "top_rear":
|
|
119
|
+
cx = d + w / 2;
|
|
120
|
+
return `translate(-50%, -50%) translateX(${cx - halfTotal}px) translateY(-${_h}px)`;
|
|
121
|
+
case "bottom":
|
|
122
|
+
case "bottom_front":
|
|
123
|
+
case "bottom_rear":
|
|
124
|
+
cx = d + w / 2;
|
|
125
|
+
return `translate(-50%, -50%) translateX(${cx - halfTotal}px) translateY(${_h}px)`;
|
|
126
|
+
default:
|
|
127
|
+
cx = d + w / 2;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
const offsetX = cx - halfTotal;
|
|
131
|
+
return `translate(-50%, -50%) translateX(${offsetX}px)`;
|
|
132
|
+
}
|
|
133
|
+
function parseCssText(css) {
|
|
134
|
+
if (!css) return {};
|
|
135
|
+
const style = {};
|
|
136
|
+
css.split(";").forEach((rule) => {
|
|
137
|
+
const [prop, ...rest] = rule.split(":");
|
|
138
|
+
if (!prop || rest.length === 0) return;
|
|
139
|
+
const key = prop.trim().replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
140
|
+
style[key] = rest.join(":").trim();
|
|
141
|
+
});
|
|
142
|
+
return style;
|
|
143
|
+
}
|
|
144
|
+
function faceDimensions(name, w, h, d) {
|
|
145
|
+
switch (name) {
|
|
146
|
+
case "left":
|
|
147
|
+
case "right":
|
|
148
|
+
return { width: d, height: h };
|
|
149
|
+
case "top":
|
|
150
|
+
case "bottom":
|
|
151
|
+
case "top_front":
|
|
152
|
+
case "top_rear":
|
|
153
|
+
case "bottom_front":
|
|
154
|
+
case "bottom_rear":
|
|
155
|
+
return { width: w, height: d };
|
|
156
|
+
default:
|
|
157
|
+
return { width: w, height: h };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
var DEFAULT_FACE_NAMES = [
|
|
161
|
+
"front",
|
|
162
|
+
"back",
|
|
163
|
+
"left",
|
|
164
|
+
"right",
|
|
165
|
+
"top",
|
|
166
|
+
"bottom"
|
|
167
|
+
];
|
|
168
|
+
var Obj = React.memo(
|
|
169
|
+
({
|
|
170
|
+
width = 160,
|
|
171
|
+
height = 160,
|
|
172
|
+
depth = 150,
|
|
173
|
+
perspective = 600,
|
|
174
|
+
perspectiveOrigin = "50% 50%",
|
|
175
|
+
faces,
|
|
176
|
+
global: globalDef,
|
|
177
|
+
anim1,
|
|
178
|
+
anim2,
|
|
179
|
+
showCenterDiv = false,
|
|
180
|
+
flat = false,
|
|
181
|
+
transitionDuration = 1,
|
|
182
|
+
className,
|
|
183
|
+
style
|
|
184
|
+
}) => {
|
|
185
|
+
const w = typeof width === "number" ? width : parseFloat(width);
|
|
186
|
+
const h = typeof height === "number" ? height : parseFloat(height);
|
|
187
|
+
const d = typeof depth === "number" ? depth : parseFloat(depth);
|
|
188
|
+
const animation1 = toAnimationShorthand(anim1) ?? void 0;
|
|
189
|
+
const animation2 = toAnimationShorthand(anim2) ?? void 0;
|
|
190
|
+
const faceList = faces && faces.length > 0 ? faces : DEFAULT_FACE_NAMES.map((name) => ({ name }));
|
|
191
|
+
const transitionCss = `transform ${transitionDuration}s ease-in-out`;
|
|
192
|
+
const renderFace = (face, i) => {
|
|
193
|
+
const dims = faceDimensions(face.name, w, h, d);
|
|
194
|
+
const transform = flat ? faceTransformFlat(face.name, w, h, d) : faceTransform3D(face.name, w, h, d);
|
|
195
|
+
const globalStyle = parseCssText(globalDef?.css);
|
|
196
|
+
const faceInlineStyle = parseCssText(face.css);
|
|
197
|
+
const mergedStyle = {
|
|
198
|
+
...globalStyle,
|
|
199
|
+
...globalDef?.style ?? {},
|
|
200
|
+
...faceInlineStyle,
|
|
201
|
+
...face.style ?? {},
|
|
202
|
+
width: dims.width,
|
|
203
|
+
height: dims.height,
|
|
204
|
+
transform,
|
|
205
|
+
transition: transitionCss
|
|
206
|
+
};
|
|
207
|
+
const body = face.body ?? globalDef?.body ?? null;
|
|
208
|
+
const faceClassName = [
|
|
209
|
+
"anim3d-face",
|
|
210
|
+
face.className
|
|
211
|
+
].filter(Boolean).join(" ");
|
|
212
|
+
return /* @__PURE__ */ jsx(
|
|
213
|
+
"div",
|
|
214
|
+
{
|
|
215
|
+
className: faceClassName,
|
|
216
|
+
style: mergedStyle,
|
|
217
|
+
children: body
|
|
218
|
+
},
|
|
219
|
+
face.name + "-" + i
|
|
220
|
+
);
|
|
221
|
+
};
|
|
222
|
+
const cssVars = {
|
|
223
|
+
"--obj-w": w + "px",
|
|
224
|
+
"--obj-h": h + "px",
|
|
225
|
+
"--obj-d": d + "px"
|
|
226
|
+
};
|
|
227
|
+
return /* @__PURE__ */ jsx(
|
|
228
|
+
"div",
|
|
229
|
+
{
|
|
230
|
+
className: ["anim3d-stage", className].filter(Boolean).join(" "),
|
|
231
|
+
style: {
|
|
232
|
+
perspective: flat ? "none" : perspective,
|
|
233
|
+
perspectiveOrigin,
|
|
234
|
+
...cssVars,
|
|
235
|
+
...style
|
|
236
|
+
},
|
|
237
|
+
"data-anim-3d-obj": true,
|
|
238
|
+
role: "img",
|
|
239
|
+
"aria-label": "3D object",
|
|
240
|
+
children: /* @__PURE__ */ jsx(
|
|
241
|
+
"div",
|
|
242
|
+
{
|
|
243
|
+
className: "anim3d-wrapper",
|
|
244
|
+
style: {
|
|
245
|
+
...cssVars,
|
|
246
|
+
animation: flat ? "none" : animation1,
|
|
247
|
+
transformStyle: "preserve-3d",
|
|
248
|
+
transition: transitionCss
|
|
249
|
+
},
|
|
250
|
+
children: /* @__PURE__ */ jsxs(
|
|
251
|
+
"div",
|
|
252
|
+
{
|
|
253
|
+
className: "anim3d-wrapper",
|
|
254
|
+
style: {
|
|
255
|
+
...cssVars,
|
|
256
|
+
animation: flat ? "none" : animation2,
|
|
257
|
+
transformStyle: "preserve-3d",
|
|
258
|
+
transition: transitionCss
|
|
259
|
+
},
|
|
260
|
+
children: [
|
|
261
|
+
showCenterDiv && /* @__PURE__ */ jsx("div", { className: "anim3d-center" }),
|
|
262
|
+
faceList.map(renderFace)
|
|
263
|
+
]
|
|
264
|
+
}
|
|
265
|
+
)
|
|
266
|
+
}
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
);
|
|
272
|
+
Obj.displayName = "Obj";
|
|
30
273
|
|
|
31
|
-
export { Obj };
|
|
274
|
+
export { Obj, Obj as default, resolveAnimation, toAnimationShorthand };
|
|
32
275
|
//# sourceMappingURL=index.js.map
|
|
33
276
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Obj.tsx"],"names":[],"mappings":";;;AAmBO,IAAM,MAA0B,CAAC;AAAA,EACrC,KAAA,GAAQ,OAAA;AAAA,EACR,MAAA,GAAS,OAAA;AAAA,EACT,KAAA,GAAQ,OAAA;AAAA,EACR,WAAA,GAAc,GAAA;AAAA,EACd,iBAAA,GAAoB,SAAA;AAAA,EACpB,QAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA;AACH,CAAA,KAAM;AAEH,EAAA,uBACG,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACE,SAAA;AAAA,MACA,KAAA,EAAO;AAAA,QACJ,WAAA;AAAA,QACA,iBAAA;AAAA,QACA,GAAG;AAAA,OACN;AAAA,MACA,kBAAA,EAAgB,IAAA;AAAA,MAGf;AAAA;AAAA,GACJ;AAEN","file":"index.js","sourcesContent":["import * as React from \"react\";\nimport \"./../styles/obj.css\";\n\nexport type ObjProps = {\n width?: string | number;\n height?: string | number;\n depth?: string | number;\n perspective?: string | number;\n perspectiveOrigin?: string;\n rotation?: string; // e.g., \"x 1s linear infinite\"\n className?: string;\n style?: React.CSSProperties;\n global?: {\n css?: string;\n body?: string;\n };\n children?: React.ReactNode;\n};\n\nexport const Obj: React.FC<ObjProps> = ({\n width = \"160px\",\n height = \"160px\",\n depth = \"150px\",\n perspective = 500,\n perspectiveOrigin = \"50% 50%\",\n rotation,\n className,\n style,\n global,\n children,\n}) => {\n // … your existing DOM/CSS 3D layout & animations\n return (\n <div\n className={className}\n style={{\n perspective,\n perspectiveOrigin,\n ...style,\n }}\n data-anim-3d-obj\n >\n {/* faces, wrappers, animations… */}\n {children}\n </div>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/keyframes.ts","../src/components/Obj.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { AnimationConfig } from \"./types\";\n\n/** Create (or reuse) a <style> tag for dynamic keyframes */\nfunction ensureStyleTag(): HTMLStyleElement {\n let tag = document.getElementById(\n \"anim3d-keyframes\"\n ) as HTMLStyleElement | null;\n if (!tag) {\n tag = document.createElement(\"style\");\n tag.id = \"anim3d-keyframes\";\n document.head.appendChild(tag);\n }\n return tag;\n}\n\nfunction inject(css: string) {\n if (typeof document === \"undefined\") return; // SSR\n const tag = ensureStyleTag();\n tag.appendChild(document.createTextNode(css));\n}\n\n/** Keyframes text for built-ins */\nfunction builtInKeyframes(name: string, cfg: AnimationConfig) {\n const hi = cfg.degreesHi ?? 15;\n const lo = cfg.degreesLow ?? -15;\n switch (name) {\n case \"Y360\":\n return `@keyframes Y360 { from { transform: rotateY(0deg) } to { transform: rotateY(360deg) } }`;\n case \"X360\":\n return `@keyframes X360 { from { transform: rotateX(0deg) } to { transform: rotateX(360deg) } }`;\n case \"Z360\":\n return `@keyframes Z360 { from { transform: rotateZ(0deg) } to { transform: rotateZ(360deg) } }`;\n case \"rockY\":\n return `@keyframes rockY { 0%{ transform: rotateY(${lo}deg) } 50%{ transform: rotateY(${hi}deg) } 100%{ transform: rotateY(${lo}deg) } }`;\n case \"rockX\":\n return `@keyframes rockX { 0%{ transform: rotateX(${lo}deg) } 50%{ transform: rotateX(${hi}deg) } 100%{ transform: rotateX(${lo}deg) } }`;\n default:\n // Custom names: let authors supply their own @keyframes in global CSS with that name.\n return \"\";\n }\n}\n\n/** Returns a concrete animation-name and ensures keyframes exist (for built-ins) */\nexport function resolveAnimation(cfg?: AnimationConfig): string | null {\n if (!cfg) return null;\n const name = cfg.name;\n const builtIn = builtInKeyframes(name, cfg);\n if (builtIn) {\n // Ensure single injection per built-in name\n const marker = `/*kf-${name}*/`;\n if (typeof document !== \"undefined\") {\n const tag = ensureStyleTag();\n if (!tag.innerHTML.includes(marker)) {\n inject(`${builtIn}\\n${marker}`);\n }\n }\n return name; // use built-in name as animation-name\n }\n // custom: use author-provided @keyframes by name\n return name;\n}\n\n/** Build the full CSS animation shorthand from a config and resolved name */\nexport function toAnimationShorthand(cfg?: AnimationConfig): string | null {\n const name = resolveAnimation(cfg);\n if (!cfg || !name) return null;\n const dur = (cfg.duration ?? 10) + \"s\";\n const delay = (cfg.delay ?? 0) + \"s\";\n const iter = cfg.iterationCount ?? \"infinite\";\n const dir = cfg.direction ?? \"normal\";\n const timing = cfg.timing ?? \"linear\";\n const fill = cfg.fillMode ?? \"forwards\";\n const play = cfg.animationPlayState ?? \"running\";\n // name duration timing delay iteration-count direction fill-mode play-state\n return `${name} ${dur} ${timing} ${delay} ${iter} ${dir} ${fill} ${play}`;\n}\n","import * as React from \"react\";\nimport type {\n ObjProps,\n FaceDef,\n FaceName,\n GlobalDef,\n} from \"../types\";\nimport { toAnimationShorthand } from \"../keyframes\";\nimport \"../styles/obj.css\";\n\n// Re-export the canonical ObjProps from types.ts\nexport type { ObjProps } from \"../types\";\n\n/* ------------------------------------------------------------------ */\n/* Face transform — 3D cuboid positions */\n/* ------------------------------------------------------------------ */\n\nfunction faceTransform3D(\n name: string,\n w: number,\n h: number,\n d: number\n): string {\n const hw = w / 2;\n const hh = h / 2;\n const hd = d / 2;\n\n switch (name as FaceName) {\n case \"front\":\n return `translate(-50%, -50%) translateZ(${hd}px)`;\n case \"back\":\n return `translate(-50%, -50%) rotateY(180deg) translateZ(${hd}px)`;\n case \"left\":\n return `translate(-50%, -50%) rotateY(-90deg) translateZ(${hw}px)`;\n case \"right\":\n return `translate(-50%, -50%) rotateY(90deg) translateZ(${hw}px)`;\n case \"top\":\n return `translate(-50%, -50%) rotateX(90deg) translateZ(${hh}px)`;\n case \"bottom\":\n return `translate(-50%, -50%) rotateX(-90deg) translateZ(${hh}px)`;\n case \"top_front\":\n return `translate(-50%, -50%) rotateX(45deg) translateZ(${hh}px)`;\n case \"top_rear\":\n return `translate(-50%, -50%) rotateX(135deg) translateZ(${hh}px)`;\n case \"bottom_front\":\n return `translate(-50%, -50%) rotateX(-45deg) translateZ(${hh}px)`;\n case \"bottom_rear\":\n return `translate(-50%, -50%) rotateX(-135deg) translateZ(${hh}px)`;\n default:\n return `translate(-50%, -50%) translateZ(${hd}px)`;\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Face transform — flat (unfolded) positions */\n/* */\n/* Layout order: … | left | front | right | back | … */\n/* Centered on the midpoint of the full row. */\n/* ------------------------------------------------------------------ */\n\n/** Ordered face names for the flat row (left-to-right) */\nconst FLAT_ORDER: FaceName[] = [\"left\", \"front\", \"right\", \"back\"];\n\n/**\n * Returns the flat-layout transform for a face.\n *\n * Side faces (left, right) have a rendered width of `d` (depth).\n * Front/back faces have a rendered width of `w`.\n * Row order: left(d) | front(w) | right(d) | back(w)\n * Total row width = 2d + 2w. We centre the row on 0.\n */\nfunction faceTransformFlat(\n name: string,\n w: number,\n _h: number,\n d: number\n): string {\n // Total row width\n const total = 2 * d + 2 * w;\n const halfTotal = total / 2;\n\n // Cumulative left-edge x positions (relative to row start = 0)\n // left : 0 width d\n // front : d width w\n // right : d + w width d\n // back : d + w + d width w\n let cx: number; // centre-x of this face in the row\n\n switch (name as FaceName) {\n case \"left\":\n cx = d / 2;\n break;\n case \"front\":\n cx = d + w / 2;\n break;\n case \"right\":\n cx = d + w + d / 2;\n break;\n case \"back\":\n cx = d + w + d + w / 2;\n break;\n case \"top\":\n case \"top_front\":\n case \"top_rear\":\n // Top faces slide upward out of the way\n cx = d + w / 2;\n return `translate(-50%, -50%) translateX(${cx - halfTotal}px) translateY(-${_h}px)`;\n case \"bottom\":\n case \"bottom_front\":\n case \"bottom_rear\":\n cx = d + w / 2;\n return `translate(-50%, -50%) translateX(${cx - halfTotal}px) translateY(${_h}px)`;\n default:\n cx = d + w / 2;\n break;\n }\n\n // Shift so the row is centred on x=0\n const offsetX = cx - halfTotal;\n return `translate(-50%, -50%) translateX(${offsetX}px)`;\n}\n\n/* ------------------------------------------------------------------ */\n/* Parse a legacy CSS text string into a CSSProperties object */\n/* ------------------------------------------------------------------ */\n\nfunction parseCssText(css?: string): React.CSSProperties {\n if (!css) return {};\n const style: Record<string, string> = {};\n css.split(\";\").forEach((rule) => {\n const [prop, ...rest] = rule.split(\":\");\n if (!prop || rest.length === 0) return;\n const key = prop\n .trim()\n .replace(/-([a-z])/g, (_, c) => c.toUpperCase());\n style[key] = rest.join(\":\").trim();\n });\n return style as React.CSSProperties;\n}\n\n/* ------------------------------------------------------------------ */\n/* Resolve face dimensions for non-standard faces */\n/* ------------------------------------------------------------------ */\n\nfunction faceDimensions(\n name: string,\n w: number,\n h: number,\n d: number\n): { width: number; height: number } {\n switch (name as FaceName) {\n case \"left\":\n case \"right\":\n return { width: d, height: h };\n case \"top\":\n case \"bottom\":\n case \"top_front\":\n case \"top_rear\":\n case \"bottom_front\":\n case \"bottom_rear\":\n return { width: w, height: d };\n default:\n return { width: w, height: h };\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Default 6-sided cube when no faces are provided */\n/* ------------------------------------------------------------------ */\n\nconst DEFAULT_FACE_NAMES: FaceName[] = [\n \"front\",\n \"back\",\n \"left\",\n \"right\",\n \"top\",\n \"bottom\",\n];\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport const Obj: React.FC<ObjProps> = React.memo(\n ({\n width = 160,\n height = 160,\n depth = 150,\n perspective = 600,\n perspectiveOrigin = \"50% 50%\",\n faces,\n global: globalDef,\n anim1,\n anim2,\n showCenterDiv = false,\n flat = false,\n transitionDuration = 1,\n className,\n style,\n }) => {\n const w = typeof width === \"number\" ? width : parseFloat(width);\n const h = typeof height === \"number\" ? height : parseFloat(height);\n const d = typeof depth === \"number\" ? depth : parseFloat(depth);\n\n // Resolve animation shorthands\n const animation1 = toAnimationShorthand(anim1) ?? undefined;\n const animation2 = toAnimationShorthand(anim2) ?? undefined;\n\n // Determine which faces to render\n const faceList: FaceDef[] =\n faces && faces.length > 0\n ? faces\n : DEFAULT_FACE_NAMES.map((name) => ({ name }));\n\n const transitionCss = `transform ${transitionDuration}s ease-in-out`;\n\n // Merge global defaults into each face\n const renderFace = (face: FaceDef, i: number) => {\n const dims = faceDimensions(face.name, w, h, d);\n const transform = flat\n ? faceTransformFlat(face.name, w, h, d)\n : faceTransform3D(face.name, w, h, d);\n\n const globalStyle = parseCssText(globalDef?.css);\n const faceInlineStyle = parseCssText(face.css);\n\n const mergedStyle: React.CSSProperties = {\n ...globalStyle,\n ...(globalDef?.style ?? {}),\n ...faceInlineStyle,\n ...(face.style ?? {}),\n width: dims.width,\n height: dims.height,\n transform,\n transition: transitionCss,\n };\n\n const body = face.body ?? globalDef?.body ?? null;\n const faceClassName = [\n \"anim3d-face\",\n face.className,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n key={face.name + \"-\" + i}\n className={faceClassName}\n style={mergedStyle}\n >\n {body}\n </div>\n );\n };\n\n const cssVars = {\n \"--obj-w\": w + \"px\",\n \"--obj-h\": h + \"px\",\n \"--obj-d\": d + \"px\",\n } as React.CSSProperties;\n\n return (\n <div\n className={[\"anim3d-stage\", className].filter(Boolean).join(\" \")}\n style={{\n perspective: flat ? \"none\" : perspective,\n perspectiveOrigin,\n ...cssVars,\n ...style,\n }}\n data-anim-3d-obj\n role=\"img\"\n aria-label=\"3D object\"\n >\n {/* Outer animation wrapper (anim1) */}\n <div\n className=\"anim3d-wrapper\"\n style={{\n ...cssVars,\n animation: flat ? \"none\" : animation1,\n transformStyle: \"preserve-3d\",\n transition: transitionCss,\n }}\n >\n {/* Inner animation wrapper (anim2) */}\n <div\n className=\"anim3d-wrapper\"\n style={{\n ...cssVars,\n animation: flat ? \"none\" : animation2,\n transformStyle: \"preserve-3d\",\n transition: transitionCss,\n }}\n >\n {showCenterDiv && <div className=\"anim3d-center\" />}\n {faceList.map(renderFace)}\n </div>\n </div>\n </div>\n );\n }\n);\n\nObj.displayName = \"Obj\";\n"]}
|