@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
package/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ # Changelog
2
+
3
+ ## 4.0.1
4
+
5
+ - Enable 3D tilt on touch and reset it when the finger lifts or scrolling takes over.
6
+ - Keep tap-to-flip active across flip, fade and scale without immediately flipping back on touch release.
7
+ - Restrict axis rotation to the flip effect so fade also works with `FlipX: true`.
8
+
9
+ ## 4.0.0
10
+
11
+ - One SSR-safe, dependency-free core with real ESM/CommonJS/browser exports.
12
+ - Preserve original DOM nodes and event handlers; idempotent initialization and teardown.
13
+ - Responsive grid faces, reversible transform transitions, fade and scale effects.
14
+ - Frame-batched pointer tilt, touch tap, keyboard controls, inert hidden faces and live reduced motion.
15
+ - Typed flip/toggle/update/state methods and change events.
16
+ - React hook, Vue 3 directive and Svelte action using existing framework-owned faces.
17
+ - Model-independent agent tool schema and allowlisted command executor with plain-text content.
18
+ - Reproducible build, automated lifecycle tests, type checks, CI and npm release workflow.
19
+
20
+ Breaking: jQuery registration removed; generated face classes replaced by data attributes;
21
+ framework integrations use existing direct-child faces; npm exports now distinguish ESM and CJS.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) SimHub
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,145 +1,312 @@
1
- [![GitHub stars](https://img.shields.io/github/stars/SimHub/justFlipIt.svg?style=social)](https://github.com/SimHub/justFlipIt)
2
- [![npm version](https://img.shields.io/npm/v/@simhub2/justflipit.svg)](https://www.npmjs.com/package/@simhub2/justflipit)
3
- [![npm downloads](https://img.shields.io/npm/dt/@simhub2/justflipit.svg)](https://www.npmjs.com/package/@simhub2/justflipit)
4
-
5
- # justFlipIt
6
-
7
- A lightweight JavaScript library for beautiful, customizable flip and tilt animations on any DOM element.
1
+ <p align="center">
2
+ <img src="img/readme-banner.svg" alt="justFlipIt v4 — A little motion. A new perspective." width="100%">
3
+ </p>
4
+
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@simhub2/justflipit"><img src="https://img.shields.io/npm/v/%40simhub2%2Fjustflipit?style=flat-square&amp;color=b4df83" alt="npm version"></a>
7
+ <a href="https://github.com/SimHub/justFlipIt/actions/workflows/ci.yml"><img src="https://github.com/SimHub/justFlipIt/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI status"></a>
8
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-d9ccff?style=flat-square" alt="MIT license"></a>
9
+ <a href="#frameworks"><img src="https://img.shields.io/badge/TypeScript-included-93c5fd?style=flat-square" alt="TypeScript declarations included"></a>
10
+ </p>
11
+
12
+ <p align="center">
13
+ Responsive flip and tilt animations for your UI.<br>
14
+ One dependency-free core. Native framework lifecycles. Model-independent agent tools.
15
+ </p>
16
+
17
+ <p align="center">
18
+ <a href="#quick-start">Quick start</a> ·
19
+ <a href="#frameworks">React / Vue / Svelte</a> ·
20
+ <a href="#agent-tools">Agent tools</a> ·
21
+ <a href="#options">Options</a> ·
22
+ <a href="#upgrading-from-v3">Upgrade from v3</a>
23
+ </p>
8
24
 
9
25
  ---
10
26
 
11
- ### 🚀 [Live Demo & Examples](https://SimHub.github.io/justFlipIt/)
27
+ ## A card with more to say
12
28
 
13
- > **Try it out!**
14
- > The interactive [Live Demo](https://SimHub.github.io/justFlipIt/) shows all features and use cases.
29
+ Build product cards, reveal details, or let an agent control a card through explicit tool calls. Choose a 3D flip, a soft fade, or a scale transition, then add pointer-driven tilt.
15
30
 
16
- ---
31
+ ![justFlipIt demo showing flip cards, effect controls and an agent tool](img/demo.png)
17
32
 
18
- ### ✨ Features
33
+ **[Browse the demo source →](example/index.html)** · Run locally with `npm run build` and `python3 -m http.server 4173`, then open [localhost:4173/example/](http://localhost:4173/example/).
19
34
 
20
- - **Plug & Play**: Automatically adopts classes and styles for seamless integration.
21
- - **3D Tilt Effect**: Adds an interactive 3D tilt effect on hover and touch.
22
- - **Lightweight & Fast**: Minimal footprint, maximum performance.
23
- - **Highly Customizable**: Use your own styles, templates, and animations.
24
- - **Modern & Responsive**: Works on all modern browsers and devices.
25
- - **Flexible**: Use via CDN, NPM, or ES modules.
35
+ | Motion that responds | Fits your application | Control when you need it |
36
+ |---|---|---|
37
+ | Flip on either axis, fade, and scale | React hook, Vue directive, Svelte action | `flip`, `toggle`, `update`, and state inspection |
38
+ | Pointer tilt batched per animation frame | Existing framework-owned faces stay in place | Model-independent JSON-schema tool definition |
39
+ | Touch, keyboard, and reduced-motion support | Responsive layout and SSR-safe imports | Typed API and change events |
26
40
 
27
- ---
41
+ ## Quick start
42
+
43
+ ```sh
44
+ npm install @simhub2/justflipit
45
+ ```
28
46
 
29
- ### 📦 Installation
47
+ Add a container to your page, then initialize it after the element exists:
30
48
 
31
- **CDN / Local:**
32
49
  ```html
33
- <script src="https://unpkg.com/@simhub2/justflipit/dist/justFlipIt-modern.min.js"></script>
50
+ <div class="product-card">
51
+ <h2>A different perspective</h2>
52
+ <p>Click to discover the other side.</p>
53
+ </div>
34
54
  ```
35
55
 
36
- **NPM:**
37
- ```bash
38
- npm install @simhub2/justflipit
39
- ```
40
56
  ```js
41
- import justFlipIt from "@simhub2/justflipit";
57
+ import justFlipIt from '@simhub2/justflipit';
58
+
59
+ const card = justFlipIt(document.querySelector('.product-card'), {
60
+ Click: true,
61
+ Template: '<h2>There is more to see.</h2><p>Your details go here.</p>',
62
+ Tilt: { max: 10, perspective: 1000, scale: 1.03 },
63
+ Duration: 450,
64
+ });
42
65
  ```
43
66
 
44
- ---
67
+ The original node and its event listeners are preserved. Both faces participate in a responsive grid, so the card adapts to its content. Style the faces to match your design; the core supplies the motion and layout.
45
68
 
46
- ### ▶️ Usage
69
+ > `Template` accepts trusted application HTML. Use the agent bridge's `setText` action for model-generated text. With a framework, render content through the framework instead.
47
70
 
48
- Initialize the flip effect on your elements. The default trigger is **hover**.
71
+ <details>
72
+ <summary><strong>Using a browser script or CommonJS?</strong></summary>
49
73
 
50
- **Hover to Flip (Default)**
51
- ```html
52
- <div class="card">Hover me!</div>
74
+ **Browser script — no bundler:**
53
75
 
76
+ ```html
77
+ <div class="card">Front of the card</div>
78
+ <script src="https://cdn.jsdelivr.net/npm/@simhub2/justflipit@4.0.1/dist/justFlipIt.min.js"></script>
54
79
  <script>
55
- justFlipIt('.card');
80
+ justFlipIt('.card', { Click: true, Template: '<p>Back of the card</p>' });
56
81
  </script>
57
82
  ```
58
83
 
59
- **Click to Flip**
84
+ **CommonJS:**
85
+
60
86
  ```js
61
- justFlipIt('.card', { Click: true });
87
+ const justFlipIt = require('@simhub2/justflipit');
88
+ ```
89
+
90
+ The browser bundle exposes `window.justFlipIt`. ESM and CommonJS imports include matching TypeScript declarations.
91
+
92
+ </details>
93
+
94
+ ## Frameworks
95
+
96
+ Use two direct child elements as the front and back faces. The adapters attach behavior to those existing nodes, so reactive content remains owned by your framework.
97
+
98
+ | Framework | Import | Integration | Cleanup |
99
+ |---|---|---|---|
100
+ | React 18+ | `@simhub2/justflipit/react` | `useFlip()` hook | Effect cleanup; StrictMode compatible |
101
+ | Vue 3 | `@simhub2/justflipit/vue` | `vFlip` directive | `beforeUnmount` |
102
+ | Svelte 4/5 | `@simhub2/justflipit/svelte` | `flip` action | Action `destroy()` |
103
+ | Other frameworks | `@simhub2/justflipit` | Core with `Faces` selectors | Call `destroy()` before unmount |
104
+
105
+ <details open>
106
+ <summary><strong>React</strong> — hook, ref and controller</summary>
107
+
108
+ ```jsx
109
+ import { useFlip } from '@simhub2/justflipit/react';
110
+
111
+ export function ProductCard({ title, details }) {
112
+ const { ref, controller } = useFlip({ Click: true, Tilt: true });
113
+
114
+ return (
115
+ <section>
116
+ <div ref={ref}>
117
+ <div data-flip-front>{title}</div>
118
+ <div data-flip-back>{details}</div>
119
+ </div>
120
+ <button onClick={() => controller.current?.toggle()}>Flip card</button>
121
+ </section>
122
+ );
123
+ }
124
+ ```
125
+
126
+ In Next.js App Router, put this hook in a Client Component with `'use client'`.
127
+
128
+ </details>
129
+
130
+ <details>
131
+ <summary><strong>Vue 3</strong> — directive with reactive options</summary>
132
+
133
+ ```vue
134
+ <script setup>
135
+ import { vFlip } from '@simhub2/justflipit/vue';
136
+
137
+ defineProps({ title: String, details: String });
138
+ </script>
139
+
140
+ <template>
141
+ <div v-flip="{ Click: true, Effect: 'scale' }">
142
+ <div data-flip-front>{{ title }}</div>
143
+ <div data-flip-back>{{ details }}</div>
144
+ </div>
145
+ </template>
146
+ ```
147
+
148
+ </details>
149
+
150
+ <details>
151
+ <summary><strong>Svelte</strong> — action with lifecycle updates</summary>
152
+
153
+ ```svelte
154
+ <script>
155
+ import { flip } from '@simhub2/justflipit/svelte';
156
+ </script>
157
+
158
+ <div use:flip={{ Click: true, Tilt: true }}>
159
+ <div data-flip-front>Front</div>
160
+ <div data-flip-back>Details</div>
161
+ </div>
62
162
  ```
63
163
 
64
- **Enable Tilt Effect**
164
+ </details>
165
+
166
+ **Lifecycle notes:** Imports are safe during server rendering; initialize DOM controllers on the client. Keep `Faces` selectors stable while mounted. Render framework content through application state and omit `Template`. Avoid simultaneously managing the plugin's style, class and accessibility attributes from your framework.
167
+
168
+ ## Agent tools
169
+
170
+ Connect any agent runtime that supports tool calls. Register the cards your agent may control, supply the exported schema to your runtime, and pass parsed tool arguments to the executor.
171
+
65
172
  ```js
66
- // Enable with default settings
67
- justFlipIt('.card', { tilt: true });
68
-
69
- // Customize tilt
70
- justFlipIt('.card', {
71
- tilt: {
72
- max: 15,
73
- perspective: 800
74
- }
173
+ import justFlipIt from '@simhub2/justflipit';
174
+ import { createAgentBridge } from '@simhub2/justflipit/agent';
175
+
176
+ const product = justFlipIt(document.querySelector('.product-card'), {
177
+ Click: true,
75
178
  });
179
+ const bridge = createAgentBridge({ product });
180
+
181
+ // Wrap this definition in the tool format expected by your agent runtime.
182
+ const tool = bridge.tool;
183
+
184
+ // Execute the parsed arguments from a tool call.
185
+ bridge.execute({ id: 'product', action: 'setText', text: 'Selected for you.' });
186
+ const result = bridge.execute({ id: 'product', action: 'flip' });
187
+ // { id: 'product', flipped: true, destroyed: false, effect: 'flip' }
76
188
  ```
77
189
 
78
- ---
190
+ | Action | Result |
191
+ |---|---|
192
+ | `state` | Read the card's current state |
193
+ | `flip` | Show the back |
194
+ | `reset` | Show the front |
195
+ | `toggle` | Switch sides |
196
+ | `setText` | Replace the generated back face with plain text |
79
197
 
80
- ### ⚙️ Options
198
+ The bridge validates commands and accepts only registered card IDs. `setText` uses `textContent`, accepts up to 100,000 characters, and rejects framework-managed cards; update framework content through application state.
81
199
 
82
- Customize the behavior with these options.
200
+ The executor runs in the browser alongside the DOM. Relay server-side tool calls through your application. The package provides a schema and executor; your application supplies the agent runtime and any model credentials.
83
201
 
84
- | Option | Type | Default | Description |
85
- | --------------- | ------- | -------- | ----------------------------------------------------------- |
86
- | `tilt` | Boolean / Object | `false` | Enables a 3D tilt effect. Customize with `{ max, perspective }`. |
87
- | `Click` | Boolean / String | `false` | `true` for click trigger, or a selector for a custom trigger. |
88
- | `FlipX` | Boolean | `false` | `true` for vertical flip (around X-axis). |
89
- | `Template` | String | `null` | HTML content for the back side. |
90
- | `preserveClasses` | Boolean | `true` | Inherit all CSS classes from the original element. |
91
- | `preserveStyles`| Boolean | `true` | Inherit all inline styles from the original element. |
92
- | `Duration` | Number | `400` | Animation duration in ms. |
93
- | `Easing` | String | `ease-in-out` | CSS easing function for the animation. |
94
- | `Style` | Array | `[]` | Apply custom styles to the flip panels (see demo). |
202
+ ## Controller API
95
203
 
204
+ ```js
205
+ card.flip(); // Show back
206
+ card.flip(false); // Show front
207
+ card.toggle(); // Switch sides
208
+ card.update({ Effect: 'fade' }); // Change options in place
209
+ card.getState(); // { flipped, destroyed, effect }
210
+ card.destroy(); // Remove listeners and restore the element
211
+ ```
212
+
213
+ | Call | Returns |
214
+ |---|---|
215
+ | `justFlipIt(element, options)` | One controller |
216
+ | `justFlipIt(selectorOrCollection, options)` | An array of controllers |
217
+ | `justFlipIt.get(element)` | Existing controller, or `undefined` |
218
+ | `justFlipIt.destroy(target)` | Destroys matching instances |
219
+
220
+ Repeated initialization returns the existing instance. Use `update()` to change its options. `destroy()` is safe to call more than once. Initialize an HTML container, such as a `div`, rather than a void element such as `img`.
221
+
222
+ ```js
223
+ card.hoverPanel.addEventListener('justflipit:change', ({ detail }) => {
224
+ console.log(detail.flipped, detail.effect);
225
+ });
226
+ ```
227
+
228
+ ## Options
229
+
230
+ | Option | Default | What it controls |
231
+ |---|---|---|
232
+ | `Click` | `false` | Hover by default; `true` for click; a selector or selector array for delegated clicks |
233
+ | `FlipX` | `false` | X-axis rotation instead of Y-axis |
234
+ | `Template` | Clone of original | Trusted HTML for a generated back face |
235
+ | `Duration` | `400` | Non-negative duration in milliseconds |
236
+ | `Easing` | `cubic-bezier(.22,.61,.36,1)` | CSS easing function |
237
+ | `Effect` | `'flip'` | `'flip'`, `'fade'`, or `'scale'` |
238
+ | `Tilt` | `false` | `true`, `'only'`, or `{ max, perspective, scale }` |
239
+ | `ReducedMotion` | `true` | Respect live `prefers-reduced-motion` preferences |
240
+ | `Faces` | Omitted | Existing direct children: `{ front: selector, back: selector }` |
241
+ | `preserveClasses` | `true` | Copy original classes onto a generated container |
242
+ | `preserveStyles` | `true` | Copy original inline styles onto a generated container |
243
+ | `Style` | `[]` | Apply `{ el: 'self' or selector, style: {...} }` entries |
96
244
 
97
245
  <details>
98
- <summary><b>Advanced Example</b></summary>
246
+ <summary><strong>Style existing faces and choose a different effect</strong></summary>
99
247
 
100
248
  ```js
101
- justFlipIt(".card", {
102
- preserveClasses: false, // Start with a clean slate
249
+ justFlipIt(document.querySelector('.card'), {
250
+ Faces: { front: '[data-front]', back: '[data-back]' },
103
251
  Click: true,
104
252
  FlipX: true,
105
- tilt: true,
106
- Duration: 800,
107
- Easing: "cubic-bezier(0.68, -0.55, 0.27, 1.55)",
108
- Template: "<div>My custom back side!</div>",
253
+ Effect: 'scale',
254
+ Duration: 500,
109
255
  Style: [
110
- {
111
- el: "self",
112
- style: {
113
- background: "#fff",
114
- borderRadius: "1rem",
115
- boxShadow: "0 2px 8px #0002",
116
- },
117
- },
118
- { el: ".front", style: { background: "#f5c939", color: "#222" } },
119
- { el: ".backY", style: { background: "#ca9dfe", color: "#fff" } },
256
+ { el: '[data-front]', style: { background: '#243b2b', borderRadius: '20px' } },
257
+ { el: '[data-back]', style: { background: '#c1f384', borderRadius: '20px' } },
120
258
  ],
121
259
  });
122
260
  ```
261
+
123
262
  </details>
124
263
 
125
- ---
264
+ ## Motion and accessibility
126
265
 
127
- ### Versions & Compatibility
266
+ - **Reversible transitions:** Rapid input reverses the current CSS transition without accumulating animation objects.
267
+ - **Efficient tilt.** Mouse and finger movement share one animation frame. With `Tilt: true` or custom tilt settings, touch tilts the card until release or until the browser takes over a scroll gesture.
268
+ - **Keyboard:** Focus the card, then use Enter or Space to toggle and Escape to reset.
269
+ - **Touch.** Tap to switch sides with any effect. Hover mode distinguishes a tap from a drag, and click mode uses the browser’s native click. Use `Tilt: 'only'` for touch tilt without tap-to-flip.
270
+ - **Hidden faces:** The inactive face is inert and marked `aria-hidden`.
271
+ - **Reduced motion:** System preference changes disable transitions and tilt automatically. Set `ReducedMotion: false` only when your application intentionally overrides this preference.
128
272
 
129
- - **modern**: `justFlipIt-modern.js` (Recommended, uses Web Animations API)
130
- - **vanilla**: `justFlipIt-vanilla.js` (CSS transitions only)
131
- - **combined**: `justFlipIt-combined.js` (Optional jQuery support)
273
+ Targets modern browsers with CSS Grid, Pointer Events, and native `inert` support. Add application-level polyfills when targeting older browsers. SSR safety covers importing the package; DOM initialization requires a browser.
132
274
 
133
- **Browser Support:**
134
- - ✅ Chrome 60+
135
- - ✅ Firefox 55+
136
- - ✅ Safari 12+
137
- - ✅ Edge 79+
275
+ ## Upgrading from v3
138
276
 
139
- ---
277
+ **v4 is a major release.** Check these changes before upgrading an existing integration:
140
278
 
141
- ### License
279
+ | v3 integration | v4 equivalent |
280
+ |---|---|
281
+ | UMD-only npm entry | Default ESM import or callable CommonJS export |
282
+ | Optional jQuery plugin registration | Call `justFlipIt(...)` directly |
283
+ | Separate modern / vanilla / combined implementations | One core; historical import paths and browser filenames remain aliases |
284
+ | `.front` / `.backY` generated face selectors | `[data-jfi-face="front"]` / `[data-jfi-face="back"]` |
285
+ | `._flipY_` / `._flip_` state classes | `[data-jfi-flipped="true"]` |
286
+ | Fixed measured dimensions | Responsive grid; add explicit sizes in your design where needed |
287
+ | Framework DOM replacement | Existing direct-child faces via an adapter or `Faces` |
142
288
 
143
- Released under the **[MIT License](https://opensource.org/licenses/MIT)**.
289
+ Option names retain PascalCase. `Faces` cannot change after initialization. Teardown restores plugin-owned attributes to their initial values.
290
+
291
+ See the [changelog](CHANGELOG.md) for the release overview.
292
+
293
+ ## Development
294
+
295
+ Use Node.js 22 or newer.
296
+
297
+ ```sh
298
+ npm ci
299
+ npm run check # Lifecycle tests and TypeScript consumer checks
300
+ npm run build # ESM, CommonJS, browser bundles, source maps, declarations
301
+ npm pack --dry-run # Inspect published files
302
+ ```
303
+
304
+ Tests cover original node preservation, teardown, delegated events, agent command validation, reduced motion, tilt batching, React StrictMode, Vue updates, and a compiled Svelte 5 component.
305
+
306
+ See the [release guide](https://github.com/SimHub/justFlipIt/blob/main/RELEASING.md) for the GitHub and npm steps.
307
+
308
+ ---
144
309
 
145
- You are free to use, modify, and distribute this project, even for commercial purposes. All that is required is to include the original copyright and license notice in any copy of the software/source.
310
+ <p align="center">
311
+ Built by <a href="https://github.com/SimHub">SimHub</a> · <a href="LICENSE">MIT license</a> · <a href="https://github.com/SimHub/justFlipIt/issues">Report an issue</a> · <a href="https://www.buymeacoffee.com/simhub">Buy me a coffee</a>
312
+ </p>
package/dist/agent.cjs ADDED
@@ -0,0 +1,63 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/adapters/agent.js
20
+ var agent_exports = {};
21
+ __export(agent_exports, {
22
+ createAgentBridge: () => createAgentBridge,
23
+ flipTool: () => flipTool
24
+ });
25
+ module.exports = __toCommonJS(agent_exports);
26
+ var flipTool = {
27
+ name: "control_flip_card",
28
+ description: "Inspect or control a registered flip card. Content is plain text.",
29
+ parameters: { type: "object", properties: { id: { type: "string" }, action: { type: "string", enum: ["state", "flip", "reset", "toggle", "setText"] }, text: { type: "string" } }, required: ["id", "action"], additionalProperties: false }
30
+ };
31
+ function createAgentBridge(cards) {
32
+ const registry = new Map(Object.entries(cards));
33
+ return {
34
+ tool: flipTool,
35
+ execute(command) {
36
+ if (!command || typeof command !== "object" || Object.keys(command).some((key) => !["id", "action", "text"].includes(key))) throw new TypeError("Invalid command");
37
+ const card = registry.get(command.id);
38
+ if (!card || card.destroyed) throw new Error("Unknown or destroyed card");
39
+ switch (command.action) {
40
+ case "state":
41
+ break;
42
+ case "flip":
43
+ card.flip(true);
44
+ break;
45
+ case "reset":
46
+ card.flip(false);
47
+ break;
48
+ case "toggle":
49
+ card.toggle();
50
+ break;
51
+ case "setText":
52
+ if (card.managed) throw new Error("Update framework content through application state");
53
+ if (typeof command.text !== "string" || command.text.length > 1e5) throw new TypeError("Expected text up to 100000 characters");
54
+ card.backWrapper.textContent = command.text;
55
+ break;
56
+ default:
57
+ throw new TypeError("Unknown action");
58
+ }
59
+ return { id: command.id, ...card.getState() };
60
+ }
61
+ };
62
+ }
63
+ //# sourceMappingURL=agent.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/adapters/agent.js"],
4
+ "sourcesContent": ["export const flipTool = {\n name: 'control_flip_card',\n description: 'Inspect or control a registered flip card. Content is plain text.',\n parameters: { type: 'object', properties: { id: { type: 'string' }, action: { type: 'string', enum: ['state', 'flip', 'reset', 'toggle', 'setText'] }, text: { type: 'string' } }, required: ['id', 'action'], additionalProperties: false }\n};\nexport function createAgentBridge(cards) {\n const registry = new Map(Object.entries(cards));\n return {\n tool: flipTool,\n execute(command) {\n if (!command || typeof command !== 'object' || Object.keys(command).some(key => !['id', 'action', 'text'].includes(key))) throw new TypeError('Invalid command');\n const card = registry.get(command.id);\n if (!card || card.destroyed) throw new Error('Unknown or destroyed card');\n switch (command.action) {\n case 'state': break;\n case 'flip': card.flip(true); break;\n case 'reset': card.flip(false); break;\n case 'toggle': card.toggle(); break;\n case 'setText':\n if (card.managed) throw new Error('Update framework content through application state');\n if (typeof command.text !== 'string' || command.text.length > 100000) throw new TypeError('Expected text up to 100000 characters');\n card.backWrapper.textContent = command.text; break;\n default: throw new TypeError('Unknown action');\n }\n return { id: command.id, ...card.getState() };\n }\n };\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,IAAM,WAAW;AAAA,EACtB,MAAM;AAAA,EACN,aAAa;AAAA,EACb,YAAY,EAAE,MAAM,UAAU,YAAY,EAAE,IAAI,EAAE,MAAM,SAAS,GAAG,QAAQ,EAAE,MAAM,UAAU,MAAM,CAAC,SAAS,QAAQ,SAAS,UAAU,SAAS,EAAE,GAAG,MAAM,EAAE,MAAM,SAAS,EAAE,GAAG,UAAU,CAAC,MAAM,QAAQ,GAAG,sBAAsB,MAAM;AAC7O;AACO,SAAS,kBAAkB,OAAO;AACvC,QAAM,WAAW,IAAI,IAAI,OAAO,QAAQ,KAAK,CAAC;AAC9C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,SAAS;AACf,UAAI,CAAC,WAAW,OAAO,YAAY,YAAY,OAAO,KAAK,OAAO,EAAE,KAAK,SAAO,CAAC,CAAC,MAAM,UAAU,MAAM,EAAE,SAAS,GAAG,CAAC,EAAG,OAAM,IAAI,UAAU,iBAAiB;AAC/J,YAAM,OAAO,SAAS,IAAI,QAAQ,EAAE;AACpC,UAAI,CAAC,QAAQ,KAAK,UAAW,OAAM,IAAI,MAAM,2BAA2B;AACxE,cAAQ,QAAQ,QAAQ;AAAA,QACtB,KAAK;AAAS;AAAA,QACd,KAAK;AAAQ,eAAK,KAAK,IAAI;AAAG;AAAA,QAC9B,KAAK;AAAS,eAAK,KAAK,KAAK;AAAG;AAAA,QAChC,KAAK;AAAU,eAAK,OAAO;AAAG;AAAA,QAC9B,KAAK;AACH,cAAI,KAAK,QAAS,OAAM,IAAI,MAAM,oDAAoD;AACtF,cAAI,OAAO,QAAQ,SAAS,YAAY,QAAQ,KAAK,SAAS,IAAQ,OAAM,IAAI,UAAU,uCAAuC;AACjI,eAAK,YAAY,cAAc,QAAQ;AAAM;AAAA,QAC/C;AAAS,gBAAM,IAAI,UAAU,gBAAgB;AAAA,MAC/C;AACA,aAAO,EAAE,IAAI,QAAQ,IAAI,GAAG,KAAK,SAAS,EAAE;AAAA,IAC9C;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,4 @@
1
+ import type { FlipController, FlipState } from './justFlipIt.mjs';
2
+ export interface AgentCommand { id: string; action: 'state' | 'flip' | 'reset' | 'toggle' | 'setText'; text?: string }
3
+ export const flipTool: { name: string; description: string; parameters: Record<string, unknown> };
4
+ export function createAgentBridge(cards: Record<string, FlipController>): { tool: typeof flipTool; execute(command: AgentCommand): FlipState & { id: string } };
@@ -0,0 +1,4 @@
1
+ import type { FlipController, FlipState } from './justFlipIt.mjs';
2
+ export interface AgentCommand { id: string; action: 'state' | 'flip' | 'reset' | 'toggle' | 'setText'; text?: string }
3
+ export const flipTool: { name: string; description: string; parameters: Record<string, unknown> };
4
+ export function createAgentBridge(cards: Record<string, FlipController>): { tool: typeof flipTool; execute(command: AgentCommand): FlipState & { id: string } };
@@ -0,0 +1,4 @@
1
+ import type { FlipController, FlipState } from './justFlipIt';
2
+ export interface AgentCommand { id: string; action: 'state' | 'flip' | 'reset' | 'toggle' | 'setText'; text?: string }
3
+ export const flipTool: { name: string; description: string; parameters: Record<string, unknown> };
4
+ export function createAgentBridge(cards: Record<string, FlipController>): { tool: typeof flipTool; execute(command: AgentCommand): FlipState & { id: string } };
package/dist/agent.mjs ADDED
@@ -0,0 +1,43 @@
1
+ // src/adapters/agent.js
2
+ var flipTool = {
3
+ name: "control_flip_card",
4
+ description: "Inspect or control a registered flip card. Content is plain text.",
5
+ parameters: { type: "object", properties: { id: { type: "string" }, action: { type: "string", enum: ["state", "flip", "reset", "toggle", "setText"] }, text: { type: "string" } }, required: ["id", "action"], additionalProperties: false }
6
+ };
7
+ function createAgentBridge(cards) {
8
+ const registry = new Map(Object.entries(cards));
9
+ return {
10
+ tool: flipTool,
11
+ execute(command) {
12
+ if (!command || typeof command !== "object" || Object.keys(command).some((key) => !["id", "action", "text"].includes(key))) throw new TypeError("Invalid command");
13
+ const card = registry.get(command.id);
14
+ if (!card || card.destroyed) throw new Error("Unknown or destroyed card");
15
+ switch (command.action) {
16
+ case "state":
17
+ break;
18
+ case "flip":
19
+ card.flip(true);
20
+ break;
21
+ case "reset":
22
+ card.flip(false);
23
+ break;
24
+ case "toggle":
25
+ card.toggle();
26
+ break;
27
+ case "setText":
28
+ if (card.managed) throw new Error("Update framework content through application state");
29
+ if (typeof command.text !== "string" || command.text.length > 1e5) throw new TypeError("Expected text up to 100000 characters");
30
+ card.backWrapper.textContent = command.text;
31
+ break;
32
+ default:
33
+ throw new TypeError("Unknown action");
34
+ }
35
+ return { id: command.id, ...card.getState() };
36
+ }
37
+ };
38
+ }
39
+ export {
40
+ createAgentBridge,
41
+ flipTool
42
+ };
43
+ //# sourceMappingURL=agent.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/adapters/agent.js"],
4
+ "sourcesContent": ["export const flipTool = {\n name: 'control_flip_card',\n description: 'Inspect or control a registered flip card. Content is plain text.',\n parameters: { type: 'object', properties: { id: { type: 'string' }, action: { type: 'string', enum: ['state', 'flip', 'reset', 'toggle', 'setText'] }, text: { type: 'string' } }, required: ['id', 'action'], additionalProperties: false }\n};\nexport function createAgentBridge(cards) {\n const registry = new Map(Object.entries(cards));\n return {\n tool: flipTool,\n execute(command) {\n if (!command || typeof command !== 'object' || Object.keys(command).some(key => !['id', 'action', 'text'].includes(key))) throw new TypeError('Invalid command');\n const card = registry.get(command.id);\n if (!card || card.destroyed) throw new Error('Unknown or destroyed card');\n switch (command.action) {\n case 'state': break;\n case 'flip': card.flip(true); break;\n case 'reset': card.flip(false); break;\n case 'toggle': card.toggle(); break;\n case 'setText':\n if (card.managed) throw new Error('Update framework content through application state');\n if (typeof command.text !== 'string' || command.text.length > 100000) throw new TypeError('Expected text up to 100000 characters');\n card.backWrapper.textContent = command.text; break;\n default: throw new TypeError('Unknown action');\n }\n return { id: command.id, ...card.getState() };\n }\n };\n}\n"],
5
+ "mappings": ";AAAO,IAAM,WAAW;AAAA,EACtB,MAAM;AAAA,EACN,aAAa;AAAA,EACb,YAAY,EAAE,MAAM,UAAU,YAAY,EAAE,IAAI,EAAE,MAAM,SAAS,GAAG,QAAQ,EAAE,MAAM,UAAU,MAAM,CAAC,SAAS,QAAQ,SAAS,UAAU,SAAS,EAAE,GAAG,MAAM,EAAE,MAAM,SAAS,EAAE,GAAG,UAAU,CAAC,MAAM,QAAQ,GAAG,sBAAsB,MAAM;AAC7O;AACO,SAAS,kBAAkB,OAAO;AACvC,QAAM,WAAW,IAAI,IAAI,OAAO,QAAQ,KAAK,CAAC;AAC9C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,SAAS;AACf,UAAI,CAAC,WAAW,OAAO,YAAY,YAAY,OAAO,KAAK,OAAO,EAAE,KAAK,SAAO,CAAC,CAAC,MAAM,UAAU,MAAM,EAAE,SAAS,GAAG,CAAC,EAAG,OAAM,IAAI,UAAU,iBAAiB;AAC/J,YAAM,OAAO,SAAS,IAAI,QAAQ,EAAE;AACpC,UAAI,CAAC,QAAQ,KAAK,UAAW,OAAM,IAAI,MAAM,2BAA2B;AACxE,cAAQ,QAAQ,QAAQ;AAAA,QACtB,KAAK;AAAS;AAAA,QACd,KAAK;AAAQ,eAAK,KAAK,IAAI;AAAG;AAAA,QAC9B,KAAK;AAAS,eAAK,KAAK,KAAK;AAAG;AAAA,QAChC,KAAK;AAAU,eAAK,OAAO;AAAG;AAAA,QAC9B,KAAK;AACH,cAAI,KAAK,QAAS,OAAM,IAAI,MAAM,oDAAoD;AACtF,cAAI,OAAO,QAAQ,SAAS,YAAY,QAAQ,KAAK,SAAS,IAAQ,OAAM,IAAI,UAAU,uCAAuC;AACjI,eAAK,YAAY,cAAc,QAAQ;AAAM;AAAA,QAC/C;AAAS,gBAAM,IAAI,UAAU,gBAAgB;AAAA,MAC/C;AACA,aAAO,EAAE,IAAI,QAAQ,IAAI,GAAG,KAAK,SAAS,EAAE;AAAA,IAC9C;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }