@simhub2/justflipit 3.2.2 → 4.0.1

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +258 -91
  4. package/dist/agent.cjs +63 -0
  5. package/dist/agent.cjs.map +7 -0
  6. package/dist/agent.d.cts +4 -0
  7. package/dist/agent.d.mts +4 -0
  8. package/dist/agent.d.ts +4 -0
  9. package/dist/agent.mjs +43 -0
  10. package/dist/agent.mjs.map +7 -0
  11. package/dist/justFlipIt-combined.js +295 -0
  12. package/dist/justFlipIt-combined.min.js +23 -0
  13. package/dist/justFlipIt-modern.js +271 -476
  14. package/dist/justFlipIt-modern.min.js +23 -1
  15. package/dist/justFlipIt-vanilla.js +272 -343
  16. package/dist/justFlipIt-vanilla.min.js +23 -1
  17. package/dist/justFlipIt.cjs +293 -0
  18. package/dist/justFlipIt.cjs.map +7 -0
  19. package/dist/justFlipIt.d.cts +4 -0
  20. package/dist/justFlipIt.d.mts +38 -0
  21. package/dist/justFlipIt.d.ts +38 -0
  22. package/dist/justFlipIt.js +269 -391
  23. package/dist/justFlipIt.js.map +7 -0
  24. package/dist/justFlipIt.min.js +23 -1
  25. package/dist/justFlipIt.min.js.map +7 -0
  26. package/dist/justFlipIt.mjs +272 -0
  27. package/dist/justFlipIt.mjs.map +7 -0
  28. package/dist/react.cjs +55 -0
  29. package/dist/react.cjs.map +7 -0
  30. package/dist/react.d.cts +3 -0
  31. package/dist/react.d.mts +3 -0
  32. package/dist/react.d.ts +3 -0
  33. package/dist/react.mjs +25 -0
  34. package/dist/react.mjs.map +7 -0
  35. package/dist/svelte.cjs +45 -0
  36. package/dist/svelte.cjs.map +7 -0
  37. package/dist/svelte.d.cts +3 -0
  38. package/dist/svelte.d.mts +3 -0
  39. package/dist/svelte.d.ts +3 -0
  40. package/dist/svelte.mjs +15 -0
  41. package/dist/svelte.mjs.map +7 -0
  42. package/dist/types/justFlipIt.d.ts +36 -59
  43. package/dist/vue.cjs +49 -0
  44. package/dist/vue.cjs.map +7 -0
  45. package/dist/vue.d.cts +3 -0
  46. package/dist/vue.d.mts +3 -0
  47. package/dist/vue.d.ts +3 -0
  48. package/dist/vue.mjs +19 -0
  49. package/dist/vue.mjs.map +7 -0
  50. package/package.json +117 -50
  51. package/src/justFlipIt-combined.js +0 -417
  52. package/src/justFlipIt-combined.min.js +0 -1
  53. package/src/justFlipIt-modern.js +0 -500
  54. package/src/justFlipIt-modern.min.js +0 -1
  55. package/src/justFlipIt-vanilla.js +0 -366
  56. package/src/justFlipIt-vanilla.min.js +0 -1
  57. package/src/justFlipIt.d.ts +0 -61
@@ -1,417 +1,295 @@
1
- /*!
2
- * justFlipIt v3.1.0
3
- * https://github.com/SimHub/justFlipIt
4
- *
5
- * Copyright SimHub
6
- * Released under the MIT license
7
- *
8
- * Date: 2025
9
- */
10
-
11
- (function (root, factory) {
12
- if (typeof define === "function" && define.amd) {
13
- define(["jquery"], function (jQuery) {
14
- return factory(jQuery || root.jQuery || root.$);
15
- });
16
- } else if (typeof module === "object" && module.exports) {
17
- var jQuery = typeof window !== "undefined" ? window.jQuery : undefined;
18
- if (!jQuery) {
19
- try {
20
- jQuery = require("jquery");
21
- } catch (e) {
22
- jQuery = null;
23
- }
24
- }
25
- module.exports = factory(jQuery);
26
- } else {
27
- root.justFlipIt = factory(root.jQuery || root.$);
28
- }
29
- })(typeof self !== "undefined" ? self : this, function (jQuery) {
30
- "use strict";
31
-
32
- // PATCH: Verbesserte Style-Kopierfunktion
33
- function copyStyles(src, dest) {
34
- const computed = window.getComputedStyle(src);
35
- const properties = [
36
- "background",
37
- "backgroundColor",
38
- "backgroundImage",
39
- "backgroundPosition",
40
- "backgroundRepeat",
41
- "backgroundSize",
42
- "borderRadius",
43
- "borderTopLeftRadius",
44
- "borderTopRightRadius",
45
- "borderBottomLeftRadius",
46
- "borderBottomRightRadius",
47
- "border",
48
- "borderTop",
49
- "borderRight",
50
- "borderBottom",
51
- "borderLeft",
52
- "boxShadow",
53
- "color",
54
- "opacity",
55
- ];
56
- properties.forEach(function (prop) {
57
- if (
58
- computed[prop] &&
59
- computed[prop] !== "none" &&
60
- computed[prop] !== "initial" &&
61
- computed[prop] !== ""
62
- ) {
63
- dest.style[prop] = computed[prop];
64
- }
65
- });
66
- }
67
-
68
- // NEU: Funktion zur Anwendung der benutzerdefinierten Animationseinstellungen
69
- function applyAnimationSettings(element, duration, easing) {
70
- const transitionValue = `all ${duration / 1000}s ${easing}`;
71
- element.style.transition = transitionValue;
72
- element.style.WebkitTransition = transitionValue;
73
- element.style.MozTransition = transitionValue;
74
- element.style.msTransition = transitionValue;
75
- element.style.OTransition = transitionValue;
76
- }
77
-
78
- function addStyles() {
79
- if (document.querySelector('[data-justflipitstyle="justFlipIt_One"]')) {
80
- return;
1
+ var JustFlipItModule = (() => {
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
81
15
  }
82
- const styleX = document.createElement("style");
83
- styleX.setAttribute("data-justflipitstyle", "justFlipIt_One");
84
- styleX.textContent =
85
- "._justFlipIt_panel {perspective:1000px;-webkit-perspective:1000px;-moz-perspective:1000px;}" +
86
- "._justFlipIt_panel .front{height:inherit;width:inherit;position:absolute;top:0;z-index:900;-webkit-transform:rotateX(0) rotateX(0);-moz-transform:rotateX(0) rotateX(0);-webkit-transform-style:preserve-3d;-moz-transform-style:preserve-3d;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-webkit-transition:all .4s ease-in-out;-moz-transition:all .4s ease-in-out;-ms-transition:all .4s ease-in-out;-o-transition:all .4s ease-in-out;transition:all .4s ease-in-out}" +
87
- "._justFlipIt_panel .back{height:inherit;width:inherit;position:absolute;top:0;z-index:1000;-webkit-transform:rotateX(-180deg);-moz-transform:rotateX(-180deg);-webkit-transform-style:preserve-3d;-moz-transform-style:preserve-3d;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-webkit-transition:all .4s ease-in-out;-moz-transition:all .4s ease-in-out;-ms-transition:all .4s ease-in-out;-o-transition:all .4s ease-in-out;transition:all .4s ease-in-out}" +
88
- "._justFlipIt_panel._flip_ .front{z-index:900;-webkit-transform:rotateX(180deg);-moz-transform:rotateX(180deg)}" +
89
- "._justFlipIt_panel._flip_ .back{z-index:1000;-webkit-transform:rotateX(0) rotateX(0);-moz-transform:rotateX(0) rotateX(0)}";
90
- const styleY = document.createElement("style");
91
- styleY.setAttribute("data-justflipitstyle", "justFlipIt_Two");
92
- styleY.textContent =
93
- "._justFlipIt_panel .backY{height:inherit;width:inherit;position:absolute;top:0;z-index:1000;-webkit-transform:rotateY(-180deg);-moz-transform:rotateY(-180deg);-webkit-transform-style:preserve-3d;-moz-transform-style:preserve-3d;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-webkit-transition:all .4s ease-in-out;-moz-transition:all .4s ease-in-out;-ms-transition:all .4s ease-in-out;-o-transition:all .4s ease-in-out;transition:all .4s ease-in-out}" +
94
- "._justFlipIt_panel._flipY_ .front{z-index:900;-webkit-transform:rotateY(180deg);-moz-transform:rotateY(180deg)}" +
95
- "._justFlipIt_panel._flipY_ .backY{z-index:1000;-webkit-transform:rotateX(0) rotateY(0);-moz-transform:rotateX(0) rotateY(0)}";
96
- const styleTransparent = document.createElement("style");
97
- styleTransparent.setAttribute(
98
- "data-justflipitstyle",
99
- "justFlipIt_Transparent",
100
- );
101
- styleTransparent.textContent =
102
- "._justFlipIt_panel {background: transparent !important; box-shadow: none !important;}" +
103
- "._justFlipIt_panel > * {box-sizing: border-box;}";
104
- document.head.appendChild(styleX);
105
- document.head.appendChild(styleY);
106
- document.head.appendChild(styleTransparent);
107
- }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
108
19
 
109
- function getStyle(element, property) {
110
- return window.getComputedStyle(element, null).getPropertyValue(property);
111
- }
112
- function addClass(element, className) {
113
- if (element.classList) {
114
- element.classList.add(className);
115
- } else {
116
- element.className += " " + className;
117
- }
20
+ // src/core.js
21
+ var core_exports = {};
22
+ __export(core_exports, {
23
+ FlipController: () => FlipController,
24
+ default: () => justFlipIt
25
+ });
26
+ var instances = /* @__PURE__ */ new WeakMap();
27
+ var defaults = { Click: false, FlipX: false, Duration: 400, Easing: "cubic-bezier(.22,.61,.36,1)", Tilt: false, Effect: "flip", ReducedMotion: true, preserveClasses: true, preserveStyles: true, Style: [] };
28
+ var css = `
29
+ ._justFlipIt_panel{position:relative;display:grid;perspective:var(--jfi-perspective,1000px);isolation:isolate}
30
+ ._justFlipIt_panel>[data-jfi-face]{grid-area:1/1;min-width:0;backface-visibility:hidden;-webkit-backface-visibility:hidden;transition:transform var(--jfi-duration) var(--jfi-easing),opacity var(--jfi-duration) var(--jfi-easing);transform-origin:center}
31
+ ._justFlipIt_panel>[data-jfi-face=back],._justFlipIt_panel[data-jfi-flipped=true]>[data-jfi-face=front]{pointer-events:none}
32
+ ._justFlipIt_panel[data-jfi-flipped=true]>[data-jfi-face=back]{pointer-events:auto}
33
+ ._justFlipIt_panel[data-jfi-effect=flip]>[data-jfi-face=front]{transform:rotateY(0deg)}
34
+ ._justFlipIt_panel[data-jfi-effect=flip]>[data-jfi-face=back]{transform:rotateY(-180deg)}
35
+ ._justFlipIt_panel[data-jfi-effect=flip][data-jfi-flipped=true]>[data-jfi-face=front]{transform:rotateY(180deg)}
36
+ ._justFlipIt_panel[data-jfi-effect=flip][data-jfi-flipped=true]>[data-jfi-face=back]{transform:rotateY(0deg)}
37
+ ._justFlipIt_panel[data-jfi-effect=flip][data-jfi-axis=x]>[data-jfi-face=front]{transform:rotateX(0deg)}
38
+ ._justFlipIt_panel[data-jfi-effect=flip][data-jfi-axis=x]>[data-jfi-face=back]{transform:rotateX(-180deg)}
39
+ ._justFlipIt_panel[data-jfi-effect=flip][data-jfi-axis=x][data-jfi-flipped=true]>[data-jfi-face=front]{transform:rotateX(180deg)}
40
+ ._justFlipIt_panel[data-jfi-effect=flip][data-jfi-axis=x][data-jfi-flipped=true]>[data-jfi-face=back]{transform:rotateX(0deg)}
41
+ ._justFlipIt_panel[data-jfi-effect=fade]>[data-jfi-face=back],._justFlipIt_panel[data-jfi-effect=scale]>[data-jfi-face=back]{opacity:0}
42
+ ._justFlipIt_panel[data-jfi-effect=fade][data-jfi-flipped=true]>[data-jfi-face=front],._justFlipIt_panel[data-jfi-effect=scale][data-jfi-flipped=true]>[data-jfi-face=front]{opacity:0}
43
+ ._justFlipIt_panel[data-jfi-effect=fade][data-jfi-flipped=true]>[data-jfi-face=back],._justFlipIt_panel[data-jfi-effect=scale][data-jfi-flipped=true]>[data-jfi-face=back]{opacity:1}
44
+ ._justFlipIt_panel[data-jfi-effect=scale]>[data-jfi-face=back],._justFlipIt_panel[data-jfi-effect=scale][data-jfi-flipped=true]>[data-jfi-face=front]{transform:scale(.94)}
45
+ ._justFlipIt_panel[data-jfi-effect=scale][data-jfi-flipped=true]>[data-jfi-face=back]{transform:scale(1)}
46
+ ._justFlipIt_panel[data-jfi-reduced=true]>[data-jfi-face]{transition:none!important}
47
+ @media(prefers-reduced-motion:reduce){._justFlipIt_panel:not([data-jfi-motion=allow])>[data-jfi-face]{transition:none!important}}
48
+ `;
49
+ function styles(doc) {
50
+ if (doc.querySelector('style[data-justflipitstyle="v4"]')) return;
51
+ const style = doc.createElement("style");
52
+ style.dataset.justflipitstyle = "v4";
53
+ style.textContent = css;
54
+ doc.head.append(style);
118
55
  }
119
- function removeClass(element, className) {
120
- if (element.classList) {
121
- element.classList.remove(className);
122
- } else {
123
- element.className = element.className.replace(
124
- new RegExp(
125
- "(^|\\b)" + className.split(" ").join("|") + "(\\b|$)",
126
- "gi",
127
- ),
128
- " ",
129
- );
130
- }
131
- }
132
- function toggleClass(element, className) {
133
- if (element.classList) {
134
- element.classList.toggle(className);
135
- } else {
136
- var classes = element.className.split(" ");
137
- var existingIndex = classes.indexOf(className);
138
- if (existingIndex >= 0) {
139
- classes.splice(existingIndex, 1);
140
- } else {
141
- classes.push(className);
56
+ function validate(options) {
57
+ if (options.Duration !== void 0 && (!Number.isFinite(options.Duration) || options.Duration < 0)) throw new TypeError("Duration must be a non-negative finite number");
58
+ if (options.Effect !== void 0 && !["flip", "fade", "scale"].includes(options.Effect)) throw new TypeError("Unknown Effect");
59
+ if (options.Tilt && typeof options.Tilt === "object") {
60
+ for (const key of ["max", "perspective", "scale"]) {
61
+ if (options.Tilt[key] !== void 0 && (!Number.isFinite(options.Tilt[key]) || options.Tilt[key] < 0)) throw new TypeError(`Invalid Tilt.${key}`);
142
62
  }
143
- element.className = classes.join(" ");
144
63
  }
145
64
  }
146
- function hasClass(element, className) {
147
- if (element.classList) {
148
- return element.classList.contains(className);
149
- } else {
150
- return new RegExp("(^| )" + className + "( |$)", "gi").test(
151
- element.className,
152
- );
153
- }
154
- }
155
-
156
- const instanceMap = new WeakMap();
157
-
158
- class JustFlipIt {
65
+ var FlipController = class {
159
66
  constructor(element, options = {}) {
160
- addStyles();
67
+ validate(options);
68
+ if (!element || element.nodeType !== 1) throw new TypeError("Expected an HTML element");
161
69
  this.element = element;
162
- this.settings = Object.assign(
163
- {},
164
- {
165
- Template: "",
166
- Click: false,
167
- FlipX: false,
168
- Style: [],
169
- // NEU: Standard-Animationsoptionen
170
- Duration: 400,
171
- Easing: "ease-in-out",
172
- preserveClasses: true, // NEU
173
- preserveStyles: true, // NEU
174
- },
175
- options,
176
- );
177
- this.elementWidth = getStyle(element, "width");
178
- this.elementHeight = getStyle(element, "height");
179
- this.elementBackgroundColor = getStyle(element, "background-color");
180
- this.originalClassName = element.className;
181
- this.originalTagName = element.tagName.toLowerCase();
182
- this.originalId = element.id || "";
183
- if (this.settings.FlipX === true) {
184
- this.flipClass = "_flip_";
185
- this.backClass = "back";
186
- } else {
187
- this.flipClass = "_flipY_";
188
- this.backClass = "backY";
189
- }
190
- this._init();
191
- if (this.settings.Tilt) {
192
- this._setupTilt();
193
- }
194
- instanceMap.set(element, this);
195
- }
196
-
197
- _init() {
198
- const originalElement = this.element;
199
- const originalClassName = this.originalClassName;
200
-
201
- // Panel-Struktur erzeugen
202
- const hoverPanel = document.createElement(this.originalTagName);
203
- addClass(hoverPanel, "hover");
204
- addClass(hoverPanel, "_justFlipIt_panel");
205
- const frontWrapper = document.createElement("div");
206
- addClass(frontWrapper, "front");
207
- const backWrapper = document.createElement("div");
208
- addClass(backWrapper, this.backClass);
209
-
210
- // NEU: Klassen übernehmen (Panel, .front, .backY)
211
- if (this.settings.preserveClasses && originalElement.classList.length) {
212
- originalElement.classList.forEach((cls) => {
213
- if (!hoverPanel.classList.contains(cls)) {
214
- hoverPanel.classList.add(cls);
215
- }
216
- if (frontWrapper && !frontWrapper.classList.contains(cls)) {
217
- frontWrapper.classList.add(cls);
218
- }
219
- if (backWrapper && !backWrapper.classList.contains(cls)) {
220
- backWrapper.classList.add(cls);
221
- }
222
- });
223
- }
224
-
225
- // NEU: Inline-Styles übernehmen (nur auf Panel)
226
- if (
227
- this.settings.preserveStyles && originalElement.getAttribute("style")
228
- ) {
229
- hoverPanel.setAttribute(
230
- "style",
231
- (hoverPanel.getAttribute("style") || "") +
232
- ";" + originalElement.getAttribute("style"),
233
- );
234
- }
235
-
236
- // Nur den INHALT übernehmen!
237
- frontWrapper.innerHTML = originalElement.innerHTML;
238
-
239
- if (this.settings.Template) {
240
- backWrapper.innerHTML = this.settings.Template;
70
+ this.settings = { ...defaults, ...options };
71
+ this.flipped = false;
72
+ this.destroyed = false;
73
+ this.cleanups = [];
74
+ this.restores = [];
75
+ this.win = element.ownerDocument.defaultView;
76
+ const doc = element.ownerDocument;
77
+ styles(doc);
78
+ this.managed = !!options.Faces;
79
+ if (this.managed) {
80
+ this.hoverPanel = element;
81
+ this.frontWrapper = element.querySelector(options.Faces.front);
82
+ this.backWrapper = element.querySelector(options.Faces.back);
83
+ if (!this.frontWrapper || !this.backWrapper || this.frontWrapper === this.backWrapper || this.frontWrapper.parentNode !== element || this.backWrapper.parentNode !== element) throw new TypeError("Faces must select two distinct direct children");
241
84
  } else {
242
- backWrapper.innerHTML = originalElement.innerHTML;
85
+ if (!element.parentNode) throw new TypeError("Element must have a parent");
86
+ this.hoverPanel = doc.createElement("div");
87
+ this.frontWrapper = doc.createElement("div");
88
+ this.backWrapper = doc.createElement("div");
89
+ if (this.settings.preserveClasses) this.hoverPanel.className = element.className;
90
+ if (this.settings.preserveStyles) this.hoverPanel.style.cssText = element.style.cssText;
91
+ element.before(this.hoverPanel);
92
+ this.hoverPanel.append(this.frontWrapper, this.backWrapper);
93
+ this.frontWrapper.append(element);
94
+ if (options.Template !== void 0) this.backWrapper.innerHTML = options.Template;
95
+ else {
96
+ const clone = element.cloneNode(true);
97
+ clone.removeAttribute("id");
98
+ clone.querySelectorAll("[id]").forEach((node) => node.removeAttribute("id"));
99
+ this.backWrapper.append(clone);
100
+ }
243
101
  }
244
-
245
- // Panel einfügen und Original entfernen
246
- originalElement.parentNode.insertBefore(hoverPanel, originalElement);
247
- hoverPanel.appendChild(frontWrapper);
248
- hoverPanel.appendChild(backWrapper);
249
- originalElement.parentNode.removeChild(originalElement);
250
-
251
- // Panel-Größe und Styles übernehmen
252
- hoverPanel.style.width = this.elementWidth;
253
- hoverPanel.style.height = this.elementHeight;
254
-
255
- // Custom Styles aus Option anwenden
256
- if (this.settings.Style && this.settings.Style.length) {
257
- this.settings.Style.forEach((styleObj) => {
258
- if (styleObj.el) {
259
- if (styleObj.el.toLowerCase() === "self") {
260
- Object.assign(hoverPanel.style, styleObj.style);
261
- } else {
262
- const targetElements = hoverPanel.querySelectorAll(styleObj.el);
263
- targetElements.forEach((el) => {
264
- Object.assign(el.style, styleObj.style);
265
- });
266
- }
102
+ const panel = this.hoverPanel;
103
+ for (const node of [panel, this.frontWrapper, this.backWrapper]) {
104
+ const owned = node === panel ? ["class", "style", "tabindex", "data-jfi-axis", "data-jfi-effect", "data-jfi-motion", "data-jfi-flipped", "data-jfi-reduced"] : ["style", "data-jfi-face", "aria-hidden", "inert"];
105
+ const attrs = owned.map((name) => [name, node.getAttribute(name)]);
106
+ const inert = node.inert || false;
107
+ this.restores.push(() => {
108
+ node.inert = inert;
109
+ for (const [name, value] of attrs) {
110
+ if (value === null) node.removeAttribute(name);
111
+ else node.setAttribute(name, value);
267
112
  }
268
113
  });
269
114
  }
270
-
271
- // Events setzen
272
- this._setupEvents(hoverPanel);
273
-
274
- // Referenzen speichern
275
- this.hoverPanel = hoverPanel;
276
- this.frontWrapper = frontWrapper;
277
- this.backWrapper = backWrapper;
278
- }
279
-
280
- _setupTilt() {
281
- const handleMove = (e) => {
282
- const rect = this.hoverPanel.getBoundingClientRect();
283
- const x = (e.touches ? e.touches[0].clientX : e.clientX) - rect.left;
284
- const y = (e.touches ? e.touches[0].clientY : e.clientY) - rect.top;
285
- const centerX = rect.width / 2;
286
- const centerY = rect.height / 2;
287
- const rotateX = ((y - centerY) / centerY) * 10;
288
- const rotateY = (-(x - centerX) / centerX) * 10;
289
- this.hoverPanel.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale3d(1.05, 1.05, 1.05)`;
115
+ panel.classList.add("_justFlipIt_panel");
116
+ this.frontWrapper.dataset.jfiFace = "front";
117
+ this.backWrapper.dataset.jfiFace = "back";
118
+ this.motion = this.win.matchMedia?.("(prefers-reduced-motion: reduce)");
119
+ const motionChange = () => {
120
+ this.resetTilt();
121
+ this.render();
290
122
  };
291
-
292
- const handleEnter = () => {
293
- this.hoverPanel.style.transition = "all 0.2s ease-out";
294
- };
295
-
296
- const handleLeave = () => {
297
- this.hoverPanel.style.transform = `perspective(1000px) rotateX(0) rotateY(0) scale3d(1, 1, 1)`;
298
- this.hoverPanel.style.transition = "all 0.5s ease-in-out";
299
- };
300
-
301
- this.hoverPanel.addEventListener("mousemove", handleMove);
302
- this.hoverPanel.addEventListener("touchmove", handleMove);
303
- this.hoverPanel.addEventListener("mouseenter", handleEnter);
304
- this.hoverPanel.addEventListener("touchstart", handleEnter);
305
- this.hoverPanel.addEventListener("mouseleave", handleLeave);
306
- this.hoverPanel.addEventListener("touchend", handleLeave);
123
+ this.motion?.addEventListener("change", motionChange);
124
+ this.cleanups.push(() => this.motion?.removeEventListener("change", motionChange));
125
+ this.configure();
126
+ this.events();
127
+ this.render();
128
+ instances.set(element, this);
129
+ instances.set(panel, this);
307
130
  }
308
-
309
- _setupEvents(hoverPanel) {
310
- if (this.settings.Tilt === 'only') return;
311
- if (this.settings.Click === true) {
312
- hoverPanel.addEventListener("click", (e) => {
313
- e.preventDefault();
314
- toggleClass(hoverPanel, this.flipClass);
315
- });
316
- } else if (typeof this.settings.Click === "string") {
317
- const clickElements = hoverPanel.querySelectorAll(this.settings.Click);
318
- clickElements.forEach((el) => {
319
- el.addEventListener("click", () => {
320
- toggleClass(hoverPanel, this.flipClass);
321
- });
322
- });
323
- } else {
324
- hoverPanel.addEventListener("mouseenter", () => {
325
- addClass(hoverPanel, this.flipClass);
326
- });
327
- hoverPanel.addEventListener("mouseleave", () => {
328
- removeClass(hoverPanel, this.flipClass);
329
- });
330
- }
131
+ listen(type, handler, options) {
132
+ this.hoverPanel.addEventListener(type, handler, options);
133
+ this.cleanups.push(() => this.hoverPanel.removeEventListener(type, handler, options));
331
134
  }
332
-
333
- destroy() {
334
- const hoverPanel = this.hoverPanel;
335
- const originalElement = hoverPanel.querySelector(".front > *");
336
- originalElement.className = this.originalClassName;
337
- hoverPanel.parentNode.insertBefore(originalElement, hoverPanel);
338
- hoverPanel.parentNode.removeChild(hoverPanel);
339
- instanceMap.delete(this.element);
135
+ get reduced() {
136
+ return this.settings.ReducedMotion !== false && !!this.motion?.matches;
340
137
  }
341
- }
342
-
343
- // Vanilla/JS API
344
- function justFlipIt(selector, options = {}) {
345
- if (typeof selector === "string") {
346
- const elements = document.querySelectorAll(selector);
347
- return Array.from(elements).map((el) => new JustFlipIt(el, options));
348
- } else if (selector instanceof Element) {
349
- return new JustFlipIt(selector, options);
350
- } else if (selector.length) {
351
- return Array.from(selector).map((el) => new JustFlipIt(el, options));
138
+ configure() {
139
+ const s = this.settings, p = this.hoverPanel;
140
+ p.style.setProperty("--jfi-duration", `${s.Duration}ms`);
141
+ p.style.setProperty("--jfi-easing", s.Easing);
142
+ p.dataset.jfiAxis = s.FlipX ? "x" : "y";
143
+ p.dataset.jfiEffect = s.Effect;
144
+ p.dataset.jfiMotion = s.ReducedMotion === false ? "allow" : "respect";
145
+ for (const item of s.Style || []) {
146
+ const targets = item.el === "self" ? [p] : p.querySelectorAll(item.el);
147
+ targets.forEach((node) => Object.assign(node.style, item.style));
148
+ }
149
+ if (s.Tilt !== "only" && !p.hasAttribute("tabindex")) p.tabIndex = 0;
352
150
  }
353
- }
354
-
355
- justFlipIt.destroy = function (selector) {
356
- if (typeof selector === "string") {
357
- const elements = document.querySelectorAll(selector);
358
- Array.from(elements).forEach((el) => {
359
- const instance = instanceMap.get(el);
360
- if (instance) instance.destroy();
361
- });
362
- } else if (selector instanceof Element) {
363
- const instance = instanceMap.get(selector);
364
- if (instance) instance.destroy();
365
- } else if (selector.length) {
366
- Array.from(selector).forEach((el) => {
367
- const instance = instanceMap.get(el);
368
- if (instance) instance.destroy();
151
+ events() {
152
+ this.listen("click", (event) => {
153
+ if (this.settings.Tilt === "only") return;
154
+ const trigger = this.settings.Click;
155
+ if (trigger === true || trigger && [].concat(trigger).some((selector) => event.target.closest?.(selector) && this.hoverPanel.contains(event.target.closest(selector)))) this.toggle();
369
156
  });
370
- }
371
- };
372
-
373
- // jQuery-Plugin API
374
- if (jQuery) {
375
- jQuery.fn.justFlipIt = function (options) {
376
- return this.each(function () {
377
- if (!jQuery.data(this, "plugin_justFlipIt")) {
378
- jQuery.data(this, "plugin_justFlipIt", new JustFlipIt(this, options));
157
+ this.listen("keydown", (event) => {
158
+ if (event.target !== this.hoverPanel || this.settings.Tilt === "only") return;
159
+ if (event.key === "Enter" || event.key === " ") {
160
+ event.preventDefault();
161
+ this.toggle();
379
162
  }
163
+ if (event.key === "Escape") this.flip(false);
380
164
  });
381
- };
382
-
383
- jQuery.fn.destroy = function () {
384
- return this.each(function () {
385
- const instance = instanceMap.get(this);
386
- if (instance) {
387
- instance.destroy();
388
- jQuery.removeData(this, "plugin_justFlipIt");
165
+ this.listen("pointerenter", (event) => {
166
+ if (!this.settings.Click && this.settings.Tilt !== "only" && event.pointerType !== "touch") this.flip(true);
167
+ });
168
+ this.listen("pointerleave", (event) => {
169
+ if (event.pointerType === "touch") return;
170
+ this.resetTilt();
171
+ if (!this.settings.Click && this.settings.Tilt !== "only") this.flip(false);
172
+ });
173
+ this.listen("pointerdown", (event) => {
174
+ if (event.pointerType !== "touch" || event.isPrimary === false || this.touch) return;
175
+ this.resetTilt();
176
+ this.touch = { id: event.pointerId, x: event.clientX, y: event.clientY, moved: false };
177
+ this.queueTilt(event, this.touch);
178
+ }, { passive: true });
179
+ this.listen("pointermove", (event) => {
180
+ if (event.pointerType !== "touch") {
181
+ if (!this.touch) this.queueTilt(event);
182
+ return;
389
183
  }
184
+ const touch = this.touch;
185
+ if (!touch || touch.id !== event.pointerId) return;
186
+ touch.moved || (touch.moved = this.touchMoved(event, touch));
187
+ this.queueTilt(event, touch);
188
+ }, { passive: true });
189
+ this.listen("pointerup", (event) => {
190
+ const touch = this.finishTouch(event);
191
+ if (!touch || touch.moved || this.touchMoved(event, touch)) return;
192
+ if (!this.settings.Click && this.settings.Tilt !== "only") this.toggle();
390
193
  });
391
- };
392
-
393
- // jQuery-API als Haupt-Export
394
- var api = function (selector, options) {
395
- if (typeof selector === "string") {
396
- return jQuery(selector).justFlipIt(options);
397
- } else if (selector instanceof Element) {
398
- return jQuery(selector).justFlipIt(options);
399
- } else if (selector instanceof jQuery) {
400
- return selector.justFlipIt(options);
194
+ this.listen("pointercancel", (event) => {
195
+ if (event.pointerType === "touch") this.finishTouch(event);
196
+ else this.resetTilt();
197
+ });
198
+ this.listen("lostpointercapture", (event) => this.finishTouch(event));
199
+ this.baseTransform = this.hoverPanel.style.transform;
200
+ }
201
+ touchMoved(event, touch) {
202
+ return Math.hypot(event.clientX - touch.x, event.clientY - touch.y) > 10;
203
+ }
204
+ finishTouch(event) {
205
+ const touch = this.touch;
206
+ if (event.pointerType !== "touch" || !touch || touch.id !== event.pointerId) return;
207
+ this.touch = null;
208
+ this.resetTilt();
209
+ return touch;
210
+ }
211
+ queueTilt(event, touch) {
212
+ if (!this.settings.Tilt || this.reduced) return;
213
+ this.point = [event.clientX, event.clientY];
214
+ if (this.frame) return;
215
+ this.frame = this.win.requestAnimationFrame(() => {
216
+ this.frame = 0;
217
+ const rect = touch ? touch.rect ?? (touch.rect = this.hoverPanel.getBoundingClientRect()) : this.hoverPanel.getBoundingClientRect();
218
+ if (!rect.width || !rect.height) return;
219
+ const { max = 10, perspective = 1e3, scale = 1.03 } = this.settings.Tilt;
220
+ const x = Math.max(-1, Math.min(1, (this.point[0] - rect.left) / rect.width * 2 - 1));
221
+ const y = Math.max(-1, Math.min(1, (this.point[1] - rect.top) / rect.height * 2 - 1));
222
+ this.hoverPanel.style.transform = `perspective(${perspective}px) rotateX(${-y * max}deg) rotateY(${x * max}deg) scale(${scale})`;
223
+ });
224
+ }
225
+ resetTilt() {
226
+ if (this.frame) this.win.cancelAnimationFrame(this.frame);
227
+ this.frame = 0;
228
+ this.hoverPanel.style.transform = this.baseTransform || "";
229
+ }
230
+ render() {
231
+ this.hoverPanel.dataset.jfiFlipped = String(this.flipped);
232
+ this.hoverPanel.dataset.jfiReduced = String(this.reduced);
233
+ for (const [node, hidden] of [[this.frontWrapper, this.flipped], [this.backWrapper, !this.flipped]]) {
234
+ node.setAttribute("aria-hidden", String(hidden));
235
+ node.inert = hidden;
401
236
  }
402
- };
403
- api.destroy = function (selector) {
404
- if (typeof selector === "string") {
405
- jQuery(selector).destroy();
406
- } else if (selector instanceof Element) {
407
- jQuery(selector).destroy();
408
- } else if (selector instanceof jQuery) {
409
- selector.destroy();
237
+ }
238
+ flip(value = true) {
239
+ if (this.destroyed || this.flipped === !!value) return this;
240
+ const active = this.element.ownerDocument.activeElement;
241
+ if ((value ? this.frontWrapper : this.backWrapper).contains(active)) this.hoverPanel.focus({ preventScroll: true });
242
+ this.flipped = !!value;
243
+ this.render();
244
+ this.hoverPanel.dispatchEvent(new this.win.CustomEvent("justflipit:change", { bubbles: true, detail: this.getState() }));
245
+ return this;
246
+ }
247
+ toggle() {
248
+ return this.flip(!this.flipped);
249
+ }
250
+ update(options = {}) {
251
+ if (this.destroyed) return this;
252
+ if ("Faces" in options) throw new TypeError("Faces cannot change after initialization");
253
+ validate(options);
254
+ if (this.managed && "Template" in options) throw new TypeError("Render framework face content with the framework");
255
+ this.settings = { ...this.settings, ...options };
256
+ if ("Template" in options) {
257
+ if (this.managed) throw new TypeError("Render framework face content with the framework");
258
+ this.backWrapper.innerHTML = options.Template;
410
259
  }
411
- };
412
- return api;
260
+ this.resetTilt();
261
+ this.configure();
262
+ this.render();
263
+ return this;
264
+ }
265
+ getState() {
266
+ return { flipped: this.flipped, destroyed: this.destroyed, effect: this.settings.Effect };
267
+ }
268
+ destroy() {
269
+ if (this.destroyed) return;
270
+ this.resetTilt();
271
+ this.cleanups.forEach((fn) => fn());
272
+ this.restores.forEach((fn) => fn());
273
+ if (!this.managed) {
274
+ this.hoverPanel.replaceWith(this.element);
275
+ }
276
+ instances.delete(this.element);
277
+ instances.delete(this.hoverPanel);
278
+ this.destroyed = true;
279
+ }
280
+ };
281
+ function elements(target) {
282
+ if (typeof target === "string") return typeof document === "undefined" ? [] : Array.from(document.querySelectorAll(target));
283
+ if (target?.nodeType === 1) return [target];
284
+ return target ? Array.from(target) : [];
413
285
  }
414
-
415
- // Vanilla-API als Fallback
416
- return justFlipIt;
417
- });
286
+ function justFlipIt(target, options) {
287
+ const result = elements(target).map((element) => instances.get(element) || new FlipController(element, options));
288
+ return target?.nodeType === 1 ? result[0] : result;
289
+ }
290
+ justFlipIt.destroy = (target) => elements(target).forEach((element) => instances.get(element)?.destroy());
291
+ justFlipIt.get = (element) => instances.get(element);
292
+ return __toCommonJS(core_exports);
293
+ })();
294
+ globalThis.justFlipIt = JustFlipItModule.default;
295
+ //# sourceMappingURL=justFlipIt.js.map