venuekit 0.10.0 → 0.10.2
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 +287 -280
- package/dist/{chunk-5H5QKXPV.js → chunk-QQQM6AFF.js} +53 -23
- package/dist/{chunk-47ILVPKZ.cjs → chunk-Z47OPTEP.cjs} +54 -24
- package/dist/index.cjs +12 -2
- package/dist/index.d.cts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +11 -1
- package/dist/{place-types-CeTjPHTF.d.cts → place-types-Dc0eabAi.d.cts} +12 -1
- package/dist/{place-types-CeTjPHTF.d.ts → place-types-Dc0eabAi.d.ts} +12 -1
- package/dist/react.cjs +396 -244
- package/dist/react.d.cts +16 -4
- package/dist/react.d.ts +16 -4
- package/dist/react.js +212 -60
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
zoneLocalSize,
|
|
46
46
|
zoneOutline,
|
|
47
47
|
zoneWithLocalSize
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-QQQM6AFF.js";
|
|
49
49
|
|
|
50
50
|
// ../canvas/src/camera.ts
|
|
51
51
|
var MIN_ZOOM = 0.05;
|
|
@@ -270,7 +270,15 @@ function tableBodyBox(table) {
|
|
|
270
270
|
function elementBounds(_layout, element) {
|
|
271
271
|
return pieceBounds(element);
|
|
272
272
|
}
|
|
273
|
+
var boundsCache = /* @__PURE__ */ new WeakMap();
|
|
273
274
|
function pieceBounds(element) {
|
|
275
|
+
const cached = boundsCache.get(element);
|
|
276
|
+
if (cached !== void 0) return cached;
|
|
277
|
+
const box = computeBounds(element);
|
|
278
|
+
boundsCache.set(element, box);
|
|
279
|
+
return box;
|
|
280
|
+
}
|
|
281
|
+
function computeBounds(element) {
|
|
274
282
|
if (element.type === "zone") return zoneBounds(element);
|
|
275
283
|
if (element.type === "landmark") {
|
|
276
284
|
return centredBox(element.transform, element.width, element.height, element.transform.rotation);
|
|
@@ -481,16 +489,12 @@ function buildScene(input) {
|
|
|
481
489
|
}
|
|
482
490
|
}
|
|
483
491
|
}
|
|
484
|
-
const
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
else byElement.set(u.elementId, [u]);
|
|
489
|
-
}
|
|
490
|
-
for (const el of mode === "designer" ? layout.elements : []) {
|
|
491
|
-
if (el.type === "landmark" || colorOf(refOf(el)) !== null) continue;
|
|
492
|
+
const chipped = mode === "designer" ? layout.elements.filter((el) => el.type !== "landmark" && colorOf(refOf(el)) === null) : [];
|
|
493
|
+
const byElement = new Map(chipped.map((el) => [el.id, []]));
|
|
494
|
+
if (byElement.size > 0) for (const u of units) byElement.get(u.elementId)?.push(u);
|
|
495
|
+
for (const el of chipped) {
|
|
492
496
|
const own = byElement.get(el.id);
|
|
493
|
-
if (!own) continue;
|
|
497
|
+
if (!own || own.length === 0) continue;
|
|
494
498
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
495
499
|
for (const u of own) {
|
|
496
500
|
if (u.x < minX) minX = u.x;
|
|
@@ -1326,6 +1330,8 @@ var es = {
|
|
|
1326
1330
|
mapLabel: "Plano del lugar. Movete con las flechas y eleg\xED con Enter.",
|
|
1327
1331
|
zoomIn: "Acercar",
|
|
1328
1332
|
zoomOut: "Alejar",
|
|
1333
|
+
zoomToChoose: "Hay {n} lugares a la vista. Acerc\xE1 el mapa para elegir uno.",
|
|
1334
|
+
wheelHint: "Para acercar el mapa, us\xE1 Ctrl + rueda o los botones + y \u2212",
|
|
1329
1335
|
overviewMapLabel: "Plano del lugar. Toc\xE1 una entrada en el mapa o elegila en la lista de abajo.",
|
|
1330
1336
|
overviewList: "Entradas del lugar",
|
|
1331
1337
|
soldOut: "Agotada",
|
|
@@ -1369,6 +1375,8 @@ var en = {
|
|
|
1369
1375
|
mapLabel: "Venue map. Move with the arrow keys and choose with Enter.",
|
|
1370
1376
|
zoomIn: "Zoom in",
|
|
1371
1377
|
zoomOut: "Zoom out",
|
|
1378
|
+
zoomToChoose: "There are {n} spots in view. Zoom in to choose one.",
|
|
1379
|
+
wheelHint: "To zoom the map, use Ctrl + scroll or the + and \u2212 buttons",
|
|
1372
1380
|
overviewMapLabel: "Venue map. Tap a ticket on the map or choose it from the list below.",
|
|
1373
1381
|
overviewList: "Tickets at the venue",
|
|
1374
1382
|
soldOut: "Sold out",
|
|
@@ -1481,11 +1489,19 @@ var PICKER_CSS = `
|
|
|
1481
1489
|
min-height:300px;max-height:70vh;background:var(--vk-surface);
|
|
1482
1490
|
border:1px solid var(--vk-line);border-radius:var(--vk-radius-lg);overflow:hidden;touch-action:none}
|
|
1483
1491
|
.vk-root[data-fill="true"] .vk-map{flex:1;aspect-ratio:auto;min-height:0;max-height:none}
|
|
1492
|
+
.vk-map[data-cooperative="true"]{touch-action:pan-y}
|
|
1484
1493
|
.vk-canvas{display:block;width:100%;height:100%}
|
|
1485
1494
|
.vk-a11y{position:absolute;inset:0;pointer-events:none}
|
|
1486
1495
|
.vk-seat{position:absolute;transform:translate(-50%,-50%);padding:0;margin:0;border:0;background:transparent;
|
|
1487
1496
|
border-radius:50%;cursor:pointer;color:transparent;overflow:hidden}
|
|
1488
1497
|
.vk-seat:focus-visible{outline:3px solid var(--vk-accent);outline-offset:2px}
|
|
1498
|
+
.vk-choose{position:absolute;left:8px;top:8px;max-width:calc(100% - 64px);min-height:44px;padding:8px 12px;
|
|
1499
|
+
border:1px solid var(--vk-line);border-radius:var(--vk-radius);background:var(--vk-bg);color:var(--vk-fg);
|
|
1500
|
+
font:inherit;font-size:14px;text-align:left;cursor:pointer;opacity:0}
|
|
1501
|
+
.vk-choose:focus{opacity:1;pointer-events:auto;outline:3px solid var(--vk-accent);outline-offset:2px}
|
|
1502
|
+
.vk-map-hint{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin:0;max-width:calc(100% - 32px);
|
|
1503
|
+
padding:8px 12px;border-radius:var(--vk-radius);background:rgba(0,0,0,.72);color:#fff;font-size:14px;
|
|
1504
|
+
text-align:center;pointer-events:none}
|
|
1489
1505
|
.vk-zoom{position:absolute;right:8px;bottom:8px;display:flex;flex-direction:column;gap:4px}
|
|
1490
1506
|
.vk-zoom button{width:36px;height:36px;border:1px solid var(--vk-line);background:var(--vk-bg);
|
|
1491
1507
|
color:var(--vk-fg);border-radius:var(--vk-radius);font-size:16px;line-height:1;cursor:pointer}
|
|
@@ -1567,7 +1583,37 @@ function useImage(src) {
|
|
|
1567
1583
|
|
|
1568
1584
|
// ../react/src/VenueCanvas.tsx
|
|
1569
1585
|
import { useEffect as useEffect2, useMemo, useRef, useState as useState2 } from "react";
|
|
1586
|
+
|
|
1587
|
+
// ../react/src/map-targets.ts
|
|
1588
|
+
var MAX_SEAT_BUTTONS = 500;
|
|
1589
|
+
var MIN_PICK_RADIUS_PX = 6;
|
|
1590
|
+
function chooseTarget(visible, activeId, centre) {
|
|
1591
|
+
const active = activeId === null ? void 0 : visible.find((n) => n.id === activeId);
|
|
1592
|
+
if (active) return active;
|
|
1593
|
+
let best2 = null;
|
|
1594
|
+
let bestD = Infinity;
|
|
1595
|
+
for (const n of visible) {
|
|
1596
|
+
const d = (n.x - centre.x) ** 2 + (n.y - centre.y) ** 2;
|
|
1597
|
+
if (d < bestD) {
|
|
1598
|
+
bestD = d;
|
|
1599
|
+
best2 = n;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
return best2;
|
|
1603
|
+
}
|
|
1604
|
+
function zoomToChoose(camera, visibleCount, target) {
|
|
1605
|
+
const factor = Math.max(2, Math.sqrt(visibleCount / (MAX_SEAT_BUTTONS / 2)));
|
|
1606
|
+
return { x: target.x, y: target.y, zoom: clampZoom(camera.zoom * factor) };
|
|
1607
|
+
}
|
|
1608
|
+
function tapZoom(camera, viewport, screen, radiusPx) {
|
|
1609
|
+
if (radiusPx >= MIN_PICK_RADIUS_PX) return null;
|
|
1610
|
+
const next = zoomAt(camera, viewport, screen, Math.max(2, MIN_NUMBERED_RADIUS_PX / Math.max(radiusPx, 0.01)));
|
|
1611
|
+
return next.zoom > camera.zoom ? next : null;
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
// ../react/src/VenueCanvas.tsx
|
|
1570
1615
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1616
|
+
var WHEEL_HINT_MS = 1600;
|
|
1571
1617
|
var ARROWS = {
|
|
1572
1618
|
ArrowUp: "up",
|
|
1573
1619
|
ArrowDown: "down",
|
|
@@ -1638,6 +1684,9 @@ function VenueCanvas(props) {
|
|
|
1638
1684
|
);
|
|
1639
1685
|
const visible = useMemo(() => new Set(scene.visibleUnitIds), [scene]);
|
|
1640
1686
|
const visibleNodes = useMemo(() => a11yNodes.filter((n) => visible.has(n.id)), [a11yNodes, visible]);
|
|
1687
|
+
const tooMany = visibleNodes.length > MAX_SEAT_BUTTONS;
|
|
1688
|
+
const unitById = useMemo(() => new Map(units.map((u) => [u.id, u])), [units]);
|
|
1689
|
+
const chooseRef = useRef(null);
|
|
1641
1690
|
const sizeOf = (elementId) => Math.max(24, 2 * (props.radii.get(elementId) ?? DEFAULT_UNIT_RADIUS) * camera.zoom);
|
|
1642
1691
|
const lastSize = useRef({ width: 0, height: 0 });
|
|
1643
1692
|
const onViewportChangeRef = useRef(props.onViewportChange);
|
|
@@ -1674,10 +1723,23 @@ function VenueCanvas(props) {
|
|
|
1674
1723
|
viewportRef.current = viewport;
|
|
1675
1724
|
const onCameraChangeRef = useRef(props.onCameraChange);
|
|
1676
1725
|
onCameraChangeRef.current = props.onCameraChange;
|
|
1726
|
+
const cooperativeRef = useRef(props.cooperative === true);
|
|
1727
|
+
cooperativeRef.current = props.cooperative === true;
|
|
1728
|
+
const [wheelHint, setWheelHint] = useState2(false);
|
|
1729
|
+
const hintTimer = useRef(null);
|
|
1730
|
+
useEffect2(() => () => {
|
|
1731
|
+
if (hintTimer.current) clearTimeout(hintTimer.current);
|
|
1732
|
+
}, []);
|
|
1677
1733
|
useEffect2(() => {
|
|
1678
1734
|
const canvas = canvasRef.current;
|
|
1679
1735
|
if (!canvas) return;
|
|
1680
1736
|
const onWheel = (e) => {
|
|
1737
|
+
if (cooperativeRef.current && !e.ctrlKey && !e.metaKey) {
|
|
1738
|
+
setWheelHint(true);
|
|
1739
|
+
if (hintTimer.current) clearTimeout(hintTimer.current);
|
|
1740
|
+
hintTimer.current = setTimeout(() => setWheelHint(false), WHEEL_HINT_MS);
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1681
1743
|
e.preventDefault();
|
|
1682
1744
|
const rect = canvas.getBoundingClientRect();
|
|
1683
1745
|
const currentCamera = cameraRef.current;
|
|
@@ -1697,7 +1759,7 @@ function VenueCanvas(props) {
|
|
|
1697
1759
|
if (!id) return;
|
|
1698
1760
|
const button = wrapRef.current?.querySelector(`[data-unit-id="${id}"]`);
|
|
1699
1761
|
pendingFocus.current = null;
|
|
1700
|
-
button?.focus();
|
|
1762
|
+
(button ?? chooseRef.current)?.focus();
|
|
1701
1763
|
}, [visibleNodes]);
|
|
1702
1764
|
const send = (input) => {
|
|
1703
1765
|
const result = reduceGesture(gesture.current, camera, viewport, input);
|
|
@@ -1705,8 +1767,26 @@ function VenueCanvas(props) {
|
|
|
1705
1767
|
if (result.camera !== camera) props.onCameraChange(result.camera);
|
|
1706
1768
|
if (!result.tap) return;
|
|
1707
1769
|
const unitId = hitUnit({ index, camera, viewport, screenPoint: result.tap, units, radii: props.radii });
|
|
1708
|
-
if (unitId)
|
|
1709
|
-
|
|
1770
|
+
if (!unitId) {
|
|
1771
|
+
props.onTapEmpty?.(result.tap);
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
const unit = unitById.get(unitId);
|
|
1775
|
+
if (unit && props.focusRef !== null && unit.placeTypeRef === props.focusRef) {
|
|
1776
|
+
const closer = tapZoom(camera, viewport, result.tap, (props.radii.get(unit.elementId) ?? DEFAULT_UNIT_RADIUS) * camera.zoom);
|
|
1777
|
+
if (closer) {
|
|
1778
|
+
props.onCameraChange(closer);
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
props.onActivateUnit(unitId);
|
|
1783
|
+
};
|
|
1784
|
+
const zoomInToChoose = () => {
|
|
1785
|
+
const target = chooseTarget(visibleNodes, activeId, camera);
|
|
1786
|
+
if (!target) return;
|
|
1787
|
+
setActiveId(target.id);
|
|
1788
|
+
pendingFocus.current = target.id;
|
|
1789
|
+
props.onCameraChange(zoomToChoose(camera, visibleNodes.length, target));
|
|
1710
1790
|
};
|
|
1711
1791
|
const samplePointer = (e) => {
|
|
1712
1792
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
@@ -1738,6 +1818,7 @@ function VenueCanvas(props) {
|
|
|
1738
1818
|
"data-testid": "venue-map",
|
|
1739
1819
|
"data-background": props.backgroundStatus,
|
|
1740
1820
|
"data-camera": `${camera.x.toFixed(2)},${camera.y.toFixed(2)},${camera.zoom.toFixed(4)}`,
|
|
1821
|
+
"data-cooperative": props.cooperative ? "true" : void 0,
|
|
1741
1822
|
style: {
|
|
1742
1823
|
["--vk-plan-ratio"]: props.ratio ? `${Math.round(props.ratio.width)} / ${Math.round(props.ratio.height)}` : `${layout.meta.width} / ${layout.meta.height}`,
|
|
1743
1824
|
...props.height !== void 0 ? { height: props.height, aspectRatio: "auto", minHeight: 0, maxHeight: "none" } : {}
|
|
@@ -1758,7 +1839,7 @@ function VenueCanvas(props) {
|
|
|
1758
1839
|
onPointerCancel: (e) => send({ type: "pointercancel", pointer: samplePointer(e) })
|
|
1759
1840
|
}
|
|
1760
1841
|
),
|
|
1761
|
-
/* @__PURE__ */ jsx("div", { className: "vk-a11y", role: "group", "aria-label": messages.mapLabel, onKeyDown, children: visibleNodes.map((node) => {
|
|
1842
|
+
/* @__PURE__ */ jsx("div", { className: "vk-a11y", role: "group", "aria-label": messages.mapLabel, onKeyDown, children: tooMany ? /* @__PURE__ */ jsx("button", { ref: chooseRef, type: "button", className: "vk-choose", "data-testid": "zoom-to-choose", onClick: zoomInToChoose, children: format(messages.zoomToChoose, { n: visibleNodes.length.toLocaleString() }) }) : visibleNodes.map((node) => {
|
|
1762
1843
|
const p = worldToScreen(camera, viewport, node);
|
|
1763
1844
|
const size = sizeOf(node.elementId);
|
|
1764
1845
|
return /* @__PURE__ */ jsx(
|
|
@@ -1779,6 +1860,7 @@ function VenueCanvas(props) {
|
|
|
1779
1860
|
node.id
|
|
1780
1861
|
);
|
|
1781
1862
|
}) }),
|
|
1863
|
+
wheelHint ? /* @__PURE__ */ jsx("p", { className: "vk-map-hint", role: "status", children: messages.wheelHint }) : null,
|
|
1782
1864
|
/* @__PURE__ */ jsxs("div", { className: "vk-zoom", children: [
|
|
1783
1865
|
/* @__PURE__ */ jsx("button", { type: "button", onClick: zoomButton(1.4), "aria-label": messages.zoomIn, children: "+" }),
|
|
1784
1866
|
/* @__PURE__ */ jsx("button", { type: "button", onClick: zoomButton(1 / 1.4), "aria-label": messages.zoomOut, children: "\u2212" })
|
|
@@ -1914,7 +1996,7 @@ function SeatMap(props) {
|
|
|
1914
1996
|
announce(`${unitName(unit, messages)}: ${added ? messages.selected : messages.free}`);
|
|
1915
1997
|
onSelectionChange(result.selection);
|
|
1916
1998
|
}, [unitById, focusRef, states, selection, maxSelection, messages, announce, onSelectionChange, switchTo]);
|
|
1917
|
-
const summary = selectionSummary(units, selection, messages);
|
|
1999
|
+
const summary = useMemo2(() => selectionSummary(units, selection, messages), [units, selection, messages]);
|
|
1918
2000
|
const focusColor = placeTypeColors.get(focusRef) ?? "var(--vk-unassigned)";
|
|
1919
2001
|
const focusType = props.placeTypes.find((p) => p.ref === focusRef);
|
|
1920
2002
|
const embedded = props.embedded === true;
|
|
@@ -1965,6 +2047,7 @@ function SeatMap(props) {
|
|
|
1965
2047
|
onTapEmpty,
|
|
1966
2048
|
placeTypePrices,
|
|
1967
2049
|
...props.height !== void 0 ? { height: props.height } : {},
|
|
2050
|
+
cooperative: embedded,
|
|
1968
2051
|
images,
|
|
1969
2052
|
...backgroundStatus ? { backgroundStatus } : {}
|
|
1970
2053
|
}
|
|
@@ -2133,6 +2216,7 @@ function VenueOverview(props) {
|
|
|
2133
2216
|
highlightRefs,
|
|
2134
2217
|
...props.height !== void 0 ? { height: props.height } : {},
|
|
2135
2218
|
ratio: contentRatio,
|
|
2219
|
+
cooperative: true,
|
|
2136
2220
|
images,
|
|
2137
2221
|
...backgroundStatus ? { backgroundStatus } : {}
|
|
2138
2222
|
}
|
|
@@ -2394,6 +2478,57 @@ function BackgroundControl(props) {
|
|
|
2394
2478
|
// ../react/src/designer/DesignerCanvas.tsx
|
|
2395
2479
|
import { forwardRef, useEffect as useEffect5, useImperativeHandle, useMemo as useMemo4, useRef as useRef5, useState as useState5 } from "react";
|
|
2396
2480
|
|
|
2481
|
+
// ../react/src/designer/drag-preview.ts
|
|
2482
|
+
function changedIds(preview) {
|
|
2483
|
+
return preview.kind === "move" ? [...preview.ids] : [preview.element.id];
|
|
2484
|
+
}
|
|
2485
|
+
function splitUnits(units, changed) {
|
|
2486
|
+
const still = [];
|
|
2487
|
+
const moving = [];
|
|
2488
|
+
for (const u of units) (changed.has(u.elementId) ? moving : still).push(u);
|
|
2489
|
+
return { changed, still, stillIndex: new SpatialIndex(still), moving, movingIndex: new SpatialIndex(moving) };
|
|
2490
|
+
}
|
|
2491
|
+
function boxesOf(layout) {
|
|
2492
|
+
const out = /* @__PURE__ */ new Map();
|
|
2493
|
+
for (const el of layout.elements) {
|
|
2494
|
+
const b = pieceBounds(el);
|
|
2495
|
+
if (b) out.set(el.id, b);
|
|
2496
|
+
}
|
|
2497
|
+
return out;
|
|
2498
|
+
}
|
|
2499
|
+
function shifted(el, dx, dy) {
|
|
2500
|
+
return { ...el, transform: { ...el.transform, x: el.transform.x + dx, y: el.transform.y + dy } };
|
|
2501
|
+
}
|
|
2502
|
+
function joined(still, moving, dx, dy) {
|
|
2503
|
+
return {
|
|
2504
|
+
queryRect: (q) => {
|
|
2505
|
+
const out = still.queryRect(q);
|
|
2506
|
+
for (const id of moving.queryRect({ minX: q.minX - dx, minY: q.minY - dy, maxX: q.maxX - dx, maxY: q.maxY - dy })) out.push(id);
|
|
2507
|
+
return out;
|
|
2508
|
+
}
|
|
2509
|
+
};
|
|
2510
|
+
}
|
|
2511
|
+
function previewFrame(base, split, baseBoxes, preview) {
|
|
2512
|
+
const boxes = new Map(baseBoxes);
|
|
2513
|
+
if (preview.kind === "move") {
|
|
2514
|
+
const { dx, dy } = preview;
|
|
2515
|
+
const layout2 = { ...base, elements: base.elements.map((el) => split.changed.has(el.id) ? shifted(el, dx, dy) : el) };
|
|
2516
|
+
for (const id of split.changed) {
|
|
2517
|
+
const b2 = baseBoxes.get(id);
|
|
2518
|
+
if (b2) boxes.set(id, shiftBox(b2, dx, dy));
|
|
2519
|
+
}
|
|
2520
|
+
const units = split.still.concat(split.moving.map((u) => ({ ...u, x: u.x + dx, y: u.y + dy })));
|
|
2521
|
+
return { layout: layout2, units, index: joined(split.stillIndex, split.movingIndex, dx, dy), boxes };
|
|
2522
|
+
}
|
|
2523
|
+
const { element } = preview;
|
|
2524
|
+
const layout = { ...base, elements: base.elements.map((el) => el.id === element.id ? element : el) };
|
|
2525
|
+
const own = expand({ ...base, elements: [element] });
|
|
2526
|
+
const b = pieceBounds(element);
|
|
2527
|
+
if (b) boxes.set(element.id, b);
|
|
2528
|
+
else boxes.delete(element.id);
|
|
2529
|
+
return { layout, units: split.still.concat(own), index: joined(split.stillIndex, new SpatialIndex(own), 0, 0), boxes };
|
|
2530
|
+
}
|
|
2531
|
+
|
|
2397
2532
|
// ../react/src/designer/sizing.ts
|
|
2398
2533
|
var SIZE_STEP = 0.1;
|
|
2399
2534
|
var KEY_RESIZE_STEP = 20;
|
|
@@ -2416,9 +2551,6 @@ var NO_STATES = /* @__PURE__ */ new Map();
|
|
|
2416
2551
|
var TICK_MS = 50;
|
|
2417
2552
|
var MAX_SEAT_TARGETS = 1e3;
|
|
2418
2553
|
var isScaled2 = (el) => el.type === "seatBlock" || el.type === "table";
|
|
2419
|
-
function withElement(layout, el) {
|
|
2420
|
-
return { ...layout, elements: layout.elements.map((e) => e.id === el.id ? el : e) };
|
|
2421
|
-
}
|
|
2422
2554
|
function union(boxes) {
|
|
2423
2555
|
if (boxes.length === 0) return null;
|
|
2424
2556
|
return boxes.reduce((a, b) => ({
|
|
@@ -2455,9 +2587,20 @@ function fullBlock(layout, id) {
|
|
|
2455
2587
|
}
|
|
2456
2588
|
var DesignerCanvas = forwardRef(function DesignerCanvas2({ designer, placeTypes, lockedUnitIds, messages, frameKey, onPieceTap, backgroundImage = null, compact = false, overlay, theme }, ref) {
|
|
2457
2589
|
const { ui } = designer;
|
|
2458
|
-
const [
|
|
2590
|
+
const [preview, setPreview] = useState5(null);
|
|
2459
2591
|
const resizingRef = useRef5(null);
|
|
2460
|
-
const
|
|
2592
|
+
const resizing = preview?.kind === "replace" ? preview.element : null;
|
|
2593
|
+
const base = designer.layout;
|
|
2594
|
+
const baseUnits = useMemo4(() => expand(base), [base]);
|
|
2595
|
+
const baseIndex = useMemo4(() => new SpatialIndex(baseUnits), [baseUnits]);
|
|
2596
|
+
const baseBoxes = useMemo4(() => boxesOf(base), [base]);
|
|
2597
|
+
const changedKey = preview ? changedIds(preview).join("\0") : "";
|
|
2598
|
+
const split = useMemo4(() => changedKey ? splitUnits(baseUnits, new Set(changedKey.split("\0"))) : null, [baseUnits, changedKey]);
|
|
2599
|
+
const view = useMemo4(
|
|
2600
|
+
() => preview && split ? previewFrame(base, split, baseBoxes, preview) : { layout: base, units: baseUnits, index: baseIndex, boxes: baseBoxes },
|
|
2601
|
+
[preview, split, base, baseUnits, baseIndex, baseBoxes]
|
|
2602
|
+
);
|
|
2603
|
+
const { layout, units, index, boxes } = view;
|
|
2461
2604
|
const stageRef = useRef5(null);
|
|
2462
2605
|
const canvasRef = useRef5(null);
|
|
2463
2606
|
const [viewport, setViewport] = useState5({ width: 0, height: 0 });
|
|
@@ -2480,8 +2623,6 @@ var DesignerCanvas = forwardRef(function DesignerCanvas2({ designer, placeTypes,
|
|
|
2480
2623
|
const spaceHeld = useRef5(false);
|
|
2481
2624
|
const [panReady, setPanReady] = useState5(false);
|
|
2482
2625
|
const marqueeArmed = useRef5(false);
|
|
2483
|
-
const units = useMemo4(() => expand(layout), [layout]);
|
|
2484
|
-
const index = useMemo4(() => new SpatialIndex(units), [units]);
|
|
2485
2626
|
const radii = useMemo4(() => unitRadii(layout), [layout]);
|
|
2486
2627
|
const bg = layout.meta.background;
|
|
2487
2628
|
const images = useMemo4(
|
|
@@ -2489,21 +2630,21 @@ var DesignerCanvas = forwardRef(function DesignerCanvas2({ designer, placeTypes,
|
|
|
2489
2630
|
[bg, backgroundImage]
|
|
2490
2631
|
);
|
|
2491
2632
|
const placeTypeColors = useMemo4(() => new Map(placeTypes.map((p) => [p.ref, p.color])), [placeTypes]);
|
|
2492
|
-
const seatEditUnits = useMemo4(() => fullBlock(
|
|
2633
|
+
const seatEditUnits = useMemo4(() => fullBlock(base, ui.seatEditId), [base, ui.seatEditId]);
|
|
2493
2634
|
const seatEditIndex = useMemo4(() => new SpatialIndex(seatEditUnits), [seatEditUnits]);
|
|
2494
2635
|
const seatEditById = useMemo4(() => new Map(seatEditUnits.map((u) => [u.id, u])), [seatEditUnits]);
|
|
2495
2636
|
const elementBoxes = useMemo4(
|
|
2496
2637
|
() => layout.elements.flatMap((el) => {
|
|
2497
|
-
const b =
|
|
2638
|
+
const b = boxes.get(el.id);
|
|
2498
2639
|
return b ? [{ el, b }] : [];
|
|
2499
2640
|
}),
|
|
2500
|
-
[layout]
|
|
2641
|
+
[layout, boxes]
|
|
2501
2642
|
);
|
|
2502
2643
|
const removed = useMemo4(() => {
|
|
2503
2644
|
if (seatEditUnits.length === 0) return /* @__PURE__ */ new Set();
|
|
2504
|
-
const present = new Set(
|
|
2645
|
+
const present = new Set(baseUnits.map((u) => u.id));
|
|
2505
2646
|
return new Set(seatEditUnits.filter((u) => !present.has(u.id)).map((u) => u.id));
|
|
2506
|
-
}, [seatEditUnits,
|
|
2647
|
+
}, [seatEditUnits, baseUnits]);
|
|
2507
2648
|
useEffect5(() => {
|
|
2508
2649
|
const el = stageRef.current;
|
|
2509
2650
|
if (!el) return;
|
|
@@ -2574,20 +2715,19 @@ var DesignerCanvas = forwardRef(function DesignerCanvas2({ designer, placeTypes,
|
|
|
2574
2715
|
if (bg && ui.backgroundEditing && !bg.locked) {
|
|
2575
2716
|
const a = worldToScreen(camera, viewport, { x: bg.x, y: bg.y });
|
|
2576
2717
|
const b = worldToScreen(camera, viewport, { x: bg.x + bg.width, y: bg.y + bg.height });
|
|
2577
|
-
const
|
|
2718
|
+
const up = lifted === BACKGROUND_ID;
|
|
2578
2719
|
ctx.save();
|
|
2579
|
-
if (
|
|
2720
|
+
if (up) {
|
|
2580
2721
|
ctx.shadowColor = "rgba(0,0,0,.35)";
|
|
2581
2722
|
ctx.shadowBlur = 12;
|
|
2582
2723
|
} else ctx.setLineDash([6, 4]);
|
|
2583
|
-
ctx.lineWidth =
|
|
2724
|
+
ctx.lineWidth = up ? 3 : 1.5;
|
|
2584
2725
|
ctx.strokeStyle = palette.selectedStroke;
|
|
2585
2726
|
ctx.strokeRect(a.x, a.y, b.x - a.x, b.y - a.y);
|
|
2586
2727
|
ctx.restore();
|
|
2587
2728
|
}
|
|
2588
2729
|
for (const id of ui.selection) {
|
|
2589
|
-
const
|
|
2590
|
-
const box = selected ? elementBounds(layout, selected) : null;
|
|
2730
|
+
const box = boxes.get(id);
|
|
2591
2731
|
if (!box) continue;
|
|
2592
2732
|
const a = worldToScreen(camera, viewport, { x: box.minX, y: box.minY });
|
|
2593
2733
|
const b = worldToScreen(camera, viewport, { x: box.maxX, y: box.maxY });
|
|
@@ -2612,12 +2752,11 @@ var DesignerCanvas = forwardRef(function DesignerCanvas2({ designer, placeTypes,
|
|
|
2612
2752
|
ctx.strokeRect(Math.min(a.x, b.x), Math.min(a.y, b.y), Math.abs(b.x - a.x), Math.abs(b.y - a.y));
|
|
2613
2753
|
ctx.restore();
|
|
2614
2754
|
}
|
|
2615
|
-
const
|
|
2616
|
-
|
|
2617
|
-
if (upBox) {
|
|
2755
|
+
const upBox = lifted ? boxes.get(lifted) : void 0;
|
|
2756
|
+
if (lifted && upBox) {
|
|
2618
2757
|
const a = worldToScreen(camera, viewport, { x: upBox.minX, y: upBox.minY });
|
|
2619
2758
|
const b = worldToScreen(camera, viewport, { x: upBox.maxX, y: upBox.maxY });
|
|
2620
|
-
const pad = 12 + (radii.get(
|
|
2759
|
+
const pad = 12 + (radii.get(lifted) ?? 0) * camera.zoom;
|
|
2621
2760
|
ctx.save();
|
|
2622
2761
|
ctx.shadowColor = "rgba(0,0,0,.35)";
|
|
2623
2762
|
ctx.shadowBlur = 12;
|
|
@@ -2640,7 +2779,7 @@ var DesignerCanvas = forwardRef(function DesignerCanvas2({ designer, placeTypes,
|
|
|
2640
2779
|
}
|
|
2641
2780
|
ctx.setLineDash([]);
|
|
2642
2781
|
}
|
|
2643
|
-
}, [scene, camera, viewport, dpr, images, bg, ui.backgroundEditing, ui.selection, ui.seatEditId,
|
|
2782
|
+
}, [scene, camera, viewport, dpr, images, bg, ui.backgroundEditing, ui.selection, ui.seatEditId, boxes, radii, palette, seatEditUnits, removed, lifted, hints, marquee]);
|
|
2644
2783
|
useImperativeHandle(ref, () => ({
|
|
2645
2784
|
clientToWorld: (clientX, clientY) => {
|
|
2646
2785
|
const r = stageRef.current?.getBoundingClientRect();
|
|
@@ -2679,9 +2818,12 @@ var DesignerCanvas = forwardRef(function DesignerCanvas2({ designer, placeTypes,
|
|
|
2679
2818
|
} else if (fx.type === "moveBy") {
|
|
2680
2819
|
moveDragged(fx.elementId, fx.dx, fx.dy, fx.key, zoom);
|
|
2681
2820
|
} else if (fx.type === "moveEnd") {
|
|
2682
|
-
const
|
|
2821
|
+
const done = drag.current;
|
|
2822
|
+
const group = done && done.ids.length > 1;
|
|
2683
2823
|
drag.current = null;
|
|
2684
2824
|
setHints(null);
|
|
2825
|
+
setPreview(null);
|
|
2826
|
+
if (done && (done.applied.x !== 0 || done.applied.y !== 0)) d.moveMany(done.ids, done.applied.x, done.applied.y);
|
|
2685
2827
|
if (!group) d.dispatchUi({ type: "select", id: fx.elementId });
|
|
2686
2828
|
} else if (fx.type === "marquee") {
|
|
2687
2829
|
setMarquee({ from: fx.from, to: fx.to });
|
|
@@ -2699,12 +2841,12 @@ var DesignerCanvas = forwardRef(function DesignerCanvas2({ designer, placeTypes,
|
|
|
2699
2841
|
const start = d.layout.elements.find((e) => e.id === fx.elementId);
|
|
2700
2842
|
if (!start) return;
|
|
2701
2843
|
resizingRef.current = snappedResize(start, fx.corner, fx.from, fx.to, zoom);
|
|
2702
|
-
|
|
2844
|
+
setPreview({ kind: "replace", element: resizingRef.current });
|
|
2703
2845
|
} else if (fx.type === "resizeEnd" || fx.type === "resizeCancel") {
|
|
2704
2846
|
const done = resizingRef.current;
|
|
2705
2847
|
resizingRef.current = null;
|
|
2706
2848
|
resizeOthers.current = null;
|
|
2707
|
-
|
|
2849
|
+
setPreview(null);
|
|
2708
2850
|
setHints(null);
|
|
2709
2851
|
const start = d.layout.elements.find((e) => e.id === fx.elementId);
|
|
2710
2852
|
if (fx.type === "resizeEnd" && done && start && done !== start) d.run({ type: "replaceElement", element: done });
|
|
@@ -2737,9 +2879,10 @@ var DesignerCanvas = forwardRef(function DesignerCanvas2({ designer, placeTypes,
|
|
|
2737
2879
|
current.raw = { x: current.raw.x + dx, y: current.raw.y + dy };
|
|
2738
2880
|
const snap = altHeld.current ? null : snapMove(shiftBox(current.start, current.raw.x, current.raw.y), current.others, SNAP_PX / zoom, { sheet: sheetBox(d.layout) });
|
|
2739
2881
|
const target = { x: current.raw.x + (snap?.dx ?? 0), y: current.raw.y + (snap?.dy ?? 0) };
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2882
|
+
if (target.x !== current.applied.x || target.y !== current.applied.y) {
|
|
2883
|
+
current.applied = target;
|
|
2884
|
+
setPreview({ kind: "move", ids: current.ids, dx: target.x, dy: target.y });
|
|
2885
|
+
}
|
|
2743
2886
|
setHints(snap && (snap.guides.length > 0 || snap.gaps.length > 0) ? { guides: snap.guides, gaps: snap.gaps, matches: [] } : null);
|
|
2744
2887
|
};
|
|
2745
2888
|
const snappedResize = (start, corner, from, to, zoom) => {
|
|
@@ -2931,17 +3074,16 @@ var DesignerCanvas = forwardRef(function DesignerCanvas2({ designer, placeTypes,
|
|
|
2931
3074
|
const selectedEl = ui.selectedId ? layout.elements.find((e) => e.id === ui.selectedId) : void 0;
|
|
2932
3075
|
const selectedBox = useMemo4(() => {
|
|
2933
3076
|
if (viewport.width === 0) return null;
|
|
2934
|
-
const
|
|
2935
|
-
const
|
|
2936
|
-
const b = el ? elementBounds(layout, el) : null;
|
|
3077
|
+
const picked2 = ui.selection.flatMap((id) => {
|
|
3078
|
+
const b = boxes.get(id);
|
|
2937
3079
|
if (!b) return [];
|
|
2938
3080
|
const a = worldToScreen(camera, viewport, { x: b.minX, y: b.minY });
|
|
2939
3081
|
const z = worldToScreen(camera, viewport, { x: b.maxX, y: b.maxY });
|
|
2940
3082
|
const pad = 8 + (radii.get(id) ?? 0) * camera.zoom;
|
|
2941
3083
|
return [{ minX: a.x - pad, minY: a.y - pad, maxX: z.x + pad, maxY: z.y + pad }];
|
|
2942
3084
|
});
|
|
2943
|
-
return union(
|
|
2944
|
-
}, [ui.selection,
|
|
3085
|
+
return union(picked2);
|
|
3086
|
+
}, [ui.selection, boxes, camera, viewport, radii]);
|
|
2945
3087
|
return /* @__PURE__ */ jsxs5(
|
|
2946
3088
|
"div",
|
|
2947
3089
|
{
|
|
@@ -3160,6 +3302,9 @@ function violationText(v, m) {
|
|
|
3160
3302
|
return v.reason === "table" ? format(m.rejectTable, { table: v.table }) : format(m.rejectRow, { row: v.row });
|
|
3161
3303
|
}
|
|
3162
3304
|
function rejectionText(r, m) {
|
|
3305
|
+
if (r.invalid !== void 0) {
|
|
3306
|
+
return /máximo de unidades vendibles/.test(r.invalid) ? m.rejectTooManyUnits : m.rejectInvalid;
|
|
3307
|
+
}
|
|
3163
3308
|
const [over, ...moreOver] = r.capacity ?? [];
|
|
3164
3309
|
if (over) {
|
|
3165
3310
|
const head2 = format(m.rejectCapacity, { type: over.label, capacity: over.capacity, placed: over.placed });
|
|
@@ -3176,12 +3321,12 @@ import { useEffect as useEffect6, useLayoutEffect, useRef as useRef6, useState a
|
|
|
3176
3321
|
|
|
3177
3322
|
// ../react/src/designer/guide.ts
|
|
3178
3323
|
var overlaps = (a, b) => a.minX < b.maxX && a.maxX > b.minX && a.minY < b.maxY && a.maxY > b.minY;
|
|
3179
|
-
var
|
|
3324
|
+
var shifted2 = (b, dx, dy) => ({ minX: b.minX + dx, minY: b.minY + dy, maxX: b.maxX + dx, maxY: b.maxY + dy });
|
|
3180
3325
|
function freeSpot(box, occupied, gap = 24, rings = 12) {
|
|
3181
3326
|
const sx = box.maxX - box.minX + gap;
|
|
3182
3327
|
const sy = box.maxY - box.minY + gap;
|
|
3183
3328
|
const padded = occupied.map((o) => ({ minX: o.minX - gap / 2, minY: o.minY - gap / 2, maxX: o.maxX + gap / 2, maxY: o.maxY + gap / 2 }));
|
|
3184
|
-
const free = (dx, dy) => !padded.some((o) => overlaps(
|
|
3329
|
+
const free = (dx, dy) => !padded.some((o) => overlaps(shifted2(box, dx, dy), o));
|
|
3185
3330
|
if (free(0, 0)) return { dx: 0, dy: 0 };
|
|
3186
3331
|
const dirs = [[0, 1], [1, 0], [0, -1], [-1, 0], [1, 1], [-1, 1], [1, -1], [-1, -1]];
|
|
3187
3332
|
for (let k = 1; k <= rings; k++) {
|
|
@@ -3851,6 +3996,8 @@ var designerEs = {
|
|
|
3851
3996
|
trimToCapacityLabel: "Sacar los {over} lugares que sobran de {name}",
|
|
3852
3997
|
trimPartial: "Quedan {n} de m\xE1s que no se pueden sacar: ya est\xE1n vendidos o reservados.",
|
|
3853
3998
|
rejectCapacity: "{type} tiene {capacity} lugares y ya ubicaste {placed}.",
|
|
3999
|
+
rejectInvalid: "No se pudo hacer ese cambio: la pieza quedar\xEDa demasiado grande o fuera del plano.",
|
|
4000
|
+
rejectTooManyUnits: "No se pudo hacer ese cambio: un plano puede tener hasta 100.000 lugares.",
|
|
3854
4001
|
zonesTitle: "Tus entradas generales",
|
|
3855
4002
|
zonesHint: "Si quer\xE9s, marc\xE1 en el plano d\xF3nde queda cada una. Quien compra la toca en el mapa.",
|
|
3856
4003
|
acceptsZone: "Entrada general",
|
|
@@ -4069,6 +4216,8 @@ var designerEn = {
|
|
|
4069
4216
|
trimToCapacityLabel: "Remove the {over} extra spots of {name}",
|
|
4070
4217
|
trimPartial: "{n} extra spots can't be removed: they are already sold or held.",
|
|
4071
4218
|
rejectCapacity: "{type} has {capacity} spots and you've already placed {placed}.",
|
|
4219
|
+
rejectInvalid: "That change couldn't be made: the piece would be too big or off the plan.",
|
|
4220
|
+
rejectTooManyUnits: "That change couldn't be made: a plan can have up to 100,000 spots.",
|
|
4072
4221
|
zonesTitle: "Your general admission tickets",
|
|
4073
4222
|
zonesHint: "If you want, mark on the plan where each one is. Buyers tap it on the map.",
|
|
4074
4223
|
acceptsZone: "General admission",
|
|
@@ -5273,7 +5422,8 @@ function elementPrefix(el) {
|
|
|
5273
5422
|
return el.type === "seatBlock" ? "b" : el.type === "table" ? "m" : el.type === "zone" ? "z" : "r";
|
|
5274
5423
|
}
|
|
5275
5424
|
function useDesigner({ initial, lockedUnitIds, onChange, placeTypes }) {
|
|
5276
|
-
const
|
|
5425
|
+
const [history] = useState10(() => new History(initial));
|
|
5426
|
+
const historyRef = useRef9(history);
|
|
5277
5427
|
const [layout, setLayout] = useState10(initial);
|
|
5278
5428
|
const [rejection, setRejectionState] = useState10(null);
|
|
5279
5429
|
const [rejectionSeq, setRejectionSeq] = useState10(0);
|
|
@@ -5300,10 +5450,10 @@ function useDesigner({ initial, lockedUnitIds, onChange, placeTypes }) {
|
|
|
5300
5450
|
const previous = seenTypes.current.list;
|
|
5301
5451
|
const next = placeTypesRef.current;
|
|
5302
5452
|
seenTypes.current = { key: typesKey, list: next };
|
|
5303
|
-
const
|
|
5304
|
-
const before =
|
|
5305
|
-
|
|
5306
|
-
if (
|
|
5453
|
+
const history2 = historyRef.current;
|
|
5454
|
+
const before = history2.present;
|
|
5455
|
+
history2.rewrite((l) => syncPlaceTypes(l, previous, next));
|
|
5456
|
+
if (history2.present !== before) commit(history2.present);
|
|
5307
5457
|
}, [typesKey, commit]);
|
|
5308
5458
|
const run = useCallback3(
|
|
5309
5459
|
(command, key) => {
|
|
@@ -5311,20 +5461,22 @@ function useDesigner({ initial, lockedUnitIds, onChange, placeTypes }) {
|
|
|
5311
5461
|
let candidate;
|
|
5312
5462
|
try {
|
|
5313
5463
|
candidate = applyCommand(before, command);
|
|
5314
|
-
} catch {
|
|
5464
|
+
} catch (error) {
|
|
5465
|
+
setRejection({ violations: [], invalid: error instanceof Error ? error.message : String(error) });
|
|
5315
5466
|
return false;
|
|
5316
5467
|
}
|
|
5317
|
-
const
|
|
5468
|
+
const moveOnly = keepsCount(command);
|
|
5469
|
+
const violations = moveOnly ? [] : findLockViolations(before, candidate, locked);
|
|
5318
5470
|
if (violations.length > 0) {
|
|
5319
5471
|
setRejection({ violations });
|
|
5320
5472
|
return false;
|
|
5321
5473
|
}
|
|
5322
|
-
const capacity =
|
|
5474
|
+
const capacity = moveOnly ? [] : capacityRejections(before, candidate, placeTypesRef.current);
|
|
5323
5475
|
if (capacity.length > 0) {
|
|
5324
5476
|
setRejection({ violations: [], capacity });
|
|
5325
5477
|
return false;
|
|
5326
5478
|
}
|
|
5327
|
-
commit(historyRef.current.
|
|
5479
|
+
commit(historyRef.current.commit(candidate, key));
|
|
5328
5480
|
return true;
|
|
5329
5481
|
},
|
|
5330
5482
|
[locked, commit, setRejection]
|
|
@@ -5946,7 +6098,7 @@ function VenueDesigner(props) {
|
|
|
5946
6098
|
}
|
|
5947
6099
|
|
|
5948
6100
|
// ../react/src/index.ts
|
|
5949
|
-
var VERSION = "0.10.
|
|
6101
|
+
var VERSION = "0.10.2";
|
|
5950
6102
|
export {
|
|
5951
6103
|
DESIGNER_CSS,
|
|
5952
6104
|
PICKER_CSS,
|
package/package.json
CHANGED