zumly 0.9.11 → 0.18.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.
- package/README.md +113 -143
- package/dist/zumly.css +68 -22
- package/dist/zumly.js +7 -0
- package/dist/zumly.min.css +1 -5
- package/dist/zumly.mjs +6 -770
- package/package.json +28 -42
- package/dist/zumly.min.mjs +0 -6
- package/dist/zumly.umd.js +0 -809
package/README.md
CHANGED
|
@@ -5,22 +5,27 @@
|
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
Zumly is a
|
|
8
|
+
Zumly is a JavaScript library for building zooming user interfaces. Create zooming experiences using web standards.
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
12
|
<a href="https://www.npmjs.com/package/zumly"><img src="https://img.shields.io/npm/v/zumly.svg"></a>
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
|
+
## Status
|
|
16
|
+
|
|
17
|
+
Zumly is under active development. The library is usable in production with a stable core API; view preloading, prefetch on hover, and multiple view sources (HTML, URL, async functions, web components) are supported. See [docs/roadMap.md](docs/roadMap.md) for improvement topics and roadmap.
|
|
18
|
+
|
|
15
19
|
## Overview
|
|
16
20
|
|
|
17
|
-
Zumly is a frontend library for creating zoomable user interfaces ([ZUI](https://en.wikipedia.org/wiki/Zooming_user_interface)). Instead of hyperlinks and windows, Zumly uses zooming as
|
|
21
|
+
Zumly is a frontend library for creating **zoomable user interfaces** ([ZUI](https://en.wikipedia.org/wiki/Zooming_user_interface)). Instead of hyperlinks and windows, Zumly uses zooming as the main way to move through information: an infinite virtual canvas where you zoom into elements to reveal more detail.
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
The library focuses on **zoom transitions** and stays **UI-agnostic**—you bring your own CSS and layout. Any design system or custom styling works with Zumly.
|
|
20
24
|
|
|
21
25
|
## Installation
|
|
22
26
|
|
|
23
27
|
### NPM
|
|
28
|
+
|
|
24
29
|
```sh
|
|
25
30
|
npm install zumly
|
|
26
31
|
|
|
@@ -29,235 +34,200 @@ npm install zumly
|
|
|
29
34
|
yarn add zumly
|
|
30
35
|
```
|
|
31
36
|
|
|
32
|
-
###
|
|
33
|
-
Include https://unpkg.com/zumly in your project in a `<script>` tag.
|
|
37
|
+
### CDN
|
|
34
38
|
|
|
39
|
+
Include Zumly in your project via a `<script>` tag from [unpkg.com/zumly](https://unpkg.com/zumly).
|
|
35
40
|
|
|
36
41
|
### Direct download
|
|
37
42
|
|
|
38
|
-
Download
|
|
39
|
-
|
|
43
|
+
Download the built files from [unpkg.com/zumly](https://unpkg.com/zumly/) (see the `dist` folder).
|
|
40
44
|
|
|
41
45
|
## Setup
|
|
42
46
|
|
|
47
|
+
### Browser bundle (global)
|
|
43
48
|
|
|
44
|
-
|
|
49
|
+
1. Add the CSS in your `<head>`:
|
|
45
50
|
|
|
46
|
-
1. Add CSS inside `<head>` tag:
|
|
47
51
|
```html
|
|
48
|
-
|
|
49
52
|
<link rel="stylesheet" href="zumly/dist/zumly.css">
|
|
50
|
-
|
|
51
|
-
<!-- Or "https://unpkg.com/zumly@0.9.11/dist/zumly.css" -->
|
|
52
|
-
|
|
53
|
+
<!-- or https://unpkg.com/zumly/dist/zumly.css -->
|
|
53
54
|
```
|
|
54
55
|
|
|
55
|
-
2.
|
|
56
|
-
```html
|
|
57
|
-
<script type="module">
|
|
58
|
-
import Zumly from "zumly/dist/zumly.mjs"
|
|
59
|
-
|
|
60
|
-
// Or "https://unpkg.com/zumly@0.9.11/dist/zumly.mjs"
|
|
61
|
-
</script>
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### UMD modules
|
|
65
|
-
|
|
66
|
-
1. Add Zumly CSS Styles inside `<head>` tag:
|
|
67
|
-
```html
|
|
68
|
-
|
|
69
|
-
<link rel="stylesheet" href="zumly/dist/zumly.css">
|
|
70
|
-
|
|
71
|
-
<!-- Or "https://unpkg.com/zumly@0.9.11/dist/zumly.css" -->
|
|
72
|
-
|
|
73
|
-
```
|
|
56
|
+
2. Load the JS bundle (it exposes `window.Zumly`):
|
|
74
57
|
|
|
75
|
-
2. Add Zumly as UMD module:
|
|
76
58
|
```html
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// Or "https://unpkg.com/zumly"
|
|
81
|
-
|
|
59
|
+
<script src="zumly/dist/zumly.js"></script>
|
|
60
|
+
<!-- or https://unpkg.com/zumly/dist/zumly.js -->
|
|
82
61
|
```
|
|
83
62
|
|
|
84
|
-
|
|
85
63
|
## Hello World
|
|
86
64
|
|
|
87
|
-
1.
|
|
65
|
+
1. Add a container with the class `zumly-canvas`:
|
|
88
66
|
|
|
89
67
|
```html
|
|
90
|
-
|
|
91
68
|
<div class="example zumly-canvas"></div>
|
|
92
|
-
|
|
93
69
|
```
|
|
94
70
|
|
|
95
|
-
2.
|
|
71
|
+
2. Create your views and start Zumly:
|
|
96
72
|
|
|
97
73
|
```js
|
|
98
|
-
// Some views
|
|
99
74
|
const hello = `
|
|
100
75
|
<div class="z-view">
|
|
101
|
-
H E L L O <br>
|
|
102
|
-
W <span class="zoom-me" data-to="world">O</span> R L D!
|
|
76
|
+
H E L L O <br>
|
|
77
|
+
W <span class="zoom-me" data-to="world">O</span> R L D!
|
|
103
78
|
</div>
|
|
104
79
|
`;
|
|
105
80
|
|
|
106
81
|
const world = `
|
|
107
82
|
<div class="z-view">
|
|
108
|
-
<img src="https://raw.githubusercontent.com/zumly/website/gh-pages/images/world.png"
|
|
83
|
+
<img src="https://raw.githubusercontent.com/zumly/website/gh-pages/images/world.png" alt="World">
|
|
109
84
|
</div>
|
|
110
85
|
`;
|
|
111
86
|
|
|
112
|
-
// Zumly instance
|
|
113
87
|
const app = new Zumly({
|
|
114
88
|
mount: '.example',
|
|
115
89
|
initialView: 'hello',
|
|
116
|
-
views: {
|
|
117
|
-
|
|
118
|
-
world
|
|
119
|
-
}
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
app.init()
|
|
90
|
+
views: { hello, world },
|
|
91
|
+
});
|
|
123
92
|
|
|
93
|
+
await app.init();
|
|
124
94
|
```
|
|
125
95
|
|
|
126
|
-
-
|
|
127
|
-
|
|
128
|
-
### Zumly options
|
|
129
|
-
|
|
130
|
-
1. The Zumly instance:
|
|
131
|
-
|
|
132
|
-
```js
|
|
133
|
-
const app = new Zumly({
|
|
134
|
-
// Mount DOM Element. String. Required
|
|
135
|
-
mount: '.className',
|
|
136
|
-
// First rendered view name. String. Required
|
|
137
|
-
initialView: 'viewName',
|
|
138
|
-
// Store all views. Object. Required
|
|
139
|
-
views: {
|
|
140
|
-
view1,
|
|
141
|
-
view2,
|
|
142
|
-
. . .
|
|
143
|
-
},
|
|
144
|
-
// Customize transitions. Object. Optional
|
|
145
|
-
transitions: {
|
|
146
|
-
// Effects for background views. Array. ['blur', 'sepia', 'saturate']
|
|
147
|
-
effects: ['sepia'],
|
|
148
|
-
// How new injected view is adapted. String. Default 'width'
|
|
149
|
-
cover: 'height',
|
|
150
|
-
// Transition duration. String. Default '1s'
|
|
151
|
-
duration: '1300ms' ,
|
|
152
|
-
// Transition ease. String. Default 'ease-in-out'
|
|
153
|
-
ease: 'cubic-bezier(0.25,0.1,0.25,1)'
|
|
154
|
-
},
|
|
155
|
-
// Activate debug notifications. Boolean. Default false
|
|
156
|
-
debug: true
|
|
157
|
-
})
|
|
158
|
-
// Initialize instance
|
|
159
|
-
app.init()
|
|
160
|
-
```
|
|
96
|
+
- Live example: [CodePen](https://codepen.io/zumly/pen/gOPQovd)
|
|
161
97
|
|
|
162
|
-
|
|
98
|
+
### Options
|
|
163
99
|
|
|
164
|
-
|
|
100
|
+
**Zumly constructor:**
|
|
165
101
|
|
|
166
|
-
|
|
102
|
+
| Option | Type | Required | Description |
|
|
103
|
+
|--------|------|----------|-------------|
|
|
104
|
+
| `mount` | string | Yes | CSS selector for the canvas element (must have class `zumly-canvas`). |
|
|
105
|
+
| `initialView` | string | Yes | Name of the first view to show. |
|
|
106
|
+
| `views` | object | Yes | Map of view names to view sources (see View sources below). |
|
|
107
|
+
| `preload` | string[] | No | View names to resolve and cache when the app initializes. |
|
|
108
|
+
| `transitions` | object | No | Duration, ease, cover, and effects for zoom transitions. |
|
|
109
|
+
| `debug` | boolean | No | Enable debug messages (default: `false`). |
|
|
110
|
+
| `componentContext` | object | No | Context passed to component-style views. |
|
|
167
111
|
|
|
168
|
-
|
|
112
|
+
**Transitions (optional):**
|
|
169
113
|
|
|
114
|
+
```js
|
|
115
|
+
transitions: {
|
|
116
|
+
driver: 'css', // 'css' | 'waapi' | 'anime' | 'gsap' | 'motion' | 'none' or custom function(spec, onComplete)
|
|
117
|
+
effects: ['blur', 'sepia', 'saturate'], // background view effects
|
|
118
|
+
cover: 'width', // or 'height' — how the previous view scales to cover the trigger
|
|
119
|
+
duration: '1s',
|
|
120
|
+
ease: 'ease-in-out',
|
|
121
|
+
}
|
|
170
122
|
```
|
|
171
123
|
|
|
172
|
-
|
|
124
|
+
**Transition drivers:** Zoom animations are handled by a pluggable driver so you can swap the implementation without changing app logic.
|
|
173
125
|
|
|
174
|
-
|
|
126
|
+
| Driver | Description |
|
|
127
|
+
|--------|-------------|
|
|
128
|
+
| `'css'` (default) | CSS keyframes and `animationend`; uses `zumly.css` variables. |
|
|
129
|
+
| `'waapi'` | Web Animations API (`element.animate()`). |
|
|
130
|
+
| `'anime'` | [Anime.js](https://animejs.com/) — load the library (e.g. from CDN) before use. |
|
|
131
|
+
| `'gsap'` | [GSAP](https://greensock.com/gsap/) — load the library (e.g. from CDN) before use. |
|
|
132
|
+
| `'motion'` | [Motion](https://motion.dev/) (motion.dev) — load the library (e.g. from CDN) before use. |
|
|
133
|
+
| `'none'` | No animation; applies final state immediately. Useful for tests or instant UX. |
|
|
134
|
+
| `function(spec, onComplete)` | Custom driver. Receives a transition spec and must call `onComplete()` when done. |
|
|
175
135
|
|
|
176
|
-
|
|
136
|
+
Example with instant transitions (e.g. for tests):
|
|
177
137
|
|
|
138
|
+
```js
|
|
139
|
+
const app = new Zumly({
|
|
140
|
+
mount: '.canvas',
|
|
141
|
+
initialView: 'home',
|
|
142
|
+
views: { home, detail },
|
|
143
|
+
transitions: { driver: 'none', duration: '0s' },
|
|
144
|
+
});
|
|
178
145
|
```
|
|
179
146
|
|
|
180
|
-
|
|
147
|
+
**Zoomable elements:**
|
|
181
148
|
|
|
182
|
-
|
|
149
|
+
- Give the view root the class `z-view`.
|
|
150
|
+
- Add class `zoom-me` and `data-to="viewName"` to the element that triggers zoom-in.
|
|
151
|
+
- Optional per-trigger: `data-with-duration`, `data-with-ease`.
|
|
183
152
|
|
|
184
|
-
|
|
185
|
-
|
|
153
|
+
```html
|
|
154
|
+
<div class="z-view">
|
|
155
|
+
<div class="zoom-me" data-to="detail" data-with-duration="2s" data-with-ease="ease-in">
|
|
156
|
+
Zoom in
|
|
157
|
+
</div>
|
|
186
158
|
</div>
|
|
187
|
-
|
|
188
159
|
```
|
|
189
160
|
|
|
190
|
-
|
|
161
|
+
### View sources
|
|
191
162
|
|
|
192
|
-
|
|
163
|
+
Views can be:
|
|
193
164
|
|
|
194
|
-
|
|
165
|
+
- **HTML string** — static markup.
|
|
166
|
+
- **Async function** — `(context) => string | Promise<string>` or return an `HTMLElement`.
|
|
167
|
+
- **Object with `render()`** — `{ render(): string | Promise<string>, mounted?(): void }`.
|
|
168
|
+
- **URL** — path or full URL to an HTML file (fetched and cached).
|
|
169
|
+
- **Web component tag name** — string containing a hyphen (e.g. `'my-view'`); the custom element is created after it is defined.
|
|
195
170
|
|
|
196
|
-
|
|
171
|
+
Preloading: use `preload: ['viewA', 'viewB']` to resolve those views on init. Hovering over a `zoom-me` trigger prefetches its target view; when a view becomes current, its `zoom-me` targets are prefetched in the background.
|
|
197
172
|
|
|
198
|
-
|
|
173
|
+
## Development
|
|
199
174
|
|
|
200
|
-
|
|
175
|
+
### Requirements
|
|
201
176
|
|
|
202
|
-
|
|
203
|
-
npm run dev
|
|
177
|
+
- Node.js >= 18 (or 16+ with ES module support)
|
|
204
178
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
yarn dev
|
|
208
|
-
```
|
|
179
|
+
### Commands
|
|
209
180
|
|
|
210
|
-
|
|
181
|
+
```sh
|
|
182
|
+
# Build the library
|
|
183
|
+
npm run compile
|
|
211
184
|
|
|
212
|
-
|
|
185
|
+
# Build and serve the demo at http://localhost:9090
|
|
186
|
+
npm run dev
|
|
213
187
|
|
|
214
|
-
|
|
188
|
+
# Run tests (Vitest + Playwright). Install browsers first:
|
|
189
|
+
npm run test:install-browsers
|
|
215
190
|
npm run test
|
|
216
191
|
|
|
217
|
-
#
|
|
192
|
+
# Run tests with coverage
|
|
193
|
+
npm run test:coverage
|
|
218
194
|
|
|
219
|
-
|
|
195
|
+
# Build and pack for publish
|
|
196
|
+
npm run build
|
|
220
197
|
```
|
|
221
198
|
|
|
199
|
+
Tests use [Vitest](https://vitest.dev/) with the browser provider ([Playwright](https://playwright.dev/)), same setup as [SnapDOM](https://github.com/zumerlab/snapdom). Run `npm run test:install-browsers` once (or after upgrading Playwright) to install Chromium.
|
|
200
|
+
|
|
222
201
|
### Building
|
|
223
202
|
|
|
224
203
|
```sh
|
|
225
|
-
npm run
|
|
226
|
-
|
|
227
|
-
# or
|
|
228
|
-
|
|
229
|
-
yarn build
|
|
204
|
+
npm run compile
|
|
230
205
|
```
|
|
231
206
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.
|
|
207
|
+
Output is in the `dist/` folder.
|
|
235
208
|
|
|
236
|
-
|
|
209
|
+
## Changelog
|
|
237
210
|
|
|
238
|
-
|
|
211
|
+
See [CHANGELOG.md](CHANGELOG.md) for version history.
|
|
239
212
|
|
|
240
|
-
|
|
213
|
+
## Roadmap
|
|
241
214
|
|
|
242
|
-
-
|
|
243
|
-
-
|
|
244
|
-
-
|
|
245
|
-
-
|
|
246
|
-
-
|
|
247
|
-
- Add router. [#3](https://github.com/zumly/zumly/issues/3)
|
|
248
|
-
- Allow recalculate zoom position on resize events.
|
|
215
|
+
- Additional view/template adapters
|
|
216
|
+
- Lateral navigation (same zoom level)
|
|
217
|
+
- Navigation widget and programmatic navigation
|
|
218
|
+
- Router integration (e.g. URL sync)
|
|
219
|
+
- Recalculate zoom on window resize
|
|
249
220
|
|
|
221
|
+
Details and more topics: [docs/roadMap.md](docs/roadMap.md).
|
|
250
222
|
|
|
251
|
-
##
|
|
223
|
+
## Community
|
|
252
224
|
|
|
253
225
|
- [Telegram group](https://t.me/ZumlyCommunity)
|
|
254
226
|
|
|
255
|
-
##
|
|
227
|
+
## Origin
|
|
256
228
|
|
|
257
|
-
Zumly is a
|
|
229
|
+
Zumly is a reimagined, framework-agnostic zoom engine inspired by [Zircle UI](https://github.com/zircleUI/zircleUI). It can be used together with [Orbit](https://github.com/zumerlab/orbit) for radial layouts.
|
|
258
230
|
|
|
259
231
|
## License
|
|
260
232
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
233
|
+
MIT. See [LICENSE](LICENSE).
|
package/dist/zumly.css
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* zumly v0.9.11
|
|
3
|
-
* Author Juan Martín Muda, @license MIT
|
|
4
|
-
* https://zumly.org
|
|
5
|
-
*/
|
|
1
|
+
/* src/style.css */
|
|
6
2
|
.zumly-canvas {
|
|
7
3
|
position: absolute;
|
|
8
4
|
width: 100%;
|
|
@@ -12,39 +8,89 @@
|
|
|
12
8
|
padding: 0;
|
|
13
9
|
perspective: 1000px;
|
|
14
10
|
cursor: zoom-out;
|
|
11
|
+
contain: strict;
|
|
15
12
|
}
|
|
16
|
-
|
|
17
13
|
.zumly-canvas:focus {
|
|
18
14
|
outline: none;
|
|
19
15
|
}
|
|
20
|
-
|
|
21
16
|
.z-view {
|
|
22
17
|
position: absolute;
|
|
18
|
+
contain: strict;
|
|
23
19
|
}
|
|
24
|
-
|
|
25
20
|
.z-view.is-current-view {
|
|
26
21
|
cursor: default;
|
|
27
22
|
}
|
|
28
|
-
|
|
29
|
-
.z-view.is-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.z-view.is-previous-view, .z-view.is-last-view, .z-view.has-no-events {
|
|
23
|
+
.z-view.is-previous-view,
|
|
24
|
+
.z-view.is-last-view,
|
|
25
|
+
.z-view.has-no-events {
|
|
34
26
|
pointer-events: none;
|
|
35
27
|
user-select: none;
|
|
36
28
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
.z-view {
|
|
30
|
+
will-change: transform, opacity;
|
|
31
|
+
content-visibility: auto;
|
|
40
32
|
}
|
|
41
|
-
|
|
42
33
|
.z-view.hide {
|
|
43
|
-
opacity: 0
|
|
34
|
+
opacity: 0;
|
|
35
|
+
content-visibility: hidden;
|
|
44
36
|
}
|
|
45
|
-
|
|
46
37
|
.zoom-me {
|
|
47
38
|
cursor: zoom-in;
|
|
48
39
|
}
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
.zoom-current-view-reverse {
|
|
41
|
+
animation-name: zoom-current-view;
|
|
42
|
+
animation-duration: var(--zoom-duration);
|
|
43
|
+
animation-timing-function: var(--zoom-ease);
|
|
44
|
+
animation-direction: reverse;
|
|
45
|
+
}
|
|
46
|
+
.zoom-current-view {
|
|
47
|
+
animation-name: zoom-current-view;
|
|
48
|
+
animation-duration: var(--zoom-duration);
|
|
49
|
+
animation-timing-function: var(--zoom-ease);
|
|
50
|
+
}
|
|
51
|
+
@keyframes zoom-current-view {
|
|
52
|
+
0% {
|
|
53
|
+
transform: var(--current-view-transform-start);
|
|
54
|
+
}
|
|
55
|
+
100% {
|
|
56
|
+
transform: var(--current-view-transform-end);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
.zoom-previous-view {
|
|
60
|
+
animation-name: zoom-previous-view;
|
|
61
|
+
animation-duration: var(--zoom-duration);
|
|
62
|
+
animation-timing-function: var(--zoom-ease);
|
|
63
|
+
}
|
|
64
|
+
.zoom-previous-view-reverse {
|
|
65
|
+
animation-name: zoom-previous-view;
|
|
66
|
+
animation-duration: var(--zoom-duration);
|
|
67
|
+
animation-timing-function: var(--zoom-ease);
|
|
68
|
+
animation-direction: reverse;
|
|
69
|
+
}
|
|
70
|
+
@keyframes zoom-previous-view {
|
|
71
|
+
0% {
|
|
72
|
+
transform: var(--previous-view-transform-start);
|
|
73
|
+
}
|
|
74
|
+
100% {
|
|
75
|
+
transform: var(--previous-view-transform-end);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
.zoom-last-view-reverse {
|
|
79
|
+
animation-name: zoom-last-view;
|
|
80
|
+
animation-duration: var(--zoom-duration);
|
|
81
|
+
animation-timing-function: var(--zoom-ease);
|
|
82
|
+
animation-direction: reverse;
|
|
83
|
+
}
|
|
84
|
+
.zoom-last-view {
|
|
85
|
+
animation-name: zoom-last-view;
|
|
86
|
+
animation-duration: var(--zoom-duration);
|
|
87
|
+
animation-timing-function: var(--zoom-ease);
|
|
88
|
+
}
|
|
89
|
+
@keyframes zoom-last-view {
|
|
90
|
+
0% {
|
|
91
|
+
transform: var(--last-view-transform-start);
|
|
92
|
+
}
|
|
93
|
+
100% {
|
|
94
|
+
transform: var(--last-view-transform-end);
|
|
95
|
+
}
|
|
96
|
+
}
|
package/dist/zumly.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* zumly
|
|
3
|
+
* v.0.18.1
|
|
4
|
+
* Author Juan Martin Muda - Zumerlab
|
|
5
|
+
* License MIT
|
|
6
|
+
*/
|
|
7
|
+
var Et=s=>{throw TypeError(s)};var V=(s,t,r)=>t.has(s)||Et("Cannot "+r);var g=(s,t,r)=>(V(s,t,"read from private field"),r?r.call(s):t.get(s)),T=(s,t,r)=>t.has(s)?Et("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(s):t.set(s,r),A=(s,t,r,n)=>(V(s,t,"write to private field"),n?n.call(s,r):t.set(s,r),r),xt=(s,t,r)=>(V(s,t,"access private method"),r);function jt(s){var t="",r="";if(s!==void 0)return s.map(n=>{t+=`${n.toLowerCase()==="blur"?"blur(0px) ":n.toLowerCase()==="sepia"?"sepia(0) ":n.toLowerCase()==="saturate"?"saturate(0) ":"none"}`,r+=`${n.toLowerCase()==="blur"?"blur(0.8px) ":n.toLowerCase()==="sepia"?"sepia(5) ":n.toLowerCase()==="saturate"?"saturate(8) ":"none"}`}),[t,r]}async function tt(s,t,r,n,o,e){if(!s||!s.classList){let f=document.createElement("div");f.classList.add("z-view"),s&&f.appendChild(s),s=f}else s.classList.contains("z-view")||s.classList.add("z-view");return s.dataset.viewName=t,s.style.transformOrigin="0 0",n?s.classList.add("is-current-view"):s.classList.add("is-new-current-view","has-no-events","hide"),r.append(s),typeof o[t]=="object"&&typeof o[t].mounted=="function"&&await o[t].mounted(),s}function F(s,t,r){t&&r==="welcome"&&console.info(`%c Zumly %c ${t}`,"background: #424085; color: white; border-radius: 3px;","color: #424085"),t&&s&&(r==="info"||r===void 0)&&console.info(`%c Zumly %c ${t}`,"background: #6679A3; color: #304157; border-radius: 3px;","color: #6679A3"),t&&r==="warn"&&console.warn(`%c Zumly %c ${t}`,"background: #DCBF53; color: #424085; border-radius: 3px;","color: #424085"),t&&r==="error"&&console.error(`%c Zumly %c ${t}`,"background: #BE4747; color: white; border-radius: 3px;","color: #424085")}function zt(s,t){if(!s||typeof s!="object"){F(!1,"'options' object has to be provided when instance is defined","error");return}t.options=!0,typeof s.mount=="string"?t.mount=s.mount:F(!1,"'mount' must be a string selector","error"),typeof s.initialView=="string"?t.initialView=s.initialView:F(!1,"'initialView' must be a string","error"),s.views&&typeof s.views=="object"?t.views=s.views:F(!1,"'views' must be an object","error"),t.preload=Array.isArray(s.preload)?s.preload:[],t.debug=typeof s.debug=="boolean"?s.debug:!1,t.componentContext=s.componentContext&&typeof s.componentContext=="object"?s.componentContext:new Map;let r=s.transitions&&typeof s.transitions=="object"?s.transitions:null,n=r&&r.cover,o=typeof n=="string"?n.toLowerCase():null,e=o==="width"||o==="height";if(t.cover=e?o:"width",!e&&r&&n!==void 0&&F(!1,`'transitions.cover' must be either "width" or "height". Falling back to "width".`,"warn"),t.duration=r&&typeof r.duration=="string"?r.duration:"1s",t.ease=r&&typeof r.ease=="string"?r.ease:"ease-in-out",!r||r.effects===void 0)t.effects=["none","none"];else{let c=r.effects;if(!Array.isArray(c)||c.length===0||!c.every(i=>typeof i=="string"))F(!1,`'transitions.effects' must be an array of strings: blur|sepia|saturate (or ["none",...]). Falling back to ["none","none"].`,"warn"),t.effects=["none","none"];else{let i=c.map(h=>h.toLowerCase()),a=i[0]==="none",u=["blur","sepia","saturate"];a||[...new Set(i)].every(h=>u.indexOf(h)!==-1)?(t.effects=jt(i),t.effects||(t.effects=["none","none"])):(F(!1,`'transitions.effects' contains invalid values. Falling back to ["none","none"].`,"warn"),t.effects=["none","none"])}}let f=r&&r.driver,l=typeof f=="string"?f.toLowerCase():null,d=typeof f=="function"?f:null;if(l!==null){let c=["css","waapi","none","anime","gsap","motion"];t.transitionDriver=c.includes(l)?l:"css",c.includes(l)||F(!1,`'transitions.driver' must be "css", "waapi", "none", "anime", "gsap", "motion", or a function. Got "${f}". Falling back to "css".`,"warn")}else d!==null?t.transitionDriver=d:t.transitionDriver="css"}var M,W,kt,U=class{constructor(t={}){T(this,W);T(this,M,{});A(this,M,t)}async resolve(t,r=null){if(typeof t=="string"&&Object.prototype.hasOwnProperty.call(g(this,M),t)){let o=g(this,M)[t];return this.resolve(o,r)}switch(xt(this,W,kt).call(this,t)){case"html":{let o=document.createElement("div");o.innerHTML=t.trim();let e=o.firstElementChild;if(!e)throw new Error("Zumly: view produced no element (html)");return e}case"url":{let o=await fetch(t);if(!o.ok)throw new Error(`Zumly: fetch failed for "${t}" (${o.status})`);let e=await o.text(),f=document.createElement("div");f.innerHTML=e.trim();let l=f.firstElementChild;if(!l)throw new Error("Zumly: view produced no element (url)");return l}case"function":{let o=r&&r.target||document.createElement("div"),e=await t({...r,target:o});if(typeof e=="string")return this.resolve(e,r);if(e instanceof HTMLElement)return e;let f=o.firstElementChild||o;return f.classList.contains("z-view")||f.classList.add("z-view"),f}case"object":{let o=await t.render(r);if(typeof o!="string")throw new Error("Zumly: view render() must return string");return this.resolve(o,r)}case"element":return t.cloneNode(!0);case"webcomponent":return await customElements.whenDefined(t),document.createElement(t);default:throw new Error("Zumly: unknown view type for source")}}};M=new WeakMap,W=new WeakSet,kt=function(t){return typeof t=="function"?"function":t instanceof HTMLElement?"element":typeof t=="object"&&t!==null&&typeof t.render=="function"?"object":typeof t!="string"?"unknown":/^https?:\/\/|^\/|\.html$|\.php$/i.test(t)?"url":t.includes("<")?"html":t.includes("-")?"webcomponent":"unknown"};var C,K=class{constructor(){T(this,C,new Map)}set(t,r,n=null){g(this,C).set(t,{node:r.cloneNode(!0),expires:n?Date.now()+n:null})}get(t){let r=g(this,C).get(t);return r?r.expires!==null&&Date.now()>r.expires?(g(this,C).delete(t),null):r.node.cloneNode(!0):null}has(t){return this.get(t)!==null}invalidate(t){g(this,C).delete(t)}clear(){g(this,C).clear()}};C=new WeakMap;var Dt=300*1e3,_,I,B,$,Q=class{constructor(t={}){T(this,_);T(this,I);T(this,B);T(this,$,new Map);A(this,B,t),A(this,_,new U(t)),A(this,I,new K)}async get(t,r=null){let n=g(this,I).get(t);if(n)return n;if(g(this,$).has(t))return g(this,$).get(t);let o=(async()=>{let e=await g(this,_).resolve(t,r),f=g(this,B)[t];if(typeof f=="string"){let l=/^https?:\/\/|^\/|\.html$|\.php$/i.test(f)?Dt:null;g(this,I).set(t,e,l)}return g(this,$).delete(t),e})();return g(this,$).set(t,o),o}async preloadEager(t,r=null){!Array.isArray(t)||t.length===0||await Promise.all(t.map(n=>this.get(n,r)))}prefetchOnHover(t,r=null){this.get(t,r).catch(()=>{})}scanAndPrefetch(t,r=null){if(!t||!t.querySelectorAll)return;t.querySelectorAll(".zoom-me[data-to]").forEach(o=>{let e=o.dataset.to;e&&this.prefetchOnHover(e,r)})}};_=new WeakMap,I=new WeakMap,B=new WeakMap,$=new WeakMap;function st(s,t){let{type:r,currentView:n,previousView:o,lastView:e,currentStage:f,duration:l,ease:d,canvas:c}=s;if(!n||!o||!f){t();return}r==="zoomIn"?qt(n,o,e,f,l,d,t):r==="zoomOut"?Nt(n,o,e,f,l,d,c,t):t()}function qt(s,t,r,n,o,e,f){s.classList.remove("hide"),s.style.setProperty("--zoom-duration",o),s.style.setProperty("--zoom-ease",e),s.style.setProperty("--current-view-transform-start",n.views[0].backwardState.transform),s.style.setProperty("--current-view-transform-end",n.views[0].forwardState.transform),t.style.setProperty("--zoom-duration",o),t.style.setProperty("--zoom-ease",e),t.style.setProperty("--previous-view-transform-start",n.views[1].backwardState.transform),t.style.setProperty("--previous-view-transform-end",n.views[1].forwardState.transform),r&&(r.style.setProperty("--zoom-duration",o),r.style.setProperty("--zoom-ease",e),r.style.setProperty("--last-view-transform-start",n.views[2].backwardState.transform),r.style.setProperty("--last-view-transform-end",n.views[2].forwardState.transform)),s.style.contentVisibility="auto",t.style.contentVisibility="auto",r&&(r.style.contentVisibility="auto"),s.classList.add("zoom-current-view"),t.classList.add("zoom-previous-view"),r&&r.classList.add("zoom-last-view");let l=r?[s,t,r]:[s,t],d=l.length;function c(i){let a=i.target;a.removeEventListener("animationend",c),Rt(a,n),d--,d===0&&f()}l.forEach(i=>i.addEventListener("animationend",c))}function Rt(s,t){if(s.classList.contains("is-new-current-view")){let r=t.views[0].forwardState;s.classList.replace("is-new-current-view","is-current-view"),s.classList.remove("zoom-current-view","has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform;return}if(s.classList.contains("is-previous-view")){let r=t.views[1].forwardState;s.classList.remove("zoom-previous-view"),s.style.transformOrigin=r.origin,s.style.transform=r.transform;return}if(s.classList.contains("is-last-view")){let r=t.views[2].forwardState;s.classList.remove("zoom-last-view"),s.style.transformOrigin=r.origin,s.style.transform=r.transform}}function Nt(s,t,r,n,o,e,f,l){s.classList.add("zoom-current-view-reverse"),t.classList.add("zoom-previous-view-reverse"),r&&r.classList.add("zoom-last-view-reverse"),s.style.setProperty("--zoom-duration",o),s.style.setProperty("--zoom-ease",e),t.style.setProperty("--zoom-duration",o),t.style.setProperty("--zoom-ease",e),r&&r.style.setProperty("--zoom-duration",o);let d=r?[s,t,r]:[s,t],c=d.length;function i(a){let u=a.target;u.removeEventListener("animationend",i),Yt(u,n,f),c--,c===0&&l()}d.forEach(a=>a.addEventListener("animationend",i))}function Yt(s,t,r){if(s.classList.contains("zoom-current-view-reverse")){try{r&&r.removeChild(s)}catch{try{s.parentElement&&r.removeChild(s.parentElement)}catch{}}return}if(s.classList.contains("zoom-previous-view-reverse")){let n=t.views[1].backwardState;s.classList.remove("zoom-previous-view-reverse"),s.style.transformOrigin="0 0",s.style.transform=n.transform;return}if(s.classList.contains("zoom-last-view-reverse")){let n=t.views[2].backwardState;s.classList.remove("zoom-last-view-reverse"),s.style.transformOrigin=n.origin,s.style.transform=n.transform}}function nt(s,t){let{type:r,currentView:n,previousView:o,lastView:e,currentStage:f,canvas:l}=s;if(!n||!o||!f){t();return}r==="zoomIn"?(n.classList.remove("hide"),n.style.contentVisibility="auto",o.style.contentVisibility="auto",e&&(e.style.contentVisibility="auto"),rt(n,f),rt(o,f),e&&rt(e,f)):r==="zoomOut"&&(_t(n,l),o.style.contentVisibility="auto",e&&(e.style.contentVisibility="auto"),Bt(o,f.views[1].backwardState),e&&Ht(e,f.views[2].backwardState)),t()}function rt(s,t){if(s.classList.contains("is-new-current-view")){let r=t.views[0].forwardState;s.classList.replace("is-new-current-view","is-current-view"),s.classList.remove("zoom-current-view","has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform;return}if(s.classList.contains("is-previous-view")){let r=t.views[1].forwardState;s.classList.remove("zoom-previous-view","has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform;return}if(s.classList.contains("is-last-view")){let r=t.views[2].forwardState;s.classList.remove("zoom-last-view","has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform}}function _t(s,t){try{t&&t.removeChild(s)}catch{try{s.parentElement&&t.removeChild(s.parentElement)}catch{}}}function Bt(s,t){s.classList.remove("zoom-previous-view-reverse","has-no-events"),s.style.transformOrigin="0 0",s.style.transform=t.transform}function Ht(s,t){s.classList.remove("zoom-last-view-reverse","has-no-events"),s.style.transformOrigin=t.origin,s.style.transform=t.transform}function it(s,t){let{type:r,currentView:n,previousView:o,lastView:e,currentStage:f,duration:l,ease:d,canvas:c}=s;if(!n||!o||!f){t();return}let i=Xt(l);r==="zoomIn"?Gt(n,o,e,f,i,d,t):r==="zoomOut"?Ut(n,o,e,f,i,d,c,t):t()}function Xt(s){if(typeof s=="number")return s;let t=String(s),r=parseFloat(t);return t.includes("ms")?r:t.includes("s")?r*1e3:1e3}function Gt(s,t,r,n,o,e,f){s.classList.remove("hide"),s.style.contentVisibility="auto",t.style.contentVisibility="auto",r&&(r.style.contentVisibility="auto");let l=n.views[0],d=n.views[1],c=r&&n.views[2]?n.views[2]:null;s.style.transformOrigin=l.backwardState.origin,s.style.transform=l.backwardState.transform,t.style.transformOrigin=d.backwardState.origin,t.style.transform=d.backwardState.transform,c&&(r.style.transformOrigin=c.backwardState.origin,r.style.transform=c.backwardState.transform);let i=[];i.push(s.animate([{transform:l.backwardState.transform},{transform:l.forwardState.transform}],{duration:o,easing:e,fill:"forwards"})),i.push(t.animate([{transform:d.backwardState.transform},{transform:d.forwardState.transform}],{duration:o,easing:e,fill:"forwards"})),c&&i.push(r.animate([{transform:c.backwardState.transform},{transform:c.forwardState.transform}],{duration:o,easing:e,fill:"forwards"})),Promise.all(i.map(a=>a.finished)).then(()=>{i.forEach(a=>a.cancel()),ot(s,n),ot(t,n),r&&ot(r,n),f()}).catch(()=>{i.forEach(a=>a.cancel()),f()})}function ot(s,t){if(s.classList.contains("is-new-current-view")){let r=t.views[0].forwardState;s.classList.replace("is-new-current-view","is-current-view"),s.classList.remove("has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform;return}if(s.classList.contains("is-previous-view")){let r=t.views[1].forwardState;s.classList.remove("has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform;return}if(s.classList.contains("is-last-view")){let r=t.views[2].forwardState;s.classList.remove("has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform}}function Ut(s,t,r,n,o,e,f,l){let d=n.views[0],c=n.views[1],i=r&&n.views[2]?n.views[2]:null,a=c.backwardState,u=i?i.backwardState:null;s.style.transformOrigin=d.forwardState.origin,s.style.transform=d.forwardState.transform;let m;function h(){t.style.transformOrigin=c.forwardState.origin,r&&i&&(r.style.transformOrigin=i.forwardState.origin);let v=t.style.transform||getComputedStyle(t).transform||c.forwardState.transform,S=r&&i?r.style.transform||getComputedStyle(r).transform||i.forwardState.transform:null;m=[s.animate([{transform:d.forwardState.transform},{transform:d.backwardState.transform}],{duration:o,easing:e,fill:"forwards"})],m.push(t.animate([{transform:v},{transform:a.transform}],{duration:o,easing:e,fill:"forwards"})),r&&u&&m.push(r.animate([{transform:S},{transform:u.transform}],{duration:o,easing:e,fill:"forwards"})),t.style.removeProperty("transform"),r&&r.style.removeProperty("transform"),Promise.all(m.map(w=>w.finished)).then(b).catch(()=>{m.forEach(w=>w.cancel()),l()})}function b(){m.forEach(v=>v.cancel());try{f&&f.removeChild(s)}catch{try{s.parentElement&&f.removeChild(s.parentElement)}catch{}}t.classList.remove("has-no-events"),t.style.transformOrigin="0 0",t.style.transform=a.transform,r&&u&&(r.style.transformOrigin=u.origin,r.style.transform=u.transform),l()}requestAnimationFrame(()=>{requestAnimationFrame(h)})}function at(s,t){let r=typeof globalThis<"u"&&globalThis.anime;if(!r||typeof r!="function"){typeof console<"u"&&console.warn&&console.warn('Zumly anime driver: Anime.js not loaded. Add <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.2/anime.min.js"></script>'),t();return}let{type:n,currentView:o,previousView:e,lastView:f,currentStage:l,duration:d,ease:c,canvas:i}=s;if(!o||!e||!l){t();return}let a=Wt(d);n==="zoomIn"?Qt(r,o,e,f,l,a,c,t):n==="zoomOut"?Jt(r,o,e,f,l,a,c,i,t):t()}function Wt(s){if(typeof s=="number")return s;let t=String(s),r=parseFloat(t);return t.includes("ms")?r:t.includes("s")?r*1e3:1e3}function Ot(){return{a:1,b:0,c:0,d:1,e:0,f:0}}function Kt(s){if(!s||s==="none")return Ot();let t=String(s).match(/matrix\(([-\d.eE]+),\s*([-\d.eE]+),\s*([-\d.eE]+),\s*([-\d.eE]+),\s*([-\d.eE]+),\s*([-\d.eE]+)\)/);return t?{a:parseFloat(t[1])||1,b:parseFloat(t[2])||0,c:parseFloat(t[3])||0,d:parseFloat(t[4])||1,e:parseFloat(t[5])||0,f:parseFloat(t[6])||0}:Ot()}function L(s){return`matrix(${s.a}, ${s.b}, ${s.c}, ${s.d}, ${s.e}, ${s.f})`}function j(s,t,r){return s+(t-s)*r}function D(s,t,r){let n=Math.max(0,Math.min(1,r));return{a:j(s.a,t.a,n),b:j(s.b,t.b,n),c:j(s.c,t.c,n),d:j(s.d,t.d,n),e:j(s.e,t.e,n),f:j(s.f,t.f,n)}}function E(s,t,r){s.style.transformOrigin=t,s.style.transform=r;try{s.getBoundingClientRect()}catch{}return Kt(getComputedStyle(s).transform)}function et(s,t){if(s.classList.contains("is-new-current-view")){let r=t.views[0].forwardState;s.classList.replace("is-new-current-view","is-current-view"),s.classList.remove("has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform;return}if(s.classList.contains("is-previous-view")){let r=t.views[1].forwardState;s.classList.remove("has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform;return}if(s.classList.contains("is-last-view")){let r=t.views[2].forwardState;s.classList.remove("has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform}}function Qt(s,t,r,n,o,e,f,l){t.classList.remove("hide"),t.style.contentVisibility="auto",r.style.contentVisibility="auto",n&&(n.style.contentVisibility="auto");let d=o.views[0],c=o.views[1],i=n&&o.views[2]?o.views[2]:null,a=E(t,d.backwardState.origin,d.backwardState.transform),u=E(t,d.backwardState.origin,d.forwardState.transform),m=E(r,c.backwardState.origin,c.backwardState.transform),h=E(r,c.backwardState.origin,c.forwardState.transform),b=i?E(n,i.backwardState.origin,i.backwardState.transform):null,v=i?E(n,i.backwardState.origin,i.forwardState.transform):null;t.style.transform=L(a),r.style.transform=L(m),i&&(n.style.transform=L(b));let S={value:0};s({targets:S,value:1,duration:e,easing:Tt(f),update:()=>{let y=S.value;t.style.transform=L(D(a,u,y)),r.style.transform=L(D(m,h,y)),i&&(n.style.transform=L(D(b,v,y)))},complete:()=>{et(t,o),et(r,o),n&&et(n,o),l()}})}function Jt(s,t,r,n,o,e,f,l,d){let c=o.views[0],i=o.views[1],a=n&&o.views[2]?o.views[2]:null,u=i.backwardState,m=a?a.backwardState:null,h=E(t,c.forwardState.origin,c.forwardState.transform),b=E(t,c.forwardState.origin,c.backwardState.transform),v=E(r,i.forwardState.origin,i.forwardState.transform),S=E(r,i.forwardState.origin,i.backwardState.transform),y=a?E(n,a.forwardState.origin,a.forwardState.transform):null,w=a?E(n,a.forwardState.origin,a.backwardState.transform):null;t.style.transform=L(h),r.style.transform=L(v),a&&(n.style.transform=L(y));let P={value:0};s({targets:P,value:1,duration:e,easing:Tt(f),update:()=>{let k=P.value;t.style.transform=L(D(h,b,k)),r.style.transform=L(D(v,S,k)),a&&(n.style.transform=L(D(y,w,k)))},complete:()=>{try{l&&l.removeChild(t)}catch{try{t.parentElement&&l.removeChild(t.parentElement)}catch{}}r.classList.remove("zoom-previous-view-reverse"),r.classList.remove("has-no-events"),r.style.transformOrigin="0 0",r.style.transform=u.transform,n&&m&&(n.classList.remove("zoom-last-view-reverse"),n.style.transformOrigin=m.origin,n.style.transform=m.transform),d()}})}function Tt(s){if(typeof s!="string")return"easeInOutQuad";let t=s.toLowerCase();return t==="linear"?"linear":t.includes("ease-in-out")?"easeInOutQuad":t.includes("ease-in")?"easeInQuad":t.includes("ease-out")?"easeOutQuad":t}function ft(s,t){let r=typeof globalThis<"u"&&globalThis.gsap;if(!r||typeof r.to!="function"){typeof console<"u"&&console.warn&&console.warn('Zumly GSAP driver: GSAP not loaded. Add <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>'),t();return}let{type:n,currentView:o,previousView:e,lastView:f,currentStage:l,duration:d,ease:c,canvas:i}=s;if(!o||!e||!l){t();return}let a=Vt(d);n==="zoomIn"?ts(r,o,e,f,l,a,c,t):n==="zoomOut"?ss(r,o,e,f,l,a,c,i,t):t()}function Vt(s){if(typeof s=="number")return s/1e3;let t=String(s),r=parseFloat(t);return t.includes("ms")?r/1e3:t.includes("s")?r:1}function ct(s,t){if(s.classList.contains("is-new-current-view")){let r=t.views[0].forwardState;s.classList.replace("is-new-current-view","is-current-view"),s.classList.remove("has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform;return}if(s.classList.contains("is-previous-view")){let r=t.views[1].forwardState;s.classList.remove("has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform;return}if(s.classList.contains("is-last-view")){let r=t.views[2].forwardState;s.classList.remove("has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform}}function ts(s,t,r,n,o,e,f,l){t.classList.remove("hide"),t.style.contentVisibility="auto",r.style.contentVisibility="auto",n&&(n.style.contentVisibility="auto");let d=o.views[0],c=o.views[1],i=n&&o.views[2]?o.views[2]:null;t.style.transformOrigin=d.backwardState.origin,t.style.transform=d.backwardState.transform,r.style.transformOrigin=c.backwardState.origin,r.style.transform=c.backwardState.transform,i&&(n.style.transformOrigin=i.backwardState.origin,n.style.transform=i.backwardState.transform);let a=s.timeline({onComplete:()=>{ct(t,o),ct(r,o),n&&ct(n,o),l()}});a.to(t,{transform:d.forwardState.transform,duration:e,ease:q(f)},0),a.to(r,{transform:c.forwardState.transform,duration:e,ease:q(f)},0),i&&a.to(n,{transform:i.forwardState.transform,duration:e,ease:q(f)},0)}function ss(s,t,r,n,o,e,f,l,d){let c=o.views[0],i=o.views[1],a=n&&o.views[2]?o.views[2]:null,u=i.backwardState,m=a?a.backwardState:null;t.style.transformOrigin=c.forwardState.origin,t.style.transform=c.forwardState.transform;let h=r.style.transform||getComputedStyle(r).transform||i.forwardState.transform,b=n&&a?n.style.transform||getComputedStyle(n).transform||a.forwardState.transform:null;r.style.transformOrigin=i.forwardState.origin,n&&a&&(n.style.transformOrigin=a.forwardState.origin);let v=s.timeline({onComplete:()=>{try{l&&l.removeChild(t)}catch{try{t.parentElement&&l.removeChild(t.parentElement)}catch{}}r.classList.remove("has-no-events"),r.style.transformOrigin="0 0",r.style.transform=u.transform,n&&m&&(n.style.transformOrigin=m.origin,n.style.transform=m.transform),d()}});v.fromTo(t,{transform:c.forwardState.transform},{transform:c.backwardState.transform,duration:e,ease:q(f)},0),v.fromTo(r,{transform:h},{transform:u.transform,duration:e,ease:q(f)},0),r.style.removeProperty("transform"),n&&m&&(v.fromTo(n,{transform:b},{transform:m.transform,duration:e,ease:q(f)},0),n.style.removeProperty("transform"))}function q(s){if(typeof s!="string")return"power2.inOut";let t=s.toLowerCase();return t==="linear"?"none":t.includes("ease-in-out")?"power2.inOut":t.includes("ease-in")?"power2.in":t.includes("ease-out")?"power2.out":t}function dt(s,t){let r=rs();if(!r||typeof r!="function"){typeof console<"u"&&console.warn&&console.warn('Zumly Motion driver: Motion not loaded. Add <script src="https://cdn.jsdelivr.net/npm/motion@11/dist/motion.min.js"></script>'),t();return}let{type:n,currentView:o,previousView:e,lastView:f,currentStage:l,duration:d,ease:c,canvas:i}=s;if(!o||!e||!l){t();return}let a=ns(d);n==="zoomIn"?is(r,o,e,f,l,a,c,t):n==="zoomOut"?es(r,o,e,f,l,a,c,i,t):t()}function rs(){let s=typeof globalThis<"u"?globalThis:typeof window<"u"?window:{};return s.motion?.animate||s.Motion?.animate||s.animate}function ns(s){if(typeof s=="number")return s/1e3;let t=String(s),r=parseFloat(t);return t.includes("ms")?r/1e3:t.includes("s")?r:1}function Ft(){return{a:1,b:0,c:0,d:1,e:0,f:0}}function os(s){if(!s||s==="none")return Ft();let t=String(s).match(/matrix\(([-\d.eE]+),\s*([-\d.eE]+),\s*([-\d.eE]+),\s*([-\d.eE]+),\s*([-\d.eE]+),\s*([-\d.eE]+)\)/);return t?{a:parseFloat(t[1])||1,b:parseFloat(t[2])||0,c:parseFloat(t[3])||0,d:parseFloat(t[4])||1,e:parseFloat(t[5])||0,f:parseFloat(t[6])||0}:Ft()}function x(s){return`matrix(${s.a}, ${s.b}, ${s.c}, ${s.d}, ${s.e}, ${s.f})`}function R(s,t,r){return s+(t-s)*r}function N(s,t,r){let n=Math.max(0,Math.min(1,r));return{a:R(s.a,t.a,n),b:R(s.b,t.b,n),c:R(s.c,t.c,n),d:R(s.d,t.d,n),e:R(s.e,t.e,n),f:R(s.f,t.f,n)}}function z(s,t,r){s.style.transformOrigin=t,s.style.transform=r;try{s.getBoundingClientRect()}catch{}return os(getComputedStyle(s).transform)}function lt(s,t){if(s.classList.contains("is-new-current-view")){let r=t.views[0].forwardState;s.classList.replace("is-new-current-view","is-current-view"),s.classList.remove("has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform;return}if(s.classList.contains("is-previous-view")){let r=t.views[1].forwardState;s.classList.remove("has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform;return}if(s.classList.contains("is-last-view")){let r=t.views[2].forwardState;s.classList.remove("has-no-events"),s.style.transformOrigin=r.origin,s.style.transform=r.transform}}function is(s,t,r,n,o,e,f,l){t.classList.remove("hide"),t.style.contentVisibility="auto",r.style.contentVisibility="auto",n&&(n.style.contentVisibility="auto");let d=o.views[0],c=o.views[1],i=n&&o.views[2]?o.views[2]:null,a=z(t,d.backwardState.origin,d.backwardState.transform),u=z(t,d.backwardState.origin,d.forwardState.transform),m=z(r,c.backwardState.origin,c.backwardState.transform),h=z(r,c.backwardState.origin,c.forwardState.transform),b=i?z(n,i.backwardState.origin,i.backwardState.transform):null,v=i?z(n,i.backwardState.origin,i.forwardState.transform):null;t.style.transform=x(a),r.style.transform=x(m),i&&(n.style.transform=x(b)),s(0,1,{duration:e,ease:Ct(f),onUpdate:y=>{let w=y;t.style.transform=x(N(a,u,w)),r.style.transform=x(N(m,h,w)),i&&(n.style.transform=x(N(b,v,w)))}}).then(()=>{lt(t,o),lt(r,o),n&<(n,o),l()}).catch(()=>l())}function es(s,t,r,n,o,e,f,l,d){let c=o.views[0],i=o.views[1],a=n&&o.views[2]?o.views[2]:null,u=i.backwardState,m=a?a.backwardState:null,h=z(t,c.forwardState.origin,c.forwardState.transform),b=z(t,c.forwardState.origin,c.backwardState.transform),v=z(r,i.forwardState.origin,i.forwardState.transform),S=z(r,i.forwardState.origin,i.backwardState.transform),y=a?z(n,a.forwardState.origin,a.forwardState.transform):null,w=a?z(n,a.forwardState.origin,a.backwardState.transform):null;t.style.transform=x(h),r.style.transform=x(v),a&&(n.style.transform=x(y)),s(0,1,{duration:e,ease:Ct(f),onUpdate:k=>{let O=k;t.style.transform=x(N(h,b,O)),r.style.transform=x(N(v,S,O)),a&&(n.style.transform=x(N(y,w,O)))}}).then(()=>{try{l&&l.removeChild(t)}catch{try{t.parentElement&&l.removeChild(t.parentElement)}catch{}}r.classList.remove("zoom-previous-view-reverse"),r.classList.remove("has-no-events"),r.style.transformOrigin="0 0",r.style.transform=u.transform,n&&m&&(n.classList.remove("zoom-last-view-reverse"),n.style.transformOrigin=m.origin,n.style.transform=m.transform),d()}).catch(()=>d())}function Ct(s){if(typeof s!="string")return"easeInOut";let t=s.toLowerCase();return t==="linear"?"linear":t.includes("ease-in-out")?"easeInOut":t.includes("ease-in")?"easeIn":t.includes("ease-out")?"easeOut":s}function $t(s){if(typeof s=="function")return{runTransition(r,n){s(r,n)}};switch(typeof s=="string"?s.toLowerCase():"css"){case"waapi":return{runTransition:it};case"none":return{runTransition:nt};case"anime":return{runTransition:at};case"gsap":return{runTransition:ft};case"motion":return{runTransition:dt};default:return{runTransition:st}}}var J=class{constructor(t){this.storedViews=[],this.currentStage=null,this.storedPreviousScale=[1],this.debug=!1,this.trace=[],this.blockEvents=!1,this.touchstartX=0,this.touchstartY=0,this.touchendX=0,this.touchendY=0,this.touching=!1,zt(t,this),this.options?(this.transitionDriver=$t(this.transitionDriver),this._onZoom=this.onZoom.bind(this),this._onTouchStart=this.onTouchStart.bind(this),this._onTouchEnd=this.onTouchEnd.bind(this),this._onKeyUp=this.onKeyUp.bind(this),this._onWeel=this.onWeel.bind(this),this.prefetcher=new Q(this.views),this.canvas=document.querySelector(this.mount),this.canvas.setAttribute("tabindex",0),this.canvas.addEventListener("mouseup",this._onZoom,!1),this.canvas.addEventListener("touchend",this._onZoom,!1),this.canvas.addEventListener("touchstart",this._onTouchStart,{passive:!0}),this.canvas.addEventListener("touchend",this._onTouchEnd,!1),this.canvas.addEventListener("keyup",this._onKeyUp,!1),this.canvas.addEventListener("wheel",this._onWeel,{passive:!0}),this.canvas.addEventListener("mouseover",this._onPrefetchHover=r=>{r.target.classList.contains("zoom-me")&&r.target.dataset.to&&this.prefetcher.prefetchOnHover(r.target.dataset.to,{trigger:r.target,...r.target.dataset})},{passive:!0})):this.notify("is unable to start: no {options} have been passed to the Zumly's instance.","error")}storeViews(t){this.tracing("storedViews()"),this.storedViews.push(t),this.debug&&console.debug("Zumly storedViews",t)}setPreviousScale(t){this.tracing("setPreviousScale()"),this.storedPreviousScale.push(t)}tracing(t){if(this.debug)if(t==="ended"){let r=this.trace.map((n,o)=>`${o===0?`Instance ${this.instance}: ${n}`:`${n}`}`).join(" > ");this.notify(r),this.trace=[]}else this.trace.push(t)}notify(t,r){return F(this.debug,t,r)}zoomLevel(){return this.storedViews.length}async init(){if(this.options){this.tracing("init()"),this.preload&&this.preload.length&&await this.prefetcher.preloadEager(this.preload,null);let t=await this.prefetcher.get(this.initialView,null),r=await tt(t,this.initialView,this.canvas,!0,this.views,this.componentContext);this.prefetcher.scanAndPrefetch(r,null),this.storeViews({zoomLevel:this.storedViews.length,views:[{viewName:this.initialView,backwardState:{origin:"0 0",transform:""}}]})}}async zoomIn(t){this.tracing("zoomIn()");let r=this.canvas,n=r.getBoundingClientRect();var o=n.left,e=n.top;let f=this.storedPreviousScale[this.storedPreviousScale.length-1];this.tracing("getView()");let l={trigger:t,target:document.createElement("div"),context:this.componentContext,props:Object.assign({},t.dataset)},d=await this.prefetcher.get(t.dataset.to,l);this.prefetcher.scanAndPrefetch(d,l);var c=await tt(d,t.dataset.to,r,!1,this.views,this.componentContext);if(c){t.classList.add("zoomed");let p=t.getBoundingClientRect();var i=r.querySelector(".is-current-view"),a=r.querySelector(".is-previous-view"),u=r.querySelector(".is-last-view");c.style.contentVisibility="hidden",i.style.contentVisibility="hidden",a!==null&&(a.style.contentVisibility="hidden"),u!==null&&(u.style.contentVisibility="hidden"),u!==null&&r.removeChild(u);let Z=c.getBoundingClientRect(),ht=Z.width/p.width,At=1/ht,yt=Z.height/p.height,Mt=1/yt;var m=t.dataset.withDuration||this.duration,h=t.dataset.withEase||this.ease,b=this.effects[0],v=this.effects[1],S=this.cover,y,w;S==="width"?(y=ht,w=At):S==="height"&&(y=yt,w=Mt),this.setPreviousScale(y);var P=`translate(${p.x-o+(p.width-Z.width*w)/2}px, ${p.y-e+(p.height-Z.height*w)/2}px) scale(${w})`;c.style.transform=P,i.classList.replace("is-current-view","is-previous-view");let G=i.getBoundingClientRect();var k=i.style.transform;i.style.transformOrigin=`${p.x+p.width/2-G.x}px ${p.y+p.height/2-G.y}px`;let vt=n.width/2-p.width/2-p.x+G.x,pt=n.height/2-p.height/2-p.y+G.y,gt=`translate(${vt}px, ${pt}px) scale(${y})`;i.style.transform=gt;var O=t.getBoundingClientRect(),Pt=`translate(${O.x-o+(O.width-Z.width)/2}px, ${O.y-e+(O.height-Z.height)/2}px)`;if(a!==null){a.classList.replace("is-previous-view","is-last-view");var mt=a.style.transform,H=i.getBoundingClientRect();a.style.transform=`translate(${vt-o}px, ${pt-e}px) scale(${y*f})`;var X=a.querySelector(".zoomed").getBoundingClientRect();a.style.transform=mt,i.style.transform=k;var ut=i.getBoundingClientRect(),Zt=`translate(${n.width/2-p.width/2-p.x+(ut.x-X.x)+H.x-o+(H.width-X.width)/2}px, ${n.height/2-p.height/2-p.y+(ut.y-X.y)+H.y-e+(H.height-X.height)/2}px) scale(${y*f})`}else i.style.transform=k;var Y={zoomLevel:this.storedViews.length,views:[]};let wt=c?{viewName:c.dataset.viewName,backwardState:{origin:c.style.transformOrigin,duration:m,ease:h,transform:P},forwardState:{origin:c.style.transformOrigin,duration:m,ease:h,transform:Pt}}:null,bt=i?{viewName:i.dataset.viewName,backwardState:{origin:i.style.transformOrigin,duration:m,ease:h,transform:k},forwardState:{origin:i.style.transformOrigin,duration:m,ease:h,transform:gt}}:null,St=a?{viewName:a.dataset.viewName,backwardState:{origin:a.style.transformOrigin,duration:m,ease:h,transform:mt},forwardState:{origin:a.style.transformOrigin,duration:m,ease:h,transform:Zt}}:null,Lt=u?{viewName:u}:null;wt!==null&&Y.views.push(wt),bt!==null&&Y.views.push(bt),St!==null&&Y.views.push(St),Lt!==null&&Y.views.push(Lt),this.storeViews(Y),this.currentStage=this.storedViews[this.storedViews.length-1],this.tracing("setCSSVariables()"),this.blockEvents=!0;let It={type:"zoomIn",currentView:c,previousView:i,lastView:a,currentStage:this.currentStage,duration:m,ease:h};this.transitionDriver.runTransition(It,()=>{this.blockEvents=!1,this.tracing("ended")})}}zoomOut(){this.tracing("zoomOut()");let t=this.canvas;var r=t.querySelector(".is-current-view"),n=t.querySelector(".is-previous-view");if(!r||!n){this.notify("zoomOut: current or previous view not found (animation may still be running)","warn");return}this.blockEvents=!0,this.storedPreviousScale.pop(),this.currentStage=this.storedViews[this.storedViews.length-1];let o=this.currentStage.views[3];var e=t.querySelector(".is-last-view");this.tracing("setCSSVariables()");let f=n.querySelector(".zoomed");if(f&&f.classList.remove("zoomed"),n.classList.replace("is-previous-view","is-current-view"),e!==null&&(e.classList.replace("is-last-view","is-previous-view"),e.classList.remove("hide")),o!==void 0&&o.viewName instanceof Node){t.prepend(o.viewName);var l=t.querySelector(".z-view:first-child");l&&(l.style.contentVisibility="auto",l.classList.add("hide"))}let d=this.currentStage.views[0]?.forwardState?.duration??this.duration,c=this.currentStage.views[0]?.forwardState?.ease??this.ease,i={type:"zoomOut",currentView:r,previousView:n,lastView:e,currentStage:this.currentStage,duration:d,ease:c,canvas:t};this.transitionDriver.runTransition(i,()=>{this.blockEvents=!1,this.tracing("ended")}),this.storedViews.pop()}onZoom(t){this.storedViews.length>1&&!this.blockEvents&&!t.target.classList.contains("zoom-me")&&t.target.closest(".is-current-view")===null&&!this.touching&&(this.tracing("onZoom()"),t.stopPropagation(),this.zoomOut()),!this.blockEvents&&t.target.classList.contains("zoom-me")&&!this.touching&&(this.tracing("onZoom()"),t.stopPropagation(),this.zoomIn(t.target))}onKeyUp(t){this.tracing("onKeyUp()"),(t.key==="ArrowLeft"||t.key==="ArrowDown")&&(t.preventDefault(),this.storedViews.length>1&&!this.blockEvents?this.zoomOut():this.notify(`is on level zero. Can't zoom out. Trigger: ${t.key}`,"warn")),(t.key==="ArrowRight"||t.key==="ArrowUp")&&(t.preventDefault(),this.notify(t.key+"has not actions defined"))}onWeel(t){this.blockEvents||(this.tracing("onWeel()"),t.deltaY<0,t.deltaY>0&&this.storedViews.length>1&&!this.blockEvents&&this.zoomOut())}onTouchStart(t){this.tracing("onTouchStart()"),this.touching=!0,this.touchstartX=t.changedTouches[0].screenX,this.touchstartY=t.changedTouches[0].screenY}onTouchEnd(t){this.blockEvents||(this.tracing("onTouchEnd()"),this.touchendX=t.changedTouches[0].screenX,this.touchendY=t.changedTouches[0].screenY,this.handleGesture(t))}handleGesture(t){t.stopPropagation(),this.tracing("handleGesture()"),this.touchendX<this.touchstartX-30&&(this.storedViews.length>1&&!this.blockEvents?(this.tracing("swipe left"),this.zoomOut()):this.notify("is on level zero. Can't zoom out. Trigger: Swipe left","warn")),this.touchendY<this.touchstartY-10&&(this.storedViews.length>1&&!this.blockEvents?this.tracing("swipe up"):this.notify("is on level zero. Can't zoom out. Trigger: Swipe up","warn")),this.touchendY===this.touchstartY&&!this.blockEvents&&t.target.classList.contains("zoom-me")&&this.touching&&(this.touching=!1,this.tracing("tap"),t.preventDefault(),this.zoomIn(t.target)),this.touchendY===this.touchstartY&&this.storedViews.length>1&&!this.blockEvents&&!t.target.classList.contains("zoom-me")&&t.target.closest(".is-current-view")===null&&this.touching&&(this.touching=!1,this.tracing("tap"),this.zoomOut())}};window.Zumly=J;
|
package/dist/zumly.min.css
CHANGED
|
@@ -1,5 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* zumly v0.9.11
|
|
3
|
-
* Author Juan Martín Muda, @license MIT
|
|
4
|
-
* https://zumly.org
|
|
5
|
-
*/.zumly-canvas{position:absolute;width:100%;height:100%;overflow:hidden;margin:0;padding:0;perspective:1000px;cursor:zoom-out}.zumly-canvas:focus{outline:none}.z-view{position:absolute}.z-view.is-current-view{cursor:default}.z-view.has-no-events,.z-view.is-last-view,.z-view.is-previous-view{pointer-events:none;user-select:none}.z-view.performance{will-change:transform,opacity,filter}.z-view.hide{opacity:0}.zoom-me{cursor:zoom-in}
|
|
1
|
+
.zumly-canvas{position:absolute;width:100%;height:100%;overflow:hidden;margin:0;padding:0;perspective:1000px;cursor:zoom-out;contain:strict}.zumly-canvas:focus{outline:none}.z-view{position:absolute;contain:strict}.z-view.is-current-view{cursor:default}.z-view.is-previous-view,.z-view.is-last-view,.z-view.has-no-events{pointer-events:none;user-select:none}.z-view{will-change:transform,opacity;content-visibility:auto}.z-view.hide{opacity:0;content-visibility:hidden}.zoom-me{cursor:zoom-in}.zoom-current-view-reverse{animation-name:zoom-current-view;animation-duration:var(--zoom-duration);animation-timing-function:var(--zoom-ease);animation-direction:reverse}.zoom-current-view{animation-name:zoom-current-view;animation-duration:var(--zoom-duration);animation-timing-function:var(--zoom-ease)}@keyframes zoom-current-view{0%{transform:var(--current-view-transform-start)}to{transform:var(--current-view-transform-end)}}.zoom-previous-view{animation-name:zoom-previous-view;animation-duration:var(--zoom-duration);animation-timing-function:var(--zoom-ease)}.zoom-previous-view-reverse{animation-name:zoom-previous-view;animation-duration:var(--zoom-duration);animation-timing-function:var(--zoom-ease);animation-direction:reverse}@keyframes zoom-previous-view{0%{transform:var(--previous-view-transform-start)}to{transform:var(--previous-view-transform-end)}}.zoom-last-view-reverse{animation-name:zoom-last-view;animation-duration:var(--zoom-duration);animation-timing-function:var(--zoom-ease);animation-direction:reverse}.zoom-last-view{animation-name:zoom-last-view;animation-duration:var(--zoom-duration);animation-timing-function:var(--zoom-ease)}@keyframes zoom-last-view{0%{transform:var(--last-view-transform-start)}to{transform:var(--last-view-transform-end)}}
|