anim-3d-obj 2.0.2 → 2.0.4

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 CHANGED
@@ -1,35 +1,264 @@
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
- var Obj = ({
7
- width = "160px",
8
- height = "160px",
9
- depth = "150px",
10
- perspective = 500,
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 faceTransform(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
+ // Legacy names – map to angled half-faces
112
+ case "top_front":
113
+ return `translate(-50%, -50%) rotateX(45deg) translateZ(${hh}px)`;
114
+ case "top_rear":
115
+ return `translate(-50%, -50%) rotateX(135deg) translateZ(${hh}px)`;
116
+ case "bottom_front":
117
+ return `translate(-50%, -50%) rotateX(-45deg) translateZ(${hh}px)`;
118
+ case "bottom_rear":
119
+ return `translate(-50%, -50%) rotateX(-135deg) translateZ(${hh}px)`;
120
+ default:
121
+ return `translate(-50%, -50%) translateZ(${hd}px)`;
122
+ }
123
+ }
124
+ function parseCssText(css) {
125
+ if (!css) return {};
126
+ const style = {};
127
+ css.split(";").forEach((rule) => {
128
+ const [prop, ...rest] = rule.split(":");
129
+ if (!prop || rest.length === 0) return;
130
+ const key = prop.trim().replace(/-([a-z])/g, (_, c) => c.toUpperCase());
131
+ style[key] = rest.join(":").trim();
132
+ });
133
+ return style;
134
+ }
135
+ function faceDimensions(name, w, h, d) {
136
+ switch (name) {
137
+ case "left":
138
+ case "right":
139
+ return { width: d, height: h };
140
+ case "top":
141
+ case "bottom":
142
+ case "top_front":
143
+ case "top_rear":
144
+ case "bottom_front":
145
+ case "bottom_rear":
146
+ return { width: w, height: d };
147
+ default:
148
+ return { width: w, height: h };
149
+ }
150
+ }
151
+ var DEFAULT_FACE_NAMES = [
152
+ "front",
153
+ "back",
154
+ "left",
155
+ "right",
156
+ "top",
157
+ "bottom"
158
+ ];
159
+ var Obj = React__namespace.memo(
160
+ ({
161
+ width = 160,
162
+ height = 160,
163
+ depth = 150,
164
+ perspective = 600,
165
+ perspectiveOrigin = "50% 50%",
166
+ faces,
167
+ global: globalDef,
168
+ anim1,
169
+ anim2,
170
+ showCenterDiv = false,
171
+ className,
172
+ style
173
+ }) => {
174
+ const w = typeof width === "number" ? width : parseFloat(width);
175
+ const h = typeof height === "number" ? height : parseFloat(height);
176
+ const d = typeof depth === "number" ? depth : parseFloat(depth);
177
+ const animation1 = toAnimationShorthand(anim1) ?? void 0;
178
+ const animation2 = toAnimationShorthand(anim2) ?? void 0;
179
+ const faceList = faces && faces.length > 0 ? faces : DEFAULT_FACE_NAMES.map((name) => ({ name }));
180
+ const renderFace = (face, i) => {
181
+ const dims = faceDimensions(face.name, w, h, d);
182
+ const transform = faceTransform(face.name, w, h, d);
183
+ const globalStyle = parseCssText(globalDef?.css);
184
+ const faceInlineStyle = parseCssText(face.css);
185
+ const mergedStyle = {
186
+ ...globalStyle,
187
+ ...globalDef?.style ?? {},
188
+ ...faceInlineStyle,
189
+ ...face.style ?? {},
190
+ width: dims.width,
191
+ height: dims.height,
192
+ transform
193
+ };
194
+ const body = face.body ?? globalDef?.body ?? null;
195
+ const faceClassName = [
196
+ "anim3d-face",
197
+ face.className
198
+ ].filter(Boolean).join(" ");
199
+ return /* @__PURE__ */ jsxRuntime.jsx(
200
+ "div",
201
+ {
202
+ className: faceClassName,
203
+ style: mergedStyle,
204
+ children: body
205
+ },
206
+ face.name + "-" + i
207
+ );
208
+ };
209
+ const cssVars = {
210
+ "--obj-w": w + "px",
211
+ "--obj-h": h + "px",
212
+ "--obj-d": d + "px"
213
+ };
214
+ return /* @__PURE__ */ jsxRuntime.jsx(
215
+ "div",
216
+ {
217
+ className: ["anim3d-stage", className].filter(Boolean).join(" "),
218
+ style: {
219
+ perspective,
220
+ perspectiveOrigin,
221
+ ...cssVars,
222
+ ...style
223
+ },
224
+ "data-anim-3d-obj": true,
225
+ role: "img",
226
+ "aria-label": "3D object",
227
+ children: /* @__PURE__ */ jsxRuntime.jsx(
228
+ "div",
229
+ {
230
+ className: "anim3d-wrapper",
231
+ style: {
232
+ ...cssVars,
233
+ animation: animation1,
234
+ transformStyle: "preserve-3d"
235
+ },
236
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
237
+ "div",
238
+ {
239
+ className: "anim3d-wrapper",
240
+ style: {
241
+ ...cssVars,
242
+ animation: animation2,
243
+ transformStyle: "preserve-3d"
244
+ },
245
+ children: [
246
+ showCenterDiv && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "anim3d-center" }),
247
+ faceList.map(renderFace)
248
+ ]
249
+ }
250
+ )
251
+ }
252
+ )
253
+ }
254
+ );
255
+ }
256
+ );
257
+ Obj.displayName = "Obj";
32
258
 
