@sebastianwessel/isostate 0.1.2 → 0.2.0

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.
@@ -0,0 +1,5 @@
1
+ import { mountScene } from "./runtime/mount-scene.ts";
2
+ import { projectToScreen as projectGridToScreen } from "./utils/projection.ts";
3
+ export { mountScene };
4
+ export declare function projectToScreen(x: number, y: number, cellSize: number, offsetX?: number, offsetY?: number, paddingX?: number, paddingY?: number): ReturnType<typeof projectGridToScreen>;
5
+ //# sourceMappingURL=browser-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-runtime.d.ts","sourceRoot":"","sources":["../src/browser-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,eAAe,IAAI,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE/E,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,wBAAgB,eAAe,CAC9B,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GACf,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAExC"}
@@ -908,6 +908,7 @@ function buildSceneDOM(container, bundle, config) {
908
908
  presence: "removed",
909
909
  };
910
910
  const instance = createElementInstance(initial, layout, assetResolver);
911
+ instance.anchor = assetAnchorForBounds(bundle, initial);
911
912
  instance.node.classList.add(`iso-layer-${def.layer}`);
912
913
  instance.node.setAttribute("data-layer", def.layer);
913
914
  if (initial.presence === "removed") {
@@ -936,6 +937,7 @@ function updateElementTransforms(svg, elements, connectors = []) {
936
937
  const state = map.get(def.id);
937
938
  if (!state)
938
939
  continue;
940
+ state.current = def;
939
941
  updateGeneratedElementContent(state.node, def, layout);
940
942
  applyElementTransform(state.node, def, layout);
941
943
  applyAmbientClasses(state, def.ambient ?? []);
@@ -962,6 +964,32 @@ function getConnectorState(svg, id) {
962
964
  function getResolvedViewBox(bundle) {
963
965
  return resolveSceneLayout(bundle).viewBox;
964
966
  }
967
+ function getCurrentElementBounds(svg, id) {
968
+ const layout = svg._layout;
969
+ const state = svg._elementMap?.get(id);
970
+ if (!layout || !state || state.current.presence === "removed")
971
+ return undefined;
972
+ return boundsToViewBox(calculateElementBounds(state.current, layout, state.anchor));
973
+ }
974
+ function getGridAreaBounds(bundle, area) {
975
+ const layout = resolveSceneLayout(bundle);
976
+ const [x, y] = area.at;
977
+ const [width, height] = area.size;
978
+ let bounds = emptyBounds();
979
+ for (const point of [
980
+ [x, y],
981
+ [x + width, y],
982
+ [x, y + height],
983
+ [x + width, y + height],
984
+ ]) {
985
+ const screen = projectToScreen(point[0], point[1], layout.cellSize, layout.selectedBounds.minX, layout.selectedBounds.minY, layout.padding.x, layout.padding.y);
986
+ bounds = includePoint(bounds, screen.screenX, screen.screenY);
987
+ }
988
+ return boundsToViewBox(bounds);
989
+ }
990
+ function applySceneViewBox(svg, viewBox) {
991
+ svg.setAttribute("viewBox", `${viewBox.minX} ${viewBox.minY} ${viewBox.width} ${viewBox.height}`);
992
+ }
965
993
  // ── Lifecycle helpers ─────────────────────────────────────────────────────
966
994
  /** Hide an element after its exit animation completes. */
967
995
  function hideElementAfterExit(node) {
@@ -1003,15 +1031,7 @@ function calculateContentBounds(bundle, cellSize) {
1003
1031
  for (const element of stop.elements ?? []) {
1004
1032
  if (element.presence === "removed")
1005
1033
  continue;
1006
- const { rawX, rawY } = projectToRaw(element.pos[0] + element.size, element.pos[1] + element.size, cellSize);
1007
- const visualSize = calculateVisualSize(element.size, cellSize);
1008
- const [anchorX, anchorY] = assetAnchorForBounds(bundle, element);
1009
- bounds = includeBounds(bounds, {
1010
- minX: rawX - visualSize * anchorX,
1011
- minY: rawY - visualSize * anchorY,
1012
- maxX: rawX + visualSize * (1 - anchorX),
1013
- maxY: rawY + visualSize * (1 - anchorY),
1014
- });
1034
+ bounds = includeBounds(bounds, calculateRawElementBounds(bundle, element, cellSize));
1015
1035
  }
1016
1036
  for (const connector of stop.connectors ?? []) {
1017
1037
  if (connector.presence === "removed")
@@ -1021,6 +1041,27 @@ function calculateContentBounds(bundle, cellSize) {
1021
1041
  }
1022
1042
  return normalizeBounds(bounds, cellSize);
1023
1043
  }
1044
+ function calculateRawElementBounds(bundle, element, cellSize) {
1045
+ const { rawX, rawY } = projectToRaw(element.pos[0] + element.size, element.pos[1] + element.size, cellSize);
1046
+ const visualSize = calculateVisualSize(element.size, cellSize);
1047
+ const [anchorX, anchorY] = assetAnchorForBounds(bundle, element);
1048
+ return {
1049
+ minX: rawX - visualSize * anchorX,
1050
+ minY: rawY - visualSize * anchorY,
1051
+ maxX: rawX + visualSize * (1 - anchorX),
1052
+ maxY: rawY + visualSize * (1 - anchorY),
1053
+ };
1054
+ }
1055
+ function calculateElementBounds(element, layout, anchor) {
1056
+ const screen = projectToScreen(element.pos[0] + element.size, element.pos[1] + element.size, layout.cellSize, layout.selectedBounds.minX, layout.selectedBounds.minY, layout.padding.x, layout.padding.y);
1057
+ const visualSize = calculateVisualSize(element.size, layout.cellSize);
1058
+ return {
1059
+ minX: screen.screenX - visualSize * anchor[0],
1060
+ minY: screen.screenY - visualSize * anchor[1],
1061
+ maxX: screen.screenX + visualSize * (1 - anchor[0]),
1062
+ maxY: screen.screenY + visualSize * (1 - anchor[1]),
1063
+ };
1064
+ }
1024
1065
  function assetAnchorForBounds(bundle, element) {
1025
1066
  return bundle.assets?.[element.asset]?.anchor ?? [0.5, 1];
1026
1067
  }
@@ -1076,6 +1117,18 @@ function normalizeBounds(bounds, cellSize) {
1076
1117
  return bounds;
1077
1118
  return { minX: 0, minY: 0, maxX: cellSize, maxY: cellSize };
1078
1119
  }
1120
+ function boundsToViewBox(bounds) {
1121
+ const centerX = (bounds.minX + bounds.maxX) / 2;
1122
+ const centerY = (bounds.minY + bounds.maxY) / 2;
1123
+ const width = Math.max(1, bounds.maxX - bounds.minX);
1124
+ const height = Math.max(1, bounds.maxY - bounds.minY);
1125
+ return {
1126
+ minX: roundDimension(centerX - width / 2),
1127
+ minY: roundDimension(centerY - height / 2),
1128
+ width: roundDimension(width),
1129
+ height: roundDimension(height),
1130
+ };
1131
+ }
1079
1132
  function includePoint(bounds, x, y) {
1080
1133
  return {
1081
1134
  minX: Math.min(bounds.minX, x),
@@ -1242,9 +1295,9 @@ function createElementInstance(def, layout, resolveAsset) {
1242
1295
  node.addEventListener("animationend", () => {
1243
1296
  node.style.animation = "";
1244
1297
  }, { once: true });
1245
- return { node, isHidden: false, entryKey: entryAnim, ambient: new Set() };
1298
+ return { node, current: def, anchor: [0.5, 1], isHidden: false, entryKey: entryAnim, ambient: new Set() };
1246
1299
  }
1247
- return { node, isHidden: false, ambient: new Set() };
1300
+ return { node, current: def, anchor: [0.5, 1], isHidden: false, ambient: new Set() };
1248
1301
  }
1249
1302
  function isTextAsset(assetId) {
1250
1303
  return assetId === BUILT_IN_TEXT_ASSET_ID;
@@ -1586,6 +1639,8 @@ class AnimationController {
1586
1639
  _pendingProgress = null;
1587
1640
  _destroyed = false;
1588
1641
  _listeners = new Map();
1642
+ _cameraAnim = null;
1643
+ _cameraState = null;
1589
1644
  // Scroll tracking state
1590
1645
  _minScroll = 0;
1591
1646
  _maxScroll = 0;
@@ -1637,6 +1692,11 @@ class AnimationController {
1637
1692
  this._paused = false;
1638
1693
  this._config = { ...DEFAULT_CONFIG, ...config };
1639
1694
  this._sceneElement = runtime.sceneElement ?? config.sceneElement ?? null;
1695
+ this._cameraState = {
1696
+ viewBox: getResolvedViewBox(bundle),
1697
+ target: { type: "reset" },
1698
+ isZoomed: false,
1699
+ };
1640
1700
  this._engine.init(bundle);
1641
1701
  this._bindScroll();
1642
1702
  }
@@ -1653,6 +1713,7 @@ class AnimationController {
1653
1713
  return;
1654
1714
  }
1655
1715
  this._progress = clamped;
1716
+ this._cancelCameraAnimation();
1656
1717
  if (this._paused)
1657
1718
  return;
1658
1719
  this._scheduleProgressForward(clamped);
@@ -1720,6 +1781,47 @@ class AnimationController {
1720
1781
  this._assertNotDestroyed();
1721
1782
  return this._paused;
1722
1783
  }
1784
+ zoomToElement(id, options = {}) {
1785
+ this._assertNotDestroyed();
1786
+ const svg = this._getSceneSvg();
1787
+ if (!this._bundle || !svg) {
1788
+ throw new ControllerError("CAMERA_NOT_INITIALIZED", "zoomToElement() requires an initialized scene SVG");
1789
+ }
1790
+ const elementBounds = getCurrentElementBounds(svg, id);
1791
+ if (!elementBounds) {
1792
+ throw new ControllerError("CAMERA_TARGET_NOT_FOUND", `Camera target element "${id}" was not found`, {
1793
+ elementId: id,
1794
+ });
1795
+ }
1796
+ this._applyCameraDestination(expandViewBox(elementBounds, this._resolveCameraPadding(options)), { type: "element", id }, options);
1797
+ }
1798
+ zoomToArea(area, options = {}) {
1799
+ this._assertNotDestroyed();
1800
+ if (!this._bundle || !this._getSceneSvg()) {
1801
+ throw new ControllerError("CAMERA_NOT_INITIALIZED", "zoomToArea() requires an initialized scene SVG");
1802
+ }
1803
+ this._assertValidCameraArea(area);
1804
+ const bounds = getGridAreaBounds(this._bundle, area);
1805
+ this._applyCameraDestination(expandViewBox(bounds, this._resolveCameraPadding(options)), {
1806
+ type: "area",
1807
+ at: [...area.at],
1808
+ size: [...area.size],
1809
+ }, options);
1810
+ }
1811
+ resetZoom(options = {}) {
1812
+ this._assertNotDestroyed();
1813
+ if (!this._bundle || !this._getSceneSvg()) {
1814
+ throw new ControllerError("CAMERA_NOT_INITIALIZED", "resetZoom() requires an initialized scene SVG");
1815
+ }
1816
+ this._applyCameraDestination(getResolvedViewBox(this._bundle), { type: "reset" }, options);
1817
+ }
1818
+ getCameraState() {
1819
+ this._assertNotDestroyed();
1820
+ if (!this._cameraState) {
1821
+ throw new ControllerError("CAMERA_NOT_INITIALIZED", "Camera state is not initialized");
1822
+ }
1823
+ return copyCameraState(this._cameraState);
1824
+ }
1723
1825
  /**
1724
1826
  * Destroy controller and clean up all listeners and resources.
1725
1827
  */
@@ -1728,12 +1830,14 @@ class AnimationController {
1728
1830
  this._unbindScroll();
1729
1831
  this._cancelFrame();
1730
1832
  this._cancelTransition();
1833
+ this._cancelCameraAnimation();
1731
1834
  if (this._ownsEngine)
1732
1835
  this._engine.destroy();
1733
1836
  this._listeners.clear();
1734
1837
  this._bundle = null;
1735
1838
  this._container = null;
1736
1839
  this._pendingProgress = null;
1840
+ this._cameraState = null;
1737
1841
  this._destroyed = true;
1738
1842
  }
1739
1843
  // ── Event system ───────────────────────────────────────────────────────
@@ -1823,6 +1927,121 @@ class AnimationController {
1823
1927
  updateElementTransforms(svg, updates, connectors);
1824
1928
  this._applyLifecycleChanges(updates);
1825
1929
  this._applyConnectorLifecycleChanges(connectors);
1930
+ this._applyCameraForProgress(this._progress);
1931
+ }
1932
+ _applyCameraForProgress(progress) {
1933
+ const svg = this._getSceneSvg();
1934
+ if (!this._bundle || !svg)
1935
+ return;
1936
+ const sceneStops = this.scenes;
1937
+ if (sceneStops.length === 0)
1938
+ return;
1939
+ const { previous, next } = surroundingStops(sceneStops, progress);
1940
+ const previousCamera = this._effectiveCameraAt(previous.index);
1941
+ const nextCamera = this._effectiveCameraAt(next.index);
1942
+ const previousViewBox = this._resolveCameraViewBox(previousCamera);
1943
+ const nextViewBox = this._resolveCameraViewBox(nextCamera);
1944
+ const range = next.scene.progress - previous.scene.progress;
1945
+ const rawT = range <= 0 ? 0 : (progress - previous.scene.progress) / range;
1946
+ const t = resolveCameraEasing(nextCamera.easing)(Math.max(0, Math.min(1, rawT)));
1947
+ const viewBox = lerpViewBox(previousViewBox, nextViewBox, t);
1948
+ const target = t < 1 ? previousCamera.target : nextCamera.target;
1949
+ this._setCameraViewBox(svg, viewBox, target);
1950
+ }
1951
+ _effectiveCameraAt(index) {
1952
+ for (let i = index; i >= 0; i--) {
1953
+ const camera = this.scenes[i]?.camera;
1954
+ if (camera) {
1955
+ return {
1956
+ target: camera.target,
1957
+ padding: camera.padding,
1958
+ duration: camera.duration,
1959
+ easing: camera.easing,
1960
+ };
1961
+ }
1962
+ }
1963
+ return { target: { type: "reset" } };
1964
+ }
1965
+ _resolveCameraViewBox(camera) {
1966
+ if (!this._bundle)
1967
+ throw new ControllerError("CAMERA_NOT_INITIALIZED", "Camera requires an initialized bundle");
1968
+ if (camera.target.type === "reset")
1969
+ return getResolvedViewBox(this._bundle);
1970
+ if (camera.target.type === "area") {
1971
+ return expandViewBox(getGridAreaBounds(this._bundle, { at: camera.target.at, size: camera.target.size }), camera.padding ?? 32);
1972
+ }
1973
+ const svg = this._getSceneSvg();
1974
+ if (!svg)
1975
+ throw new ControllerError("CAMERA_NOT_INITIALIZED", "Camera requires an initialized scene SVG");
1976
+ const bounds = getCurrentElementBounds(svg, camera.target.id);
1977
+ if (!bounds) {
1978
+ throw new ControllerError("CAMERA_TARGET_NOT_FOUND", `Camera target element "${camera.target.id}" was not found`, {
1979
+ elementId: camera.target.id,
1980
+ });
1981
+ }
1982
+ return expandViewBox(bounds, camera.padding ?? 32);
1983
+ }
1984
+ _applyCameraDestination(viewBox, target, options) {
1985
+ const svg = this._getSceneSvg();
1986
+ if (!svg)
1987
+ throw new ControllerError("CAMERA_NOT_INITIALIZED", "Camera requires an initialized scene SVG");
1988
+ this._cancelCameraAnimation();
1989
+ const duration = this._resolveCameraDuration(options);
1990
+ if (duration === 0) {
1991
+ this._setCameraViewBox(svg, viewBox, target);
1992
+ return;
1993
+ }
1994
+ const from = currentSvgViewBox(svg) ?? this._cameraState?.viewBox ?? viewBox;
1995
+ const easing = resolveCameraEasing(options.easing ?? this._config.transitionEasing);
1996
+ const start = performance.now();
1997
+ const step = (now) => {
1998
+ const t = Math.min((now - start) / duration, 1);
1999
+ this._setCameraViewBox(svg, lerpViewBox(from, viewBox, easing(t)), target);
2000
+ if (t < 1) {
2001
+ this._cameraAnim = requestAnimationFrame(step);
2002
+ }
2003
+ else {
2004
+ this._cameraAnim = null;
2005
+ }
2006
+ };
2007
+ this._cameraAnim = requestAnimationFrame(step);
2008
+ }
2009
+ _setCameraViewBox(svg, viewBox, target) {
2010
+ applySceneViewBox(svg, viewBox);
2011
+ const full = this._bundle ? getResolvedViewBox(this._bundle) : viewBox;
2012
+ this._cameraState = {
2013
+ viewBox,
2014
+ target,
2015
+ isZoomed: !sameViewBox(viewBox, full),
2016
+ };
2017
+ this._emit("camera-change", this.getCameraState());
2018
+ }
2019
+ _getSceneSvg() {
2020
+ return (this._sceneElement ?? this._container?.querySelector("svg") ?? null);
2021
+ }
2022
+ _resolveCameraPadding(options) {
2023
+ const padding = options.padding ?? 32;
2024
+ if (!Number.isFinite(padding) || padding < 0 || padding > 2048) {
2025
+ throw new ControllerError("INVALID_CAMERA_OPTIONS", "Camera padding must be between 0 and 2048");
2026
+ }
2027
+ return padding;
2028
+ }
2029
+ _resolveCameraDuration(options) {
2030
+ const duration = options.duration ?? this._config.transitionDuration;
2031
+ if (!Number.isInteger(duration) || duration < 0 || duration > 10000) {
2032
+ throw new ControllerError("INVALID_CAMERA_OPTIONS", "Camera duration must be an integer from 0 to 10000");
2033
+ }
2034
+ return duration;
2035
+ }
2036
+ _assertValidCameraArea(area) {
2037
+ if (!Array.isArray(area.at) ||
2038
+ area.at.length !== 2 ||
2039
+ !area.at.every((value) => Number.isFinite(value) && value >= 0) ||
2040
+ !Array.isArray(area.size) ||
2041
+ area.size.length !== 2 ||
2042
+ !area.size.every((value) => Number.isFinite(value) && value > 0)) {
2043
+ throw new ControllerError("INVALID_CAMERA_OPTIONS", "Camera area must use non-negative at and positive size");
2044
+ }
1826
2045
  }
1827
2046
  _applyLifecycleChanges(elements) {
1828
2047
  for (const elDef of elements) {
@@ -2002,6 +2221,12 @@ class AnimationController {
2002
2221
  this._transitionAnim = null;
2003
2222
  }
2004
2223
  }
2224
+ _cancelCameraAnimation() {
2225
+ if (this._cameraAnim !== null) {
2226
+ cancelAnimationFrame(this._cameraAnim);
2227
+ this._cameraAnim = null;
2228
+ }
2229
+ }
2005
2230
  // ── Scroll binding ─────────────────────────────────────────────────────
2006
2231
  _bindScroll() {
2007
2232
  const container = this._config.container;
@@ -2186,9 +2411,70 @@ function oppositeEntryAnimation(exit) {
2186
2411
  return "none";
2187
2412
  }
2188
2413
  }
2414
+ function surroundingStops(scenes, progress) {
2415
+ let previousIndex = 0;
2416
+ let nextIndex = scenes.length - 1;
2417
+ for (let i = 0; i < scenes.length; i++) {
2418
+ if (scenes[i].progress <= progress)
2419
+ previousIndex = i;
2420
+ if (scenes[i].progress >= progress) {
2421
+ nextIndex = i;
2422
+ break;
2423
+ }
2424
+ }
2425
+ return {
2426
+ previous: { scene: scenes[previousIndex], index: previousIndex },
2427
+ next: { scene: scenes[nextIndex], index: nextIndex },
2428
+ };
2429
+ }
2430
+ function expandViewBox(viewBox, padding) {
2431
+ return {
2432
+ minX: roundCameraNumber(viewBox.minX - padding),
2433
+ minY: roundCameraNumber(viewBox.minY - padding),
2434
+ width: roundCameraNumber(Math.max(1, viewBox.width + padding * 2)),
2435
+ height: roundCameraNumber(Math.max(1, viewBox.height + padding * 2)),
2436
+ };
2437
+ }
2438
+ function lerpViewBox(from, to, t) {
2439
+ return {
2440
+ minX: roundCameraNumber(from.minX + (to.minX - from.minX) * t),
2441
+ minY: roundCameraNumber(from.minY + (to.minY - from.minY) * t),
2442
+ width: roundCameraNumber(from.width + (to.width - from.width) * t),
2443
+ height: roundCameraNumber(from.height + (to.height - from.height) * t),
2444
+ };
2445
+ }
2446
+ function sameViewBox(a, b) {
2447
+ return a.minX === b.minX && a.minY === b.minY && a.width === b.width && a.height === b.height;
2448
+ }
2449
+ function currentSvgViewBox(svg) {
2450
+ const raw = svg.getAttribute("viewBox");
2451
+ if (!raw)
2452
+ return undefined;
2453
+ const parts = raw.trim().split(/\s+/).map(Number);
2454
+ if (parts.length !== 4 || parts.some((part) => !Number.isFinite(part)))
2455
+ return undefined;
2456
+ return { minX: parts[0], minY: parts[1], width: parts[2], height: parts[3] };
2457
+ }
2458
+ function resolveCameraEasing(easing) {
2459
+ return resolveEasing(easing === "ease-in-out" ? "easeInOutCubic" : easing === "ease-out" ? "easeOutCubic" : "linear");
2460
+ }
2461
+ function copyCameraState(state) {
2462
+ return {
2463
+ viewBox: { ...state.viewBox },
2464
+ target: state.target?.type === "area"
2465
+ ? { type: "area", at: [...state.target.at], size: [...state.target.size] }
2466
+ : state.target
2467
+ ? { ...state.target }
2468
+ : undefined,
2469
+ isZoomed: state.isZoomed,
2470
+ };
2471
+ }
2472
+ function roundCameraNumber(value) {
2473
+ return Math.round(value * 1000) / 1000;
2474
+ }
2189
2475
 
2190
2476
  const RUNTIME_BUNDLE_FORMAT = "isostate-runtime-bundle";
2191
- const RUNTIME_VERSION = "0.1.2";
2477
+ const RUNTIME_VERSION = "0.2.0";
2192
2478
  const HEX_DIGEST_PATTERN = /^[a-f0-9]{64}$/;
2193
2479
  /** Mount a compiled runtime bundle into an HTML element. */
2194
2480
  function mountScene(target, bundle, options = {}) {
@@ -2278,6 +2564,10 @@ function getResolvedConfig(bundle, options = {}) {
2278
2564
  align: [...bundle.layout.align],
2279
2565
  },
2280
2566
  viewBox: getResolvedViewBox(bundle),
2567
+ camera: {
2568
+ viewBox: getResolvedViewBox(bundle),
2569
+ isZoomed: false,
2570
+ },
2281
2571
  theme: bundle.theme,
2282
2572
  themeVars: getResolvedThemeVars(bundle, options.themeVars),
2283
2573
  scenes: bundle.scenes.map((scene) => ({
@@ -2388,4 +2678,4 @@ function rotr(value, bits) {
2388
2678
  }
2389
2679
 
2390
2680
  export { AnimationController as A, DEFAULT_CELL_SIZE as D, AnimationEngine as a, AssetRegistryImpl as b, applyThemeToElement as c, buildSceneDOM as d, calculateTransform as e, calculateVisualSize as f, composeTheme as g, createAssetRegistry as h, createDefaultRegistry as i, easeInCubic as j, easeInOutCubic as k, easeOutCubic as l, linear as m, mountScene as n, resolveTheme as o, projectToScreen as p, resolveEasing as r };
2391
- //# sourceMappingURL=index-DEv2-G9F.js.map
2681
+ //# sourceMappingURL=index-DoyWxJDm.js.map