33
259
  exports.Obj = Obj;
260
+ exports.default = Obj;
261
+ exports.resolveAnimation = resolveAnimation;
262
+ exports.toAnimationShorthand = toAnimationShorthand;
34
263
  //# sourceMappingURL=index.cjs.map
35
264
  //# sourceMappingURL=index.cjs.map
@@ -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 map */\n/* ------------------------------------------------------------------ */\n\nfunction faceTransform(\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 // Legacy names – map to angled half-faces\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/* 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 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 // 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 = faceTransform(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 };\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,\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: animation1,\n transformStyle: \"preserve-3d\",\n }}\n >\n {/* Inner animation wrapper (anim2) */}\n <div\n className=\"anim3d-wrapper\"\n style={{\n ...cssVars,\n animation: animation2,\n transformStyle: \"preserve-3d\",\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;
@@ -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 perspective: 600px;\n perspective-origin: 50% 50%;\n}\n\n.anim3d-wrapper {\n position: relative;\n transform-style: preserve-3d;\n width: var(--obj-w);\n height: var(--obj-h);\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}\n\n.anim3d-face {\n position: absolute;\n left: 50%;\n top: 50%;\n width: var(--obj-w);\n height: var(--obj-h);\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}\n"],"mappings":";AAAA,CAAC;AACE,YAAU;AACV,SAAO;AACP,UAAQ;AACR,eAAa;AACb,sBAAoB,IAAI;AAC3B;AAEA,CAAC;AACE,YAAU;AACV,mBAAiB;AACjB,SAAO,IAAI;AACX,UAAQ,IAAI;AACf;AAEA,CAAC;AACE,YAAU;AACV,QAAM;AACN,OAAK;AACL,SAAO;AACP,UAAQ;AACR,cAAY;AACZ,aAAW,UAAU,IAAI,EAAE;AAC3B,WAAS;AACZ;AAEA,CAAC;AACE,YAAU;AACV,QAAM;AACN,OAAK;AACL,SAAO,IAAI;AACX,UAAQ,IAAI;AACZ,mBAAiB;AACjB,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,uBAAqB;AACrB,cAAY;AACf;","names":[]}
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,56 @@
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?: string | number;
5
- height?: string | number;
6
- depth?: string | number;
7
- perspective?: string | number;
35
+ width?: number;
36
+ height?: number;
37
+ depth?: number;
38
+ perspective?: number;
8
39
  perspectiveOrigin?: string;
9
- rotation?: string;
40
+ faces?: FaceDef[];
41
+ global?: GlobalDef;
42
+ anim1?: AnimationConfig;
43
+ anim2?: AnimationConfig;
44
+ showCenterDiv?: boolean;
10
45
  className?: string;
11
- style?: React.CSSProperties;
12
- global?: {
13
- css?: string;
14
- body?: string;
15
- };
16
- children?: React.ReactNode;
46
+ style?: CSSProperties;
17
47
  };
48
+
18
49
  declare const Obj: React.FC<ObjProps>;
19
50
 
20
- export { Obj, type ObjProps };
51
+ /** Returns a concrete animation-name and ensures keyframes exist (for built-ins) */
52
+ declare function resolveAnimation(cfg?: AnimationConfig): string | null;
53
+ /** Build the full CSS animation shorthand from a config and resolved name */
54
+ declare function toAnimationShorthand(cfg?: AnimationConfig): string | null;
55
+
56
+ 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,56 @@
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?: string | number;
5
- height?: string | number;
6
- depth?: string | number;
7
- perspective?: string | number;
35
+ width?: number;
36
+ height?: number;
37
+ depth?: number;
38
+ perspective?: number;
8
39
  perspectiveOrigin?: string;
9
- rotation?: string;
40
+ faces?: FaceDef[];
41
+ global?: GlobalDef;
42
+ anim1?: AnimationConfig;
43
+ anim2?: AnimationConfig;
44
+ showCenterDiv?: boolean;
10
45
  className?: string;
11
- style?: React.CSSProperties;
12
- global?: {
13
- css?: string;
14
- body?: string;
15
- };
16
- children?: React.ReactNode;
46
+ style?: CSSProperties;
17
47
  };
48
+
18
49
  declare const Obj: React.FC<ObjProps>;
19
50
 
20
- export { Obj, type ObjProps };
51
+ /** Returns a concrete animation-name and ensures keyframes exist (for built-ins) */
52
+ declare function resolveAnimation(cfg?: AnimationConfig): string | null;
53
+ /** Build the full CSS animation shorthand from a config and resolved name */
54
+ declare function toAnimationShorthand(cfg?: AnimationConfig): string | null;
55
+
56
+ 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,237 @@
1
- import { jsx } from 'react/jsx-runtime';
1
+ import * as React from 'react';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
3
 
3
4
  // src/components/Obj.tsx
4
- var Obj = ({
5
- width = "160px",
6
- height = "160px",
7
- depth = "150px",
8
- perspective = 500,
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 faceTransform(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
+ // Legacy names – map to angled half-faces
88
+ case "top_front":
89
+ return `translate(-50%, -50%) rotateX(45deg) translateZ(${hh}px)`;
90
+ case "top_rear":
91
+ return `translate(-50%, -50%) rotateX(135deg) translateZ(${hh}px)`;
92
+ case "bottom_front":
93
+ return `translate(-50%, -50%) rotateX(-45deg) translateZ(${hh}px)`;
94
+ case "bottom_rear":
95
+ return `translate(-50%, -50%) rotateX(-135deg) translateZ(${hh}px)`;
96
+ default:
97
+ return `translate(-50%, -50%) translateZ(${hd}px)`;
98
+ }
99
+ }
100
+ function parseCssText(css) {
101
+ if (!css) return {};
102
+ const style = {};
103
+ css.split(";").forEach((rule) => {
104
+ const [prop, ...rest] = rule.split(":");
105
+ if (!prop || rest.length === 0) return;
106
+ const key = prop.trim().replace(/-([a-z])/g, (_, c) => c.toUpperCase());
107
+ style[key] = rest.join(":").trim();
108
+ });
109
+ return style;
110
+ }
111
+ function faceDimensions(name, w, h, d) {
112
+ switch (name) {
113
+ case "left":
114
+ case "right":
115
+ return { width: d, height: h };
116
+ case "top":
117
+ case "bottom":
118
+ case "top_front":
119
+ case "top_rear":
120
+ case "bottom_front":
121
+ case "bottom_rear":
122
+ return { width: w, height: d };
123
+ default:
124
+ return { width: w, height: h };
125
+ }
126
+ }
127
+ var DEFAULT_FACE_NAMES = [
128
+ "front",
129
+ "back",
130
+ "left",
131
+ "right",
132
+ "top",
133
+ "bottom"
134
+ ];
135
+ var Obj = React.memo(
136
+ ({
137
+ width = 160,
138
+ height = 160,
139
+ depth = 150,
140
+ perspective = 600,
141
+ perspectiveOrigin = "50% 50%",
142
+ faces,
143
+ global: globalDef,
144
+ anim1,
145
+ anim2,
146
+ showCenterDiv = false,
147
+ className,
148
+ style
149
+ }) => {
150
+ const w = typeof width === "number" ? width : parseFloat(width);
151
+ const h = typeof height === "number" ? height : parseFloat(height);
152
+ const d = typeof depth === "number" ? depth : parseFloat(depth);
153
+ const animation1 = toAnimationShorthand(anim1) ?? void 0;
154
+ const animation2 = toAnimationShorthand(anim2) ?? void 0;
155
+ const faceList = faces && faces.length > 0 ? faces : DEFAULT_FACE_NAMES.map((name) => ({ name }));
156
+ const renderFace = (face, i) => {
157
+ const dims = faceDimensions(face.name, w, h, d);
158
+ const transform = faceTransform(face.name, w, h, d);
159
+ const globalStyle = parseCssText(globalDef?.css);
160
+ const faceInlineStyle = parseCssText(face.css);
161
+ const mergedStyle = {
162
+ ...globalStyle,
163
+ ...globalDef?.style ?? {},
164
+ ...faceInlineStyle,
165
+ ...face.style ?? {},
166
+ width: dims.width,
167
+ height: dims.height,
168
+ transform
169
+ };
170
+ const body = face.body ?? globalDef?.body ?? null;
171
+ const faceClassName = [
172
+ "anim3d-face",
173
+ face.className
174
+ ].filter(Boolean).join(" ");
175
+ return /* @__PURE__ */ jsx(
176
+ "div",
177
+ {
178
+ className: faceClassName,
179
+ style: mergedStyle,
180
+ children: body
181
+ },
182
+ face.name + "-" + i
183
+ );
184
+ };
185
+ const cssVars = {
186
+ "--obj-w": w + "px",
187
+ "--obj-h": h + "px",
188
+ "--obj-d": d + "px"
189
+ };
190
+ return /* @__PURE__ */ jsx(
191
+ "div",
192
+ {
193
+ className: ["anim3d-stage", className].filter(Boolean).join(" "),
194
+ style: {
195
+ perspective,
196
+ perspectiveOrigin,
197
+ ...cssVars,
198
+ ...style
199
+ },
200
+ "data-anim-3d-obj": true,
201
+ role: "img",
202
+ "aria-label": "3D object",
203
+ children: /* @__PURE__ */ jsx(
204
+ "div",
205
+ {
206
+ className: "anim3d-wrapper",
207
+ style: {
208
+ ...cssVars,
209
+ animation: animation1,
210
+ transformStyle: "preserve-3d"
211
+ },
212
+ children: /* @__PURE__ */ jsxs(
213
+ "div",
214
+ {
215
+ className: "anim3d-wrapper",
216
+ style: {
217
+ ...cssVars,
218
+ animation: animation2,
219
+ transformStyle: "preserve-3d"
220
+ },
221
+ children: [
222
+ showCenterDiv && /* @__PURE__ */ jsx("div", { className: "anim3d-center" }),
223
+ faceList.map(renderFace)
224
+ ]
225
+ }
226
+ )
227
+ }
228
+ )
229
+ }
230
+ );
231
+ }
232
+ );
233
+ Obj.displayName = "Obj";
30
234
 
31
- export { Obj };
235
+ export { Obj, Obj as default, resolveAnimation, toAnimationShorthand };
32
236
  //# sourceMappingURL=index.js.map
33
237
  //# 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 map */\n/* ------------------------------------------------------------------ */\n\nfunction faceTransform(\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 // Legacy names – map to angled half-faces\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/* 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 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 // 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 = faceTransform(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 };\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,\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: animation1,\n transformStyle: \"preserve-3d\",\n }}\n >\n {/* Inner animation wrapper (anim2) */}\n <div\n className=\"anim3d-wrapper\"\n style={{\n ...cssVars,\n animation: animation2,\n transformStyle: \"preserve-3d\",\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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anim-3d-obj",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "Configurable 3D object with animated rotations and face content",
5
5
  "license": "MIT",
6
6
  "author": "mdnelles",