@ericchen1990/pano-view 3.8.0 → 3.9.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.
- package/README.md +675 -71
- package/README.zh-CN.md +558 -42
- package/dist/data.cjs +19 -0
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.mts +17 -1
- package/dist/data.d.ts +17 -1
- package/dist/data.mjs +19 -0
- package/dist/data.mjs.map +1 -1
- package/dist/index.cjs +1262 -159
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +144 -3
- package/dist/index.d.ts +144 -3
- package/dist/index.mjs +1281 -172
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +274 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -18410,8 +18410,916 @@ var WebVR = forwardRef4(function WebVR2({
|
|
|
18410
18410
|
] });
|
|
18411
18411
|
});
|
|
18412
18412
|
|
|
18413
|
+
// src/pano-scene-menu.tsx
|
|
18414
|
+
import {
|
|
18415
|
+
useCallback as useCallback11,
|
|
18416
|
+
useEffect as useEffect41,
|
|
18417
|
+
useId as useId3,
|
|
18418
|
+
useLayoutEffect as useLayoutEffect9,
|
|
18419
|
+
useMemo as useMemo27,
|
|
18420
|
+
useRef as useRef40,
|
|
18421
|
+
useState as useState25
|
|
18422
|
+
} from "react";
|
|
18423
|
+
|
|
18424
|
+
// src/drag-motion.ts
|
|
18425
|
+
var DRAG_INERTIA_DAMPING = 8;
|
|
18426
|
+
var DRAG_FRICTION_STOP = 24;
|
|
18427
|
+
var DRAG_SPRING_STRENGTH = 28;
|
|
18428
|
+
var DRAG_RUBBER_CONSTANT = 0.55;
|
|
18429
|
+
var DRAG_SPRING_SETTLE_DISTANCE = 0.5;
|
|
18430
|
+
var DRAG_SPRING_SETTLE_VELOCITY = 12;
|
|
18431
|
+
function resolveDragMotion(motion) {
|
|
18432
|
+
if (motion === false) {
|
|
18433
|
+
return { inertia: false, bounce: false };
|
|
18434
|
+
}
|
|
18435
|
+
return {
|
|
18436
|
+
inertia: motion?.inertia !== false,
|
|
18437
|
+
bounce: motion?.bounce !== false
|
|
18438
|
+
};
|
|
18439
|
+
}
|
|
18440
|
+
function clampAxis(value, min, max) {
|
|
18441
|
+
if (max < min) return min;
|
|
18442
|
+
return Math.min(max, Math.max(min, value));
|
|
18443
|
+
}
|
|
18444
|
+
function constrainDragPosition(raw, min, max, dimension, bounce) {
|
|
18445
|
+
if (!(Number.isFinite(raw) && Number.isFinite(min) && Number.isFinite(max))) {
|
|
18446
|
+
return 0;
|
|
18447
|
+
}
|
|
18448
|
+
if (raw >= min && raw <= max) {
|
|
18449
|
+
return raw;
|
|
18450
|
+
}
|
|
18451
|
+
if (!bounce) {
|
|
18452
|
+
return clampAxis(raw, min, max);
|
|
18453
|
+
}
|
|
18454
|
+
const size = Math.max(1, Math.abs(dimension) || 1);
|
|
18455
|
+
if (raw < min) {
|
|
18456
|
+
const overshoot2 = min - raw;
|
|
18457
|
+
return min - rubberBandDistance(overshoot2, size);
|
|
18458
|
+
}
|
|
18459
|
+
const overshoot = raw - max;
|
|
18460
|
+
return max + rubberBandDistance(overshoot, size);
|
|
18461
|
+
}
|
|
18462
|
+
function rubberBandDistance(overshoot, dimension, constant = DRAG_RUBBER_CONSTANT) {
|
|
18463
|
+
if (!(overshoot > 0)) return 0;
|
|
18464
|
+
const size = Math.max(1, Math.abs(dimension) || 1);
|
|
18465
|
+
return size * overshoot / (size + overshoot * constant);
|
|
18466
|
+
}
|
|
18467
|
+
function velocityFromSamples(samples, now) {
|
|
18468
|
+
if (samples.length < 2) return 0;
|
|
18469
|
+
const windowMs = 100;
|
|
18470
|
+
let oldest = samples[0];
|
|
18471
|
+
const newest = samples[samples.length - 1];
|
|
18472
|
+
const referenceTime = now ?? newest.t;
|
|
18473
|
+
for (let i = samples.length - 2; i >= 0; i -= 1) {
|
|
18474
|
+
const sample = samples[i];
|
|
18475
|
+
if (referenceTime - sample.t > windowMs) break;
|
|
18476
|
+
oldest = sample;
|
|
18477
|
+
}
|
|
18478
|
+
const dt = (newest.t - oldest.t) / 1e3;
|
|
18479
|
+
if (!(dt >= 1e-3)) return 0;
|
|
18480
|
+
return (newest.position - oldest.position) / dt;
|
|
18481
|
+
}
|
|
18482
|
+
function integrateAxis(state, deltaSeconds, options) {
|
|
18483
|
+
const dt = Math.max(0, deltaSeconds);
|
|
18484
|
+
if (!(dt > 0)) {
|
|
18485
|
+
return { ...state, settled: isAxisSettled(state, options) };
|
|
18486
|
+
}
|
|
18487
|
+
const damping = options.damping ?? DRAG_INERTIA_DAMPING;
|
|
18488
|
+
const frictionStop = options.frictionStop ?? DRAG_FRICTION_STOP;
|
|
18489
|
+
const spring = options.spring ?? DRAG_SPRING_STRENGTH;
|
|
18490
|
+
const { min, max } = options;
|
|
18491
|
+
let { position, velocity } = state;
|
|
18492
|
+
const pastMin = position < min;
|
|
18493
|
+
const pastMax = position > max;
|
|
18494
|
+
if (pastMin || pastMax) {
|
|
18495
|
+
if (!options.bounce) {
|
|
18496
|
+
position = clampAxis(position, min, max);
|
|
18497
|
+
return { position, velocity: 0, settled: true };
|
|
18498
|
+
}
|
|
18499
|
+
const edge = pastMin ? min : max;
|
|
18500
|
+
if (pastMin && velocity < 0) velocity = 0;
|
|
18501
|
+
if (pastMax && velocity > 0) velocity = 0;
|
|
18502
|
+
const displacement = edge - position;
|
|
18503
|
+
velocity += displacement * spring * dt;
|
|
18504
|
+
const decay = Math.exp(-damping * dt);
|
|
18505
|
+
velocity *= decay;
|
|
18506
|
+
position += velocity * dt;
|
|
18507
|
+
if (pastMin && position > min) {
|
|
18508
|
+
position = min;
|
|
18509
|
+
velocity = 0;
|
|
18510
|
+
}
|
|
18511
|
+
if (pastMax && position < max) {
|
|
18512
|
+
position = max;
|
|
18513
|
+
velocity = 0;
|
|
18514
|
+
}
|
|
18515
|
+
const settled = isAxisSettled({ position, velocity }, options);
|
|
18516
|
+
if (settled) {
|
|
18517
|
+
return { position: clampAxis(position, min, max), velocity: 0, settled: true };
|
|
18518
|
+
}
|
|
18519
|
+
return { position, velocity, settled: false };
|
|
18520
|
+
}
|
|
18521
|
+
if (!options.inertia || Math.abs(velocity) < frictionStop) {
|
|
18522
|
+
return { position, velocity: 0, settled: true };
|
|
18523
|
+
}
|
|
18524
|
+
position += velocity * dt;
|
|
18525
|
+
velocity *= Math.exp(-damping * dt);
|
|
18526
|
+
if (position < min || position > max) {
|
|
18527
|
+
if (!options.bounce) {
|
|
18528
|
+
position = clampAxis(position, min, max);
|
|
18529
|
+
return { position, velocity: 0, settled: true };
|
|
18530
|
+
}
|
|
18531
|
+
if (Math.abs(velocity) < frictionStop) {
|
|
18532
|
+
velocity = 0;
|
|
18533
|
+
}
|
|
18534
|
+
return { position, velocity, settled: false };
|
|
18535
|
+
}
|
|
18536
|
+
if (Math.abs(velocity) < frictionStop) {
|
|
18537
|
+
return { position, velocity: 0, settled: true };
|
|
18538
|
+
}
|
|
18539
|
+
return { position, velocity, settled: false };
|
|
18540
|
+
}
|
|
18541
|
+
function isAxisSettled(state, options) {
|
|
18542
|
+
const frictionStop = options.frictionStop ?? DRAG_FRICTION_STOP;
|
|
18543
|
+
const inside = state.position >= options.min - DRAG_SPRING_SETTLE_DISTANCE && state.position <= options.max + DRAG_SPRING_SETTLE_DISTANCE;
|
|
18544
|
+
const slow = Math.abs(state.velocity) < (options.frictionStop ?? DRAG_SPRING_SETTLE_VELOCITY);
|
|
18545
|
+
if (!inside) return false;
|
|
18546
|
+
return slow || Math.abs(state.velocity) < frictionStop;
|
|
18547
|
+
}
|
|
18548
|
+
function pushSample(samples, sample, maxCount = 8) {
|
|
18549
|
+
const next = samples.length >= maxCount ? samples.slice(samples.length - maxCount + 1) : samples.slice();
|
|
18550
|
+
next.push(sample);
|
|
18551
|
+
return next;
|
|
18552
|
+
}
|
|
18553
|
+
|
|
18554
|
+
// src/pano-scene-menu.tsx
|
|
18555
|
+
import { jsx as jsx41, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
18556
|
+
var SCENE_MENU_DRAG_THRESHOLD_PX = 6;
|
|
18557
|
+
var DEFAULT_PANO_SCENE_MENU_APPEARANCE = {
|
|
18558
|
+
background: "rgba(16, 16, 16, 0.72)",
|
|
18559
|
+
padding: "8px 10px",
|
|
18560
|
+
itemWidth: 128,
|
|
18561
|
+
itemHeight: 80,
|
|
18562
|
+
gap: 8,
|
|
18563
|
+
borderRadius: 8,
|
|
18564
|
+
selectionColor: "#ffffff",
|
|
18565
|
+
selectionWidth: 2,
|
|
18566
|
+
labelBackground: "rgba(0, 0, 0, 0.55)",
|
|
18567
|
+
labelColor: "#ffffff",
|
|
18568
|
+
labelAlign: "start",
|
|
18569
|
+
fontSize: 12,
|
|
18570
|
+
controlColor: "#ffffff",
|
|
18571
|
+
controlBackground: "rgba(255, 255, 255, 0.12)"
|
|
18572
|
+
};
|
|
18573
|
+
var DEFAULT_INSET = 12;
|
|
18574
|
+
function cssLength(value) {
|
|
18575
|
+
return typeof value === "number" ? `${value}px` : value;
|
|
18576
|
+
}
|
|
18577
|
+
function resolveAppearance2(appearance) {
|
|
18578
|
+
return {
|
|
18579
|
+
...DEFAULT_PANO_SCENE_MENU_APPEARANCE,
|
|
18580
|
+
...appearance
|
|
18581
|
+
};
|
|
18582
|
+
}
|
|
18583
|
+
function resolveInset(inset) {
|
|
18584
|
+
if (inset === void 0) {
|
|
18585
|
+
const value = cssLength(DEFAULT_INSET);
|
|
18586
|
+
return { top: value, right: value, bottom: value, left: value };
|
|
18587
|
+
}
|
|
18588
|
+
if (typeof inset === "number" || typeof inset === "string") {
|
|
18589
|
+
const value = cssLength(inset);
|
|
18590
|
+
return { top: value, right: value, bottom: value, left: value };
|
|
18591
|
+
}
|
|
18592
|
+
return {
|
|
18593
|
+
top: cssLength(inset.top ?? DEFAULT_INSET),
|
|
18594
|
+
right: cssLength(inset.right ?? DEFAULT_INSET),
|
|
18595
|
+
bottom: cssLength(inset.bottom ?? DEFAULT_INSET),
|
|
18596
|
+
left: cssLength(inset.left ?? DEFAULT_INSET)
|
|
18597
|
+
};
|
|
18598
|
+
}
|
|
18599
|
+
function itemLabel(item) {
|
|
18600
|
+
return item.title?.trim() || item.id;
|
|
18601
|
+
}
|
|
18602
|
+
function isHorizontal(placement) {
|
|
18603
|
+
return placement === "top" || placement === "bottom";
|
|
18604
|
+
}
|
|
18605
|
+
var CHEVRON_PATHS = {
|
|
18606
|
+
// Keep glyphs optically centered in the 16×16 viewBox.
|
|
18607
|
+
up: "M3 11l5-6 5 6",
|
|
18608
|
+
down: "M3 5l5 6 5-6",
|
|
18609
|
+
left: "M11 3 5 8l6 5",
|
|
18610
|
+
right: "M5 3l6 5-6 5"
|
|
18611
|
+
};
|
|
18612
|
+
function arrowChevron(direction, orientation2) {
|
|
18613
|
+
if (direction === "prev") {
|
|
18614
|
+
return orientation2 === "horizontal" ? "left" : "up";
|
|
18615
|
+
}
|
|
18616
|
+
return orientation2 === "horizontal" ? "right" : "down";
|
|
18617
|
+
}
|
|
18618
|
+
function toggleChevron(placement, expanded) {
|
|
18619
|
+
switch (placement) {
|
|
18620
|
+
case "bottom":
|
|
18621
|
+
return expanded ? "down" : "up";
|
|
18622
|
+
case "top":
|
|
18623
|
+
return expanded ? "up" : "down";
|
|
18624
|
+
case "left":
|
|
18625
|
+
return expanded ? "left" : "right";
|
|
18626
|
+
case "right":
|
|
18627
|
+
return expanded ? "right" : "left";
|
|
18628
|
+
default: {
|
|
18629
|
+
const exhaustive = placement;
|
|
18630
|
+
void exhaustive;
|
|
18631
|
+
return "down";
|
|
18632
|
+
}
|
|
18633
|
+
}
|
|
18634
|
+
}
|
|
18635
|
+
function dockInset(placement, inset) {
|
|
18636
|
+
switch (placement) {
|
|
18637
|
+
case "top":
|
|
18638
|
+
return inset.top;
|
|
18639
|
+
case "bottom":
|
|
18640
|
+
return inset.bottom;
|
|
18641
|
+
case "left":
|
|
18642
|
+
return inset.left;
|
|
18643
|
+
case "right":
|
|
18644
|
+
return inset.right;
|
|
18645
|
+
default: {
|
|
18646
|
+
const exhaustive = placement;
|
|
18647
|
+
void exhaustive;
|
|
18648
|
+
return inset.bottom;
|
|
18649
|
+
}
|
|
18650
|
+
}
|
|
18651
|
+
}
|
|
18652
|
+
function Chevron({ arrow }) {
|
|
18653
|
+
return /* @__PURE__ */ jsx41(
|
|
18654
|
+
"svg",
|
|
18655
|
+
{
|
|
18656
|
+
"aria-hidden": true,
|
|
18657
|
+
fill: "none",
|
|
18658
|
+
height: "16",
|
|
18659
|
+
stroke: "currentColor",
|
|
18660
|
+
strokeLinecap: "round",
|
|
18661
|
+
strokeLinejoin: "round",
|
|
18662
|
+
strokeWidth: "1.75",
|
|
18663
|
+
viewBox: "0 0 16 16",
|
|
18664
|
+
width: "16",
|
|
18665
|
+
children: /* @__PURE__ */ jsx41("path", { d: CHEVRON_PATHS[arrow] })
|
|
18666
|
+
}
|
|
18667
|
+
);
|
|
18668
|
+
}
|
|
18669
|
+
function ControlButton({
|
|
18670
|
+
className,
|
|
18671
|
+
disabled,
|
|
18672
|
+
label,
|
|
18673
|
+
onClick,
|
|
18674
|
+
children
|
|
18675
|
+
}) {
|
|
18676
|
+
return /* @__PURE__ */ jsx41(
|
|
18677
|
+
"button",
|
|
18678
|
+
{
|
|
18679
|
+
"aria-label": label,
|
|
18680
|
+
className: cn("pano-scene-menu-control", className),
|
|
18681
|
+
disabled,
|
|
18682
|
+
onClick,
|
|
18683
|
+
onPointerDown: (event) => {
|
|
18684
|
+
event.stopPropagation();
|
|
18685
|
+
},
|
|
18686
|
+
title: label,
|
|
18687
|
+
type: "button",
|
|
18688
|
+
children
|
|
18689
|
+
}
|
|
18690
|
+
);
|
|
18691
|
+
}
|
|
18692
|
+
function horizontalAlignStyle(align, inset, widthValue) {
|
|
18693
|
+
const left = `calc(${inset.left} + var(--pano-safe-left))`;
|
|
18694
|
+
const right = `calc(${inset.right} + var(--pano-safe-right))`;
|
|
18695
|
+
if (!widthValue) {
|
|
18696
|
+
return { left, right, width: void 0, marginInline: void 0 };
|
|
18697
|
+
}
|
|
18698
|
+
switch (align) {
|
|
18699
|
+
case "start":
|
|
18700
|
+
return { left, right: "auto", width: widthValue, marginInline: void 0 };
|
|
18701
|
+
case "end":
|
|
18702
|
+
return { left: "auto", right, width: widthValue, marginInline: void 0 };
|
|
18703
|
+
case "center":
|
|
18704
|
+
return { left, right, width: widthValue, marginInline: "auto" };
|
|
18705
|
+
default: {
|
|
18706
|
+
const exhaustive = align;
|
|
18707
|
+
void exhaustive;
|
|
18708
|
+
return { left, right, width: widthValue, marginInline: "auto" };
|
|
18709
|
+
}
|
|
18710
|
+
}
|
|
18711
|
+
}
|
|
18712
|
+
function verticalAlignStyle(align, inset, heightValue) {
|
|
18713
|
+
const top = `calc(${inset.top} + var(--pano-safe-top))`;
|
|
18714
|
+
const bottom = `calc(${inset.bottom} + var(--pano-safe-bottom))`;
|
|
18715
|
+
if (!heightValue) {
|
|
18716
|
+
return { top, bottom, height: void 0, marginBlock: void 0 };
|
|
18717
|
+
}
|
|
18718
|
+
switch (align) {
|
|
18719
|
+
case "start":
|
|
18720
|
+
return { top, bottom: "auto", height: heightValue, marginBlock: void 0 };
|
|
18721
|
+
case "end":
|
|
18722
|
+
return { top: "auto", bottom, height: heightValue, marginBlock: void 0 };
|
|
18723
|
+
case "center":
|
|
18724
|
+
return { top, bottom, height: heightValue, marginBlock: "auto" };
|
|
18725
|
+
default: {
|
|
18726
|
+
const exhaustive = align;
|
|
18727
|
+
void exhaustive;
|
|
18728
|
+
return { top, bottom, height: heightValue, marginBlock: "auto" };
|
|
18729
|
+
}
|
|
18730
|
+
}
|
|
18731
|
+
}
|
|
18732
|
+
function placementBoxStyle(placement, inset, width, height, align) {
|
|
18733
|
+
const widthValue = width === void 0 ? void 0 : cssLength(width);
|
|
18734
|
+
const heightValue = height === void 0 ? void 0 : cssLength(height);
|
|
18735
|
+
const maxWidth = `calc(100% - ${inset.left} - ${inset.right} - var(--pano-safe-left) - var(--pano-safe-right))`;
|
|
18736
|
+
const maxHeight = `calc(100% - ${inset.top} - ${inset.bottom} - var(--pano-safe-top) - var(--pano-safe-bottom))`;
|
|
18737
|
+
switch (placement) {
|
|
18738
|
+
case "top":
|
|
18739
|
+
return {
|
|
18740
|
+
...horizontalAlignStyle(align, inset, widthValue),
|
|
18741
|
+
top: `calc(${inset.top} + var(--pano-safe-top))`,
|
|
18742
|
+
bottom: "auto",
|
|
18743
|
+
maxWidth,
|
|
18744
|
+
height: heightValue,
|
|
18745
|
+
maxHeight
|
|
18746
|
+
};
|
|
18747
|
+
case "bottom":
|
|
18748
|
+
return {
|
|
18749
|
+
...horizontalAlignStyle(align, inset, widthValue),
|
|
18750
|
+
top: "auto",
|
|
18751
|
+
bottom: `calc(${inset.bottom} + var(--pano-safe-bottom))`,
|
|
18752
|
+
maxWidth,
|
|
18753
|
+
height: heightValue,
|
|
18754
|
+
maxHeight
|
|
18755
|
+
};
|
|
18756
|
+
case "left":
|
|
18757
|
+
return {
|
|
18758
|
+
...verticalAlignStyle(align, inset, heightValue),
|
|
18759
|
+
right: "auto",
|
|
18760
|
+
left: `calc(${inset.left} + var(--pano-safe-left))`,
|
|
18761
|
+
width: widthValue,
|
|
18762
|
+
maxWidth,
|
|
18763
|
+
maxHeight
|
|
18764
|
+
};
|
|
18765
|
+
case "right":
|
|
18766
|
+
return {
|
|
18767
|
+
...verticalAlignStyle(align, inset, heightValue),
|
|
18768
|
+
right: `calc(${inset.right} + var(--pano-safe-right))`,
|
|
18769
|
+
left: "auto",
|
|
18770
|
+
width: widthValue,
|
|
18771
|
+
maxWidth,
|
|
18772
|
+
maxHeight
|
|
18773
|
+
};
|
|
18774
|
+
default: {
|
|
18775
|
+
const exhaustive = placement;
|
|
18776
|
+
void exhaustive;
|
|
18777
|
+
return {};
|
|
18778
|
+
}
|
|
18779
|
+
}
|
|
18780
|
+
}
|
|
18781
|
+
function PanoSceneMenu({
|
|
18782
|
+
items,
|
|
18783
|
+
activeId = null,
|
|
18784
|
+
onSelect,
|
|
18785
|
+
placement = "bottom",
|
|
18786
|
+
align = "center",
|
|
18787
|
+
inset,
|
|
18788
|
+
width,
|
|
18789
|
+
height,
|
|
18790
|
+
collapsible = false,
|
|
18791
|
+
defaultExpanded = true,
|
|
18792
|
+
expanded: expandedProp,
|
|
18793
|
+
onExpandedChange,
|
|
18794
|
+
showArrows = false,
|
|
18795
|
+
loop = false,
|
|
18796
|
+
dragMotion: dragMotionProp,
|
|
18797
|
+
appearance,
|
|
18798
|
+
className,
|
|
18799
|
+
style,
|
|
18800
|
+
label = "Scenes",
|
|
18801
|
+
previousLabel = "Previous scene",
|
|
18802
|
+
nextLabel = "Next scene",
|
|
18803
|
+
expandLabel = "Show scenes",
|
|
18804
|
+
collapseLabel = "Hide scenes"
|
|
18805
|
+
}) {
|
|
18806
|
+
const listId = useId3();
|
|
18807
|
+
const listRef = useRef40(null);
|
|
18808
|
+
const trackRef = useRef40(null);
|
|
18809
|
+
const itemRefs = useRef40(/* @__PURE__ */ new Map());
|
|
18810
|
+
const resolved = resolveAppearance2(appearance);
|
|
18811
|
+
const resolvedInset = resolveInset(inset);
|
|
18812
|
+
const horizontal = isHorizontal(placement);
|
|
18813
|
+
const customDrag = dragMotionProp !== false;
|
|
18814
|
+
const dragMotion = resolveDragMotion(
|
|
18815
|
+
dragMotionProp === false ? false : dragMotionProp
|
|
18816
|
+
);
|
|
18817
|
+
const isExpandedControlled = expandedProp !== void 0;
|
|
18818
|
+
const [internalExpanded, setInternalExpanded] = useState25(defaultExpanded);
|
|
18819
|
+
const expanded = collapsible ? isExpandedControlled ? expandedProp : internalExpanded : true;
|
|
18820
|
+
const [offset, setOffset] = useState25(0);
|
|
18821
|
+
const [viewportSize, setViewportSize] = useState25(0);
|
|
18822
|
+
const [contentSize, setContentSize] = useState25(0);
|
|
18823
|
+
const offsetRef = useRef40(0);
|
|
18824
|
+
const dragRef = useRef40(null);
|
|
18825
|
+
const animRef = useRef40(null);
|
|
18826
|
+
const maxOffset = Math.max(0, contentSize - viewportSize);
|
|
18827
|
+
offsetRef.current = offset;
|
|
18828
|
+
const activeIndex = useMemo27(() => {
|
|
18829
|
+
if (activeId == null) {
|
|
18830
|
+
return -1;
|
|
18831
|
+
}
|
|
18832
|
+
return items.findIndex((item) => item.id === activeId);
|
|
18833
|
+
}, [activeId, items]);
|
|
18834
|
+
const cancelScrollAnimation = useCallback11(() => {
|
|
18835
|
+
const anim = animRef.current;
|
|
18836
|
+
if (anim?.raf != null) {
|
|
18837
|
+
cancelAnimationFrame(anim.raf);
|
|
18838
|
+
}
|
|
18839
|
+
animRef.current = null;
|
|
18840
|
+
}, []);
|
|
18841
|
+
const clampOffset = useCallback11(
|
|
18842
|
+
(value) => Math.min(maxOffset, Math.max(0, value)),
|
|
18843
|
+
[maxOffset]
|
|
18844
|
+
);
|
|
18845
|
+
const startScrollAnimation = useCallback11(
|
|
18846
|
+
(velocity) => {
|
|
18847
|
+
cancelScrollAnimation();
|
|
18848
|
+
const current = offsetRef.current;
|
|
18849
|
+
const needsSpring = dragMotion.bounce && (current < 0 || current > maxOffset);
|
|
18850
|
+
const nextVelocity = dragMotion.inertia ? velocity : 0;
|
|
18851
|
+
if (!needsSpring && Math.abs(nextVelocity) < 1) {
|
|
18852
|
+
setOffset(clampOffset(current));
|
|
18853
|
+
return;
|
|
18854
|
+
}
|
|
18855
|
+
if (!dragMotion.inertia && !dragMotion.bounce) {
|
|
18856
|
+
setOffset(clampOffset(current));
|
|
18857
|
+
return;
|
|
18858
|
+
}
|
|
18859
|
+
const anim = {
|
|
18860
|
+
raf: null,
|
|
18861
|
+
lastTime: performance.now(),
|
|
18862
|
+
position: current,
|
|
18863
|
+
velocity: nextVelocity
|
|
18864
|
+
};
|
|
18865
|
+
animRef.current = anim;
|
|
18866
|
+
const tick = (now) => {
|
|
18867
|
+
if (animRef.current !== anim) return;
|
|
18868
|
+
const dt = Math.min(0.064, Math.max(0, (now - anim.lastTime) / 1e3));
|
|
18869
|
+
anim.lastTime = now;
|
|
18870
|
+
const next = integrateAxis(
|
|
18871
|
+
{ position: anim.position, velocity: anim.velocity },
|
|
18872
|
+
dt,
|
|
18873
|
+
{
|
|
18874
|
+
min: 0,
|
|
18875
|
+
max: maxOffset,
|
|
18876
|
+
inertia: dragMotion.inertia,
|
|
18877
|
+
bounce: dragMotion.bounce
|
|
18878
|
+
}
|
|
18879
|
+
);
|
|
18880
|
+
anim.position = next.position;
|
|
18881
|
+
anim.velocity = next.velocity;
|
|
18882
|
+
setOffset(next.position);
|
|
18883
|
+
if (next.settled) {
|
|
18884
|
+
setOffset(clampOffset(next.position));
|
|
18885
|
+
animRef.current = null;
|
|
18886
|
+
return;
|
|
18887
|
+
}
|
|
18888
|
+
anim.raf = requestAnimationFrame(tick);
|
|
18889
|
+
};
|
|
18890
|
+
anim.raf = requestAnimationFrame(tick);
|
|
18891
|
+
},
|
|
18892
|
+
[
|
|
18893
|
+
cancelScrollAnimation,
|
|
18894
|
+
clampOffset,
|
|
18895
|
+
dragMotion.bounce,
|
|
18896
|
+
dragMotion.inertia,
|
|
18897
|
+
maxOffset
|
|
18898
|
+
]
|
|
18899
|
+
);
|
|
18900
|
+
useEffect41(() => () => cancelScrollAnimation(), [cancelScrollAnimation]);
|
|
18901
|
+
useLayoutEffect9(() => {
|
|
18902
|
+
if (!customDrag || !expanded) return;
|
|
18903
|
+
const list = listRef.current;
|
|
18904
|
+
const track = trackRef.current;
|
|
18905
|
+
if (!list || !track) return;
|
|
18906
|
+
const measure = () => {
|
|
18907
|
+
const nextViewport = horizontal ? list.clientWidth : list.clientHeight;
|
|
18908
|
+
const nextContent = horizontal ? track.scrollWidth : track.scrollHeight;
|
|
18909
|
+
setViewportSize(
|
|
18910
|
+
(previous) => previous === nextViewport ? previous : nextViewport
|
|
18911
|
+
);
|
|
18912
|
+
setContentSize(
|
|
18913
|
+
(previous) => previous === nextContent ? previous : nextContent
|
|
18914
|
+
);
|
|
18915
|
+
};
|
|
18916
|
+
measure();
|
|
18917
|
+
const observer = new ResizeObserver(measure);
|
|
18918
|
+
observer.observe(list);
|
|
18919
|
+
observer.observe(track);
|
|
18920
|
+
return () => observer.disconnect();
|
|
18921
|
+
}, [customDrag, expanded, horizontal, items]);
|
|
18922
|
+
useEffect41(() => {
|
|
18923
|
+
if (!customDrag) return;
|
|
18924
|
+
if (dragRef.current || animRef.current) return;
|
|
18925
|
+
setOffset((previous) => Math.min(maxOffset, Math.max(0, previous)));
|
|
18926
|
+
}, [customDrag, maxOffset]);
|
|
18927
|
+
useEffect41(() => {
|
|
18928
|
+
if (!expanded || activeId == null) {
|
|
18929
|
+
return;
|
|
18930
|
+
}
|
|
18931
|
+
const node = itemRefs.current.get(activeId);
|
|
18932
|
+
if (!node) return;
|
|
18933
|
+
if (!customDrag) {
|
|
18934
|
+
node.scrollIntoView({
|
|
18935
|
+
behavior: "smooth",
|
|
18936
|
+
block: "nearest",
|
|
18937
|
+
inline: "nearest"
|
|
18938
|
+
});
|
|
18939
|
+
return;
|
|
18940
|
+
}
|
|
18941
|
+
const list = listRef.current;
|
|
18942
|
+
if (!list) return;
|
|
18943
|
+
const listRect = list.getBoundingClientRect();
|
|
18944
|
+
const itemRect = node.getBoundingClientRect();
|
|
18945
|
+
if (horizontal) {
|
|
18946
|
+
const itemStart2 = itemRect.left - listRect.left + offsetRef.current;
|
|
18947
|
+
const itemEnd2 = itemStart2 + itemRect.width;
|
|
18948
|
+
let next2 = offsetRef.current;
|
|
18949
|
+
if (itemStart2 < next2) next2 = itemStart2;
|
|
18950
|
+
else if (itemEnd2 > next2 + listRect.width) next2 = itemEnd2 - listRect.width;
|
|
18951
|
+
cancelScrollAnimation();
|
|
18952
|
+
setOffset(clampOffset(next2));
|
|
18953
|
+
return;
|
|
18954
|
+
}
|
|
18955
|
+
const itemStart = itemRect.top - listRect.top + offsetRef.current;
|
|
18956
|
+
const itemEnd = itemStart + itemRect.height;
|
|
18957
|
+
let next = offsetRef.current;
|
|
18958
|
+
if (itemStart < next) next = itemStart;
|
|
18959
|
+
else if (itemEnd > next + listRect.height) next = itemEnd - listRect.height;
|
|
18960
|
+
cancelScrollAnimation();
|
|
18961
|
+
setOffset(clampOffset(next));
|
|
18962
|
+
}, [
|
|
18963
|
+
activeId,
|
|
18964
|
+
cancelScrollAnimation,
|
|
18965
|
+
clampOffset,
|
|
18966
|
+
customDrag,
|
|
18967
|
+
expanded,
|
|
18968
|
+
horizontal
|
|
18969
|
+
]);
|
|
18970
|
+
const rootStyle = useMemo27(() => {
|
|
18971
|
+
const vars = {
|
|
18972
|
+
"--pano-scene-menu-background": resolved.background,
|
|
18973
|
+
"--pano-scene-menu-padding": cssLength(resolved.padding),
|
|
18974
|
+
"--pano-scene-menu-item-width": cssLength(resolved.itemWidth),
|
|
18975
|
+
"--pano-scene-menu-item-height": cssLength(resolved.itemHeight),
|
|
18976
|
+
"--pano-scene-menu-gap": cssLength(resolved.gap),
|
|
18977
|
+
"--pano-scene-menu-radius": cssLength(resolved.borderRadius),
|
|
18978
|
+
"--pano-scene-menu-selection-color": resolved.selectionColor,
|
|
18979
|
+
"--pano-scene-menu-selection-width": cssLength(resolved.selectionWidth),
|
|
18980
|
+
"--pano-scene-menu-label-background": resolved.labelBackground,
|
|
18981
|
+
"--pano-scene-menu-label-color": resolved.labelColor,
|
|
18982
|
+
"--pano-scene-menu-label-align": resolved.labelAlign,
|
|
18983
|
+
"--pano-scene-menu-font-size": cssLength(resolved.fontSize),
|
|
18984
|
+
"--pano-scene-menu-control-color": resolved.controlColor,
|
|
18985
|
+
"--pano-scene-menu-control-background": resolved.controlBackground,
|
|
18986
|
+
"--pano-scene-menu-dock-inset": dockInset(placement, resolvedInset)
|
|
18987
|
+
};
|
|
18988
|
+
return {
|
|
18989
|
+
...vars,
|
|
18990
|
+
...placementBoxStyle(placement, resolvedInset, width, height, align),
|
|
18991
|
+
...style
|
|
18992
|
+
};
|
|
18993
|
+
}, [align, height, placement, resolved, resolvedInset, style, width]);
|
|
18994
|
+
const setExpanded = (next) => {
|
|
18995
|
+
if (!collapsible) {
|
|
18996
|
+
return;
|
|
18997
|
+
}
|
|
18998
|
+
if (!isExpandedControlled) {
|
|
18999
|
+
setInternalExpanded(next);
|
|
19000
|
+
}
|
|
19001
|
+
onExpandedChange?.(next);
|
|
19002
|
+
};
|
|
19003
|
+
const selectAt = (index) => {
|
|
19004
|
+
const item = items[index];
|
|
19005
|
+
if (!item) {
|
|
19006
|
+
return;
|
|
19007
|
+
}
|
|
19008
|
+
onSelect?.(item.id);
|
|
19009
|
+
itemRefs.current.get(item.id)?.focus({ preventScroll: true });
|
|
19010
|
+
};
|
|
19011
|
+
const selectRelative = (delta) => {
|
|
19012
|
+
if (items.length === 0) {
|
|
19013
|
+
return;
|
|
19014
|
+
}
|
|
19015
|
+
const current = activeIndex >= 0 ? activeIndex : 0;
|
|
19016
|
+
if (loop) {
|
|
19017
|
+
const next = ((current + delta) % items.length + items.length) % items.length;
|
|
19018
|
+
selectAt(next);
|
|
19019
|
+
return;
|
|
19020
|
+
}
|
|
19021
|
+
selectAt(Math.max(0, Math.min(items.length - 1, current + delta)));
|
|
19022
|
+
};
|
|
19023
|
+
const onKeyDown = (event) => {
|
|
19024
|
+
if (items.length === 0 || !expanded) {
|
|
19025
|
+
return;
|
|
19026
|
+
}
|
|
19027
|
+
const current = activeIndex >= 0 ? activeIndex : Math.max(
|
|
19028
|
+
0,
|
|
19029
|
+
items.findIndex(
|
|
19030
|
+
(item) => itemRefs.current.get(item.id) === event.target
|
|
19031
|
+
)
|
|
19032
|
+
);
|
|
19033
|
+
const backward = horizontal ? event.key === "ArrowLeft" : event.key === "ArrowUp";
|
|
19034
|
+
const forward = horizontal ? event.key === "ArrowRight" : event.key === "ArrowDown";
|
|
19035
|
+
if (backward) {
|
|
19036
|
+
event.preventDefault();
|
|
19037
|
+
if (loop) {
|
|
19038
|
+
selectAt((current - 1 + items.length) % items.length);
|
|
19039
|
+
} else {
|
|
19040
|
+
selectAt(Math.max(0, current - 1));
|
|
19041
|
+
}
|
|
19042
|
+
return;
|
|
19043
|
+
}
|
|
19044
|
+
if (forward) {
|
|
19045
|
+
event.preventDefault();
|
|
19046
|
+
if (loop) {
|
|
19047
|
+
selectAt((current + 1) % items.length);
|
|
19048
|
+
} else {
|
|
19049
|
+
selectAt(Math.min(items.length - 1, current + 1));
|
|
19050
|
+
}
|
|
19051
|
+
return;
|
|
19052
|
+
}
|
|
19053
|
+
switch (event.key) {
|
|
19054
|
+
case "Home": {
|
|
19055
|
+
event.preventDefault();
|
|
19056
|
+
selectAt(0);
|
|
19057
|
+
break;
|
|
19058
|
+
}
|
|
19059
|
+
case "End": {
|
|
19060
|
+
event.preventDefault();
|
|
19061
|
+
selectAt(items.length - 1);
|
|
19062
|
+
break;
|
|
19063
|
+
}
|
|
19064
|
+
default:
|
|
19065
|
+
break;
|
|
19066
|
+
}
|
|
19067
|
+
};
|
|
19068
|
+
const onWheel = (event) => {
|
|
19069
|
+
const list = listRef.current;
|
|
19070
|
+
if (!list) {
|
|
19071
|
+
return;
|
|
19072
|
+
}
|
|
19073
|
+
if (!customDrag) {
|
|
19074
|
+
if (horizontal) {
|
|
19075
|
+
const canScroll2 = list.scrollWidth > list.clientWidth + 1;
|
|
19076
|
+
if (!canScroll2 || Math.abs(event.deltaY) <= Math.abs(event.deltaX)) {
|
|
19077
|
+
return;
|
|
19078
|
+
}
|
|
19079
|
+
event.preventDefault();
|
|
19080
|
+
event.stopPropagation();
|
|
19081
|
+
list.scrollLeft += event.deltaY;
|
|
19082
|
+
return;
|
|
19083
|
+
}
|
|
19084
|
+
const canScroll = list.scrollHeight > list.clientHeight + 1;
|
|
19085
|
+
if (!canScroll || Math.abs(event.deltaX) <= Math.abs(event.deltaY)) {
|
|
19086
|
+
return;
|
|
19087
|
+
}
|
|
19088
|
+
event.preventDefault();
|
|
19089
|
+
event.stopPropagation();
|
|
19090
|
+
list.scrollTop += event.deltaX;
|
|
19091
|
+
return;
|
|
19092
|
+
}
|
|
19093
|
+
if (horizontal) {
|
|
19094
|
+
if (maxOffset <= 0 || Math.abs(event.deltaY) <= Math.abs(event.deltaX)) {
|
|
19095
|
+
return;
|
|
19096
|
+
}
|
|
19097
|
+
event.preventDefault();
|
|
19098
|
+
event.stopPropagation();
|
|
19099
|
+
cancelScrollAnimation();
|
|
19100
|
+
setOffset((previous) => clampOffset(previous + event.deltaY));
|
|
19101
|
+
return;
|
|
19102
|
+
}
|
|
19103
|
+
if (maxOffset <= 0 || Math.abs(event.deltaX) <= Math.abs(event.deltaY)) {
|
|
19104
|
+
return;
|
|
19105
|
+
}
|
|
19106
|
+
event.preventDefault();
|
|
19107
|
+
event.stopPropagation();
|
|
19108
|
+
cancelScrollAnimation();
|
|
19109
|
+
setOffset((previous) => clampOffset(previous + event.deltaX));
|
|
19110
|
+
};
|
|
19111
|
+
const axisPoint = (event) => horizontal ? event.clientX : event.clientY;
|
|
19112
|
+
const endSuppressClickRef = useRef40(false);
|
|
19113
|
+
const beginListDrag = (event, captureTarget) => {
|
|
19114
|
+
if (!customDrag || event.button !== 0) return;
|
|
19115
|
+
cancelScrollAnimation();
|
|
19116
|
+
const now = performance.now();
|
|
19117
|
+
const origin = axisPoint(event);
|
|
19118
|
+
dragRef.current = {
|
|
19119
|
+
pointerId: event.pointerId,
|
|
19120
|
+
origin,
|
|
19121
|
+
startOffset: offsetRef.current,
|
|
19122
|
+
samples: [{ t: now, position: offsetRef.current }],
|
|
19123
|
+
moved: false,
|
|
19124
|
+
suppressClick: false
|
|
19125
|
+
};
|
|
19126
|
+
try {
|
|
19127
|
+
captureTarget.setPointerCapture(event.pointerId);
|
|
19128
|
+
} catch {
|
|
19129
|
+
}
|
|
19130
|
+
};
|
|
19131
|
+
const onListPointerMove = (event) => {
|
|
19132
|
+
const drag = dragRef.current;
|
|
19133
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
19134
|
+
const point = axisPoint(event);
|
|
19135
|
+
const delta = point - drag.origin;
|
|
19136
|
+
if (!drag.moved && Math.abs(delta) >= SCENE_MENU_DRAG_THRESHOLD_PX) {
|
|
19137
|
+
drag.moved = true;
|
|
19138
|
+
drag.suppressClick = true;
|
|
19139
|
+
}
|
|
19140
|
+
if (!drag.moved) return;
|
|
19141
|
+
const raw = drag.startOffset - delta;
|
|
19142
|
+
const now = performance.now();
|
|
19143
|
+
drag.samples = pushSample(drag.samples, { t: now, position: raw });
|
|
19144
|
+
setOffset(
|
|
19145
|
+
constrainDragPosition(
|
|
19146
|
+
raw,
|
|
19147
|
+
0,
|
|
19148
|
+
maxOffset,
|
|
19149
|
+
Math.max(1, viewportSize),
|
|
19150
|
+
dragMotion.bounce
|
|
19151
|
+
)
|
|
19152
|
+
);
|
|
19153
|
+
event.preventDefault();
|
|
19154
|
+
};
|
|
19155
|
+
const finishPointerWithClickGuard = (event) => {
|
|
19156
|
+
const drag = dragRef.current;
|
|
19157
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
19158
|
+
const suppress = drag.suppressClick;
|
|
19159
|
+
dragRef.current = null;
|
|
19160
|
+
try {
|
|
19161
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
19162
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
19163
|
+
}
|
|
19164
|
+
} catch {
|
|
19165
|
+
}
|
|
19166
|
+
if (suppress) {
|
|
19167
|
+
endSuppressClickRef.current = true;
|
|
19168
|
+
queueMicrotask(() => {
|
|
19169
|
+
endSuppressClickRef.current = false;
|
|
19170
|
+
});
|
|
19171
|
+
}
|
|
19172
|
+
if (!drag.moved) return;
|
|
19173
|
+
if (event.type === "pointercancel") {
|
|
19174
|
+
setOffset(clampOffset(offsetRef.current));
|
|
19175
|
+
return;
|
|
19176
|
+
}
|
|
19177
|
+
startScrollAnimation(velocityFromSamples(drag.samples));
|
|
19178
|
+
};
|
|
19179
|
+
const onItemClick = (event, id) => {
|
|
19180
|
+
if (endSuppressClickRef.current) {
|
|
19181
|
+
event.preventDefault();
|
|
19182
|
+
event.stopPropagation();
|
|
19183
|
+
return;
|
|
19184
|
+
}
|
|
19185
|
+
onSelect?.(id);
|
|
19186
|
+
};
|
|
19187
|
+
const canStep = items.length > 1;
|
|
19188
|
+
const canGoPrevious = canStep && (loop || activeIndex !== 0);
|
|
19189
|
+
const canGoNext = canStep && (loop || activeIndex !== items.length - 1);
|
|
19190
|
+
const orientation2 = horizontal ? "horizontal" : "vertical";
|
|
19191
|
+
const trackStyle = customDrag ? {
|
|
19192
|
+
transform: horizontal ? `translate3d(${-offset}px, 0, 0)` : `translate3d(0, ${-offset}px, 0)`,
|
|
19193
|
+
willChange: "transform"
|
|
19194
|
+
} : void 0;
|
|
19195
|
+
return /* @__PURE__ */ jsxs22(
|
|
19196
|
+
"div",
|
|
19197
|
+
{
|
|
19198
|
+
"aria-label": label,
|
|
19199
|
+
className: cn("pano-scene-menu", className),
|
|
19200
|
+
"data-align": align,
|
|
19201
|
+
"data-collapsible": collapsible ? "true" : void 0,
|
|
19202
|
+
"data-drag-motion": customDrag ? "custom" : "native",
|
|
19203
|
+
"data-expanded": expanded ? "true" : "false",
|
|
19204
|
+
"data-orientation": orientation2,
|
|
19205
|
+
"data-placement": placement,
|
|
19206
|
+
role: "group",
|
|
19207
|
+
style: rootStyle,
|
|
19208
|
+
children: [
|
|
19209
|
+
/* @__PURE__ */ jsxs22(
|
|
19210
|
+
"div",
|
|
19211
|
+
{
|
|
19212
|
+
"aria-hidden": expanded ? void 0 : true,
|
|
19213
|
+
className: "pano-scene-menu-body",
|
|
19214
|
+
...!expanded ? { inert: true } : null,
|
|
19215
|
+
children: [
|
|
19216
|
+
showArrows ? /* @__PURE__ */ jsx41(
|
|
19217
|
+
ControlButton,
|
|
19218
|
+
{
|
|
19219
|
+
className: "pano-scene-menu-arrow",
|
|
19220
|
+
disabled: !canGoPrevious || !expanded,
|
|
19221
|
+
label: previousLabel,
|
|
19222
|
+
onClick: () => selectRelative(-1),
|
|
19223
|
+
children: /* @__PURE__ */ jsx41(Chevron, { arrow: arrowChevron("prev", orientation2) })
|
|
19224
|
+
}
|
|
19225
|
+
) : null,
|
|
19226
|
+
/* @__PURE__ */ jsx41(
|
|
19227
|
+
"div",
|
|
19228
|
+
{
|
|
19229
|
+
"aria-label": label,
|
|
19230
|
+
className: "pano-scene-menu-list",
|
|
19231
|
+
id: listId,
|
|
19232
|
+
onKeyDown,
|
|
19233
|
+
onPointerCancel: customDrag ? finishPointerWithClickGuard : void 0,
|
|
19234
|
+
onPointerDown: customDrag ? (event) => beginListDrag(event, event.currentTarget) : void 0,
|
|
19235
|
+
onPointerMove: customDrag ? onListPointerMove : void 0,
|
|
19236
|
+
onPointerUp: customDrag ? finishPointerWithClickGuard : void 0,
|
|
19237
|
+
onWheel,
|
|
19238
|
+
ref: listRef,
|
|
19239
|
+
role: "radiogroup",
|
|
19240
|
+
children: /* @__PURE__ */ jsx41(
|
|
19241
|
+
"div",
|
|
19242
|
+
{
|
|
19243
|
+
className: "pano-scene-menu-track",
|
|
19244
|
+
ref: trackRef,
|
|
19245
|
+
style: trackStyle,
|
|
19246
|
+
children: items.map((item) => {
|
|
19247
|
+
const name = itemLabel(item);
|
|
19248
|
+
const selected = item.id === activeId;
|
|
19249
|
+
return /* @__PURE__ */ jsx41(
|
|
19250
|
+
"button",
|
|
19251
|
+
{
|
|
19252
|
+
"aria-checked": selected,
|
|
19253
|
+
className: "pano-scene-menu-item",
|
|
19254
|
+
"data-active": selected ? "true" : void 0,
|
|
19255
|
+
onClick: (event) => onItemClick(event, item.id),
|
|
19256
|
+
onPointerDown: (event) => {
|
|
19257
|
+
event.stopPropagation();
|
|
19258
|
+
const list = listRef.current;
|
|
19259
|
+
if (customDrag && list) {
|
|
19260
|
+
beginListDrag(event, list);
|
|
19261
|
+
}
|
|
19262
|
+
},
|
|
19263
|
+
ref: (node) => {
|
|
19264
|
+
if (node) {
|
|
19265
|
+
itemRefs.current.set(item.id, node);
|
|
19266
|
+
} else {
|
|
19267
|
+
itemRefs.current.delete(item.id);
|
|
19268
|
+
}
|
|
19269
|
+
},
|
|
19270
|
+
role: "radio",
|
|
19271
|
+
tabIndex: selected || activeId == null && item === items[0] ? 0 : -1,
|
|
19272
|
+
title: name,
|
|
19273
|
+
type: "button",
|
|
19274
|
+
children: /* @__PURE__ */ jsxs22("span", { className: "pano-scene-menu-thumb", children: [
|
|
19275
|
+
/* @__PURE__ */ jsx41(
|
|
19276
|
+
"img",
|
|
19277
|
+
{
|
|
19278
|
+
alt: "",
|
|
19279
|
+
decoding: "async",
|
|
19280
|
+
draggable: false,
|
|
19281
|
+
src: item.thumbnailUrl
|
|
19282
|
+
}
|
|
19283
|
+
),
|
|
19284
|
+
/* @__PURE__ */ jsx41("span", { className: "pano-scene-menu-label", children: name })
|
|
19285
|
+
] })
|
|
19286
|
+
},
|
|
19287
|
+
item.id
|
|
19288
|
+
);
|
|
19289
|
+
})
|
|
19290
|
+
}
|
|
19291
|
+
)
|
|
19292
|
+
}
|
|
19293
|
+
),
|
|
19294
|
+
showArrows ? /* @__PURE__ */ jsx41(
|
|
19295
|
+
ControlButton,
|
|
19296
|
+
{
|
|
19297
|
+
className: "pano-scene-menu-arrow",
|
|
19298
|
+
disabled: !canGoNext || !expanded,
|
|
19299
|
+
label: nextLabel,
|
|
19300
|
+
onClick: () => selectRelative(1),
|
|
19301
|
+
children: /* @__PURE__ */ jsx41(Chevron, { arrow: arrowChevron("next", orientation2) })
|
|
19302
|
+
}
|
|
19303
|
+
) : null
|
|
19304
|
+
]
|
|
19305
|
+
}
|
|
19306
|
+
),
|
|
19307
|
+
collapsible ? /* @__PURE__ */ jsx41(
|
|
19308
|
+
ControlButton,
|
|
19309
|
+
{
|
|
19310
|
+
className: "pano-scene-menu-toggle",
|
|
19311
|
+
label: expanded ? collapseLabel : expandLabel,
|
|
19312
|
+
onClick: () => setExpanded(!expanded),
|
|
19313
|
+
children: /* @__PURE__ */ jsx41(Chevron, { arrow: toggleChevron(placement, expanded) })
|
|
19314
|
+
}
|
|
19315
|
+
) : null
|
|
19316
|
+
]
|
|
19317
|
+
}
|
|
19318
|
+
);
|
|
19319
|
+
}
|
|
19320
|
+
|
|
18413
19321
|
// src/use-pano-viewer.ts
|
|
18414
|
-
import { useMemo as
|
|
19322
|
+
import { useMemo as useMemo28, useRef as useRef41 } from "react";
|
|
18415
19323
|
function createPanoViewerHandle(ref) {
|
|
18416
19324
|
return {
|
|
18417
19325
|
getView: () => ref.current?.getView() ?? { yaw: 0, pitch: 0, fov: 75 },
|
|
@@ -18493,21 +19401,21 @@ function createPanoViewerHandle(ref) {
|
|
|
18493
19401
|
};
|
|
18494
19402
|
}
|
|
18495
19403
|
function usePanoViewer() {
|
|
18496
|
-
const ref =
|
|
18497
|
-
const handle =
|
|
18498
|
-
return
|
|
19404
|
+
const ref = useRef41(null);
|
|
19405
|
+
const handle = useMemo28(() => createPanoViewerHandle(ref), []);
|
|
19406
|
+
return useMemo28(() => ({ ref, ...handle }), [handle]);
|
|
18499
19407
|
}
|
|
18500
19408
|
|
|
18501
19409
|
// src/video/pano-video.tsx
|
|
18502
19410
|
import { useThree as useThree29 } from "@react-three/fiber";
|
|
18503
19411
|
import {
|
|
18504
|
-
useCallback as
|
|
19412
|
+
useCallback as useCallback12,
|
|
18505
19413
|
useContext as useContext28,
|
|
18506
|
-
useEffect as
|
|
18507
|
-
useLayoutEffect as
|
|
18508
|
-
useMemo as
|
|
18509
|
-
useRef as
|
|
18510
|
-
useState as
|
|
19414
|
+
useEffect as useEffect42,
|
|
19415
|
+
useLayoutEffect as useLayoutEffect10,
|
|
19416
|
+
useMemo as useMemo29,
|
|
19417
|
+
useRef as useRef42,
|
|
19418
|
+
useState as useState26
|
|
18511
19419
|
} from "react";
|
|
18512
19420
|
import {
|
|
18513
19421
|
BackSide as BackSide4,
|
|
@@ -18519,7 +19427,7 @@ import {
|
|
|
18519
19427
|
TextureLoader as TextureLoader8,
|
|
18520
19428
|
VideoTexture as VideoTexture2
|
|
18521
19429
|
} from "three";
|
|
18522
|
-
import { Fragment as Fragment7, jsx as
|
|
19430
|
+
import { Fragment as Fragment7, jsx as jsx42, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
18523
19431
|
var EMPTY_TRACKS = [];
|
|
18524
19432
|
var EMPTY_RATES = DEFAULT_PANO_VIDEO_PLAYBACK_RATES;
|
|
18525
19433
|
function createEmptySnapshot() {
|
|
@@ -18604,10 +19512,10 @@ function applyEquirectangularLayout(texture, anisotropy) {
|
|
|
18604
19512
|
}
|
|
18605
19513
|
function usePosterTexture2(poster, onError) {
|
|
18606
19514
|
const gl = useThree29((state) => state.gl);
|
|
18607
|
-
const [texture, setTexture] =
|
|
18608
|
-
const onErrorRef =
|
|
19515
|
+
const [texture, setTexture] = useState26(null);
|
|
19516
|
+
const onErrorRef = useRef42(onError);
|
|
18609
19517
|
onErrorRef.current = onError;
|
|
18610
|
-
|
|
19518
|
+
useEffect42(() => {
|
|
18611
19519
|
let active = true;
|
|
18612
19520
|
setTexture(null);
|
|
18613
19521
|
if (!poster) {
|
|
@@ -18644,7 +19552,7 @@ function usePosterTexture2(poster, onError) {
|
|
|
18644
19552
|
active = false;
|
|
18645
19553
|
};
|
|
18646
19554
|
}, [gl, poster]);
|
|
18647
|
-
|
|
19555
|
+
useEffect42(
|
|
18648
19556
|
() => () => {
|
|
18649
19557
|
texture?.dispose();
|
|
18650
19558
|
},
|
|
@@ -18704,36 +19612,36 @@ function PanoVideo({
|
|
|
18704
19612
|
usePanoMediaActivationIntent(autoPlay);
|
|
18705
19613
|
const gl = useThree29((state) => state.gl);
|
|
18706
19614
|
const host = useContext28(PanoVideoHostContext);
|
|
18707
|
-
const variants =
|
|
19615
|
+
const variants = useMemo29(
|
|
18708
19616
|
() => resolvePanoVideoVariants({ poster, src, variants: variantsProp }),
|
|
18709
19617
|
[poster, src, variantsProp]
|
|
18710
19618
|
);
|
|
18711
19619
|
const tracks = tracksProp ?? EMPTY_TRACKS;
|
|
18712
19620
|
const captionsEnabled = captions !== false;
|
|
18713
|
-
const captionAppearance =
|
|
19621
|
+
const captionAppearance = useMemo29(
|
|
18714
19622
|
() => resolvePanoVideoCaptionAppearance(
|
|
18715
19623
|
typeof captions === "object" ? captions : void 0
|
|
18716
19624
|
),
|
|
18717
19625
|
[captions]
|
|
18718
19626
|
);
|
|
18719
|
-
const [variantId, setVariantId] =
|
|
19627
|
+
const [variantId, setVariantId] = useState26(
|
|
18720
19628
|
() => resolvePanoVideoVariantId(variants, defaultVariantId)
|
|
18721
19629
|
);
|
|
18722
|
-
const [trackId, setTrackId] =
|
|
19630
|
+
const [trackId, setTrackId] = useState26(
|
|
18723
19631
|
() => captionsEnabled ? defaultPanoVideoTrackId(tracks) : null
|
|
18724
19632
|
);
|
|
18725
|
-
const [ready, setReady] =
|
|
18726
|
-
const autoPlayRef =
|
|
19633
|
+
const [ready, setReady] = useState26(false);
|
|
19634
|
+
const autoPlayRef = useRef42(autoPlay);
|
|
18727
19635
|
autoPlayRef.current = autoPlay;
|
|
18728
|
-
const blockedRef =
|
|
18729
|
-
const captionAppearanceOverrideRef =
|
|
19636
|
+
const blockedRef = useRef42(false);
|
|
19637
|
+
const captionAppearanceOverrideRef = useRef42(
|
|
18730
19638
|
{}
|
|
18731
19639
|
);
|
|
18732
|
-
const mediaCapabilitiesRef =
|
|
19640
|
+
const mediaCapabilitiesRef = useRef42({
|
|
18733
19641
|
volumeAdjustable: true,
|
|
18734
19642
|
playbackRates: [...DEFAULT_PANO_VIDEO_PLAYBACK_RATES]
|
|
18735
19643
|
});
|
|
18736
|
-
const storeRef =
|
|
19644
|
+
const storeRef = useRef42(null);
|
|
18737
19645
|
if (!storeRef.current) {
|
|
18738
19646
|
storeRef.current = {
|
|
18739
19647
|
snapshot: {
|
|
@@ -18743,7 +19651,7 @@ function PanoVideo({
|
|
|
18743
19651
|
listeners: /* @__PURE__ */ new Set()
|
|
18744
19652
|
};
|
|
18745
19653
|
}
|
|
18746
|
-
const actionsRef =
|
|
19654
|
+
const actionsRef = useRef42({
|
|
18747
19655
|
play: async () => {
|
|
18748
19656
|
},
|
|
18749
19657
|
pause: () => {
|
|
@@ -18763,19 +19671,19 @@ function PanoVideo({
|
|
|
18763
19671
|
setCaptionAppearance: (_appearance) => {
|
|
18764
19672
|
}
|
|
18765
19673
|
});
|
|
18766
|
-
const onLoadRef =
|
|
18767
|
-
const onErrorRef =
|
|
18768
|
-
const onPlaybackStateChangeRef =
|
|
18769
|
-
const onEndedRef =
|
|
18770
|
-
const onVariantChangeRef =
|
|
18771
|
-
const onTrackChangeRef =
|
|
19674
|
+
const onLoadRef = useRef42(onLoad);
|
|
19675
|
+
const onErrorRef = useRef42(onError);
|
|
19676
|
+
const onPlaybackStateChangeRef = useRef42(onPlaybackStateChange);
|
|
19677
|
+
const onEndedRef = useRef42(onEnded);
|
|
19678
|
+
const onVariantChangeRef = useRef42(onVariantChange);
|
|
19679
|
+
const onTrackChangeRef = useRef42(onTrackChange);
|
|
18772
19680
|
onLoadRef.current = onLoad;
|
|
18773
19681
|
onErrorRef.current = onError;
|
|
18774
19682
|
onPlaybackStateChangeRef.current = onPlaybackStateChange;
|
|
18775
19683
|
onEndedRef.current = onEnded;
|
|
18776
19684
|
onVariantChangeRef.current = onVariantChange;
|
|
18777
19685
|
onTrackChangeRef.current = onTrackChange;
|
|
18778
|
-
const resource =
|
|
19686
|
+
const resource = useMemo29(() => {
|
|
18779
19687
|
if (typeof document === "undefined") {
|
|
18780
19688
|
return null;
|
|
18781
19689
|
}
|
|
@@ -18790,7 +19698,7 @@ function PanoVideo({
|
|
|
18790
19698
|
texture.generateMipmaps = false;
|
|
18791
19699
|
return { video, texture };
|
|
18792
19700
|
}, []);
|
|
18793
|
-
|
|
19701
|
+
useEffect42(
|
|
18794
19702
|
() => () => {
|
|
18795
19703
|
if (!resource) {
|
|
18796
19704
|
return;
|
|
@@ -18805,13 +19713,13 @@ function PanoVideo({
|
|
|
18805
19713
|
},
|
|
18806
19714
|
[resource]
|
|
18807
19715
|
);
|
|
18808
|
-
|
|
19716
|
+
useEffect42(() => {
|
|
18809
19717
|
if (!resource) {
|
|
18810
19718
|
return;
|
|
18811
19719
|
}
|
|
18812
19720
|
resource.texture.anisotropy = gl.capabilities.getMaxAnisotropy();
|
|
18813
19721
|
}, [gl, resource]);
|
|
18814
|
-
|
|
19722
|
+
useLayoutEffect10(() => {
|
|
18815
19723
|
if (!resource) {
|
|
18816
19724
|
return;
|
|
18817
19725
|
}
|
|
@@ -18827,7 +19735,7 @@ function PanoVideo({
|
|
|
18827
19735
|
activeVariant?.poster ?? poster,
|
|
18828
19736
|
onError
|
|
18829
19737
|
);
|
|
18830
|
-
const emitSnapshot =
|
|
19738
|
+
const emitSnapshot = useCallback12(
|
|
18831
19739
|
(patch) => {
|
|
18832
19740
|
const store = storeRef.current;
|
|
18833
19741
|
const video = resource?.video;
|
|
@@ -18879,7 +19787,7 @@ function PanoVideo({
|
|
|
18879
19787
|
captionAppearance
|
|
18880
19788
|
]
|
|
18881
19789
|
);
|
|
18882
|
-
const controller =
|
|
19790
|
+
const controller = useMemo29(
|
|
18883
19791
|
() => ({
|
|
18884
19792
|
subscribe: (onStoreChange) => {
|
|
18885
19793
|
const store = storeRef.current;
|
|
@@ -18931,7 +19839,7 @@ function PanoVideo({
|
|
|
18931
19839
|
}),
|
|
18932
19840
|
[]
|
|
18933
19841
|
);
|
|
18934
|
-
|
|
19842
|
+
useLayoutEffect10(() => {
|
|
18935
19843
|
if (!host || variants.length === 0) {
|
|
18936
19844
|
return;
|
|
18937
19845
|
}
|
|
@@ -18944,7 +19852,7 @@ function PanoVideo({
|
|
|
18944
19852
|
notifyPanoVideoHost(host);
|
|
18945
19853
|
};
|
|
18946
19854
|
}, [captionsEnabled, controller, controls, host, variants.length]);
|
|
18947
|
-
|
|
19855
|
+
useLayoutEffect10(() => {
|
|
18948
19856
|
if (!resource) {
|
|
18949
19857
|
return;
|
|
18950
19858
|
}
|
|
@@ -18957,10 +19865,10 @@ function PanoVideo({
|
|
|
18957
19865
|
};
|
|
18958
19866
|
emitSnapshot();
|
|
18959
19867
|
}, [emitSnapshot, playbackRates, resource]);
|
|
18960
|
-
|
|
19868
|
+
useEffect42(() => {
|
|
18961
19869
|
emitSnapshot();
|
|
18962
19870
|
}, [emitSnapshot]);
|
|
18963
|
-
|
|
19871
|
+
useEffect42(() => {
|
|
18964
19872
|
if (!resource || !activeVariant || !mediaKey) {
|
|
18965
19873
|
return;
|
|
18966
19874
|
}
|
|
@@ -19017,7 +19925,7 @@ function PanoVideo({
|
|
|
19017
19925
|
video.removeEventListener("error", handleError);
|
|
19018
19926
|
};
|
|
19019
19927
|
}, [mediaKey, resource]);
|
|
19020
|
-
|
|
19928
|
+
useEffect42(() => {
|
|
19021
19929
|
if (!resource) {
|
|
19022
19930
|
return;
|
|
19023
19931
|
}
|
|
@@ -19109,7 +20017,7 @@ function PanoVideo({
|
|
|
19109
20017
|
}
|
|
19110
20018
|
};
|
|
19111
20019
|
}, [emitSnapshot, resource]);
|
|
19112
|
-
|
|
20020
|
+
useLayoutEffect10(() => {
|
|
19113
20021
|
if (!resource) {
|
|
19114
20022
|
return;
|
|
19115
20023
|
}
|
|
@@ -19122,7 +20030,7 @@ function PanoVideo({
|
|
|
19122
20030
|
applyInlineVideoPlayback(video, playsInline);
|
|
19123
20031
|
video.preload = preload;
|
|
19124
20032
|
}, [loop, muted, playsInline, preload, resource, volume]);
|
|
19125
|
-
|
|
20033
|
+
useEffect42(() => {
|
|
19126
20034
|
if (!resource) {
|
|
19127
20035
|
return;
|
|
19128
20036
|
}
|
|
@@ -19172,7 +20080,7 @@ function PanoVideo({
|
|
|
19172
20080
|
video.removeEventListener("ratechange", handleVolume);
|
|
19173
20081
|
};
|
|
19174
20082
|
}, [emitSnapshot, resource]);
|
|
19175
|
-
|
|
20083
|
+
useEffect42(() => {
|
|
19176
20084
|
if (!resource) {
|
|
19177
20085
|
return;
|
|
19178
20086
|
}
|
|
@@ -19207,7 +20115,7 @@ function PanoVideo({
|
|
|
19207
20115
|
video.textTracks.removeEventListener("change", applyModes);
|
|
19208
20116
|
};
|
|
19209
20117
|
}, [emitSnapshot, resource, trackId, tracks]);
|
|
19210
|
-
|
|
20118
|
+
useEffect42(() => {
|
|
19211
20119
|
if (!captionsEnabled) {
|
|
19212
20120
|
setTrackId(null);
|
|
19213
20121
|
return;
|
|
@@ -19218,15 +20126,15 @@ function PanoVideo({
|
|
|
19218
20126
|
if (variants.length === 0) {
|
|
19219
20127
|
return null;
|
|
19220
20128
|
}
|
|
19221
|
-
return /* @__PURE__ */
|
|
19222
|
-
activeTexture ? /* @__PURE__ */
|
|
20129
|
+
return /* @__PURE__ */ jsxs23(Fragment7, { children: [
|
|
20130
|
+
activeTexture ? /* @__PURE__ */ jsxs23(
|
|
19223
20131
|
"mesh",
|
|
19224
20132
|
{
|
|
19225
20133
|
rotation: [0, MathUtils13.degToRad(90 + yawOffset2), 0],
|
|
19226
20134
|
visible,
|
|
19227
20135
|
children: [
|
|
19228
|
-
/* @__PURE__ */
|
|
19229
|
-
/* @__PURE__ */
|
|
20136
|
+
/* @__PURE__ */ jsx42("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
|
|
20137
|
+
/* @__PURE__ */ jsx42(
|
|
19230
20138
|
PanoBasicMaterial,
|
|
19231
20139
|
{
|
|
19232
20140
|
map: activeTexture,
|
|
@@ -19237,19 +20145,19 @@ function PanoVideo({
|
|
|
19237
20145
|
]
|
|
19238
20146
|
}
|
|
19239
20147
|
) : null,
|
|
19240
|
-
captionsEnabled ? /* @__PURE__ */
|
|
20148
|
+
captionsEnabled ? /* @__PURE__ */ jsx42(PanoVideoCaptions, { appearance: typeof captions === "object" ? captions : void 0 }) : null
|
|
19241
20149
|
] });
|
|
19242
20150
|
}
|
|
19243
20151
|
|
|
19244
20152
|
// src/map/pano-map.tsx
|
|
19245
20153
|
import {
|
|
19246
|
-
useCallback as
|
|
19247
|
-
useEffect as
|
|
19248
|
-
useId as
|
|
19249
|
-
useLayoutEffect as
|
|
19250
|
-
useMemo as
|
|
19251
|
-
useRef as
|
|
19252
|
-
useState as
|
|
20154
|
+
useCallback as useCallback13,
|
|
20155
|
+
useEffect as useEffect44,
|
|
20156
|
+
useId as useId4,
|
|
20157
|
+
useLayoutEffect as useLayoutEffect11,
|
|
20158
|
+
useMemo as useMemo30,
|
|
20159
|
+
useRef as useRef44,
|
|
20160
|
+
useState as useState28
|
|
19253
20161
|
} from "react";
|
|
19254
20162
|
|
|
19255
20163
|
// src/map/geometry.ts
|
|
@@ -19310,14 +20218,14 @@ function normalizeDegrees(value) {
|
|
|
19310
20218
|
}
|
|
19311
20219
|
|
|
19312
20220
|
// src/map/use-map-view.ts
|
|
19313
|
-
import { useContext as useContext29, useEffect as
|
|
20221
|
+
import { useContext as useContext29, useEffect as useEffect43, useRef as useRef43, useState as useState27 } from "react";
|
|
19314
20222
|
var DEFAULT_VIEW2 = { yaw: 0, pitch: 0, fov: 75 };
|
|
19315
20223
|
function useMapView(controlled) {
|
|
19316
20224
|
const eventBus = useContext29(PanoEventBusContext);
|
|
19317
|
-
const [view, setView] =
|
|
19318
|
-
const controlledRef =
|
|
20225
|
+
const [view, setView] = useState27(controlled ?? DEFAULT_VIEW2);
|
|
20226
|
+
const controlledRef = useRef43(controlled);
|
|
19319
20227
|
controlledRef.current = controlled;
|
|
19320
|
-
|
|
20228
|
+
useEffect43(() => {
|
|
19321
20229
|
if (controlled !== void 0) {
|
|
19322
20230
|
setView(controlled);
|
|
19323
20231
|
return;
|
|
@@ -19332,7 +20240,7 @@ function useMapView(controlled) {
|
|
|
19332
20240
|
}
|
|
19333
20241
|
|
|
19334
20242
|
// src/map/pano-map.tsx
|
|
19335
|
-
import { Fragment as Fragment8, jsx as
|
|
20243
|
+
import { Fragment as Fragment8, jsx as jsx43, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
19336
20244
|
var DEFAULT_ICON_SIZE2 = 28;
|
|
19337
20245
|
var DEFAULT_SECTOR_COLOR = "#ffffff";
|
|
19338
20246
|
var DEFAULT_SECTOR_OPACITY = 0.55;
|
|
@@ -19371,8 +20279,8 @@ function SectorShape({
|
|
|
19371
20279
|
...gradient.stops.map((stop) => stop.opacity ?? 1),
|
|
19372
20280
|
Number.EPSILON
|
|
19373
20281
|
) : 1;
|
|
19374
|
-
return /* @__PURE__ */
|
|
19375
|
-
gradient ? /* @__PURE__ */
|
|
20282
|
+
return /* @__PURE__ */ jsxs24("g", { ref: transformRef, transform: `rotate(${rotation})`, style: { pointerEvents: "none" }, children: [
|
|
20283
|
+
gradient ? /* @__PURE__ */ jsx43("defs", { children: gradient.type === "radial" ? /* @__PURE__ */ jsx43("radialGradient", { id: gradientId, cx: "0", cy: "0", r: radius, gradientUnits: "userSpaceOnUse", children: gradient.stops.map((stop, index) => /* @__PURE__ */ jsx43(
|
|
19376
20284
|
"stop",
|
|
19377
20285
|
{
|
|
19378
20286
|
offset: `${stop.offset * 100}%`,
|
|
@@ -19380,7 +20288,7 @@ function SectorShape({
|
|
|
19380
20288
|
stopOpacity: (stop.opacity ?? 1) / gradientStrength
|
|
19381
20289
|
},
|
|
19382
20290
|
`${stop.offset}:${index}`
|
|
19383
|
-
)) }) : /* @__PURE__ */
|
|
20291
|
+
)) }) : /* @__PURE__ */ jsx43(
|
|
19384
20292
|
"linearGradient",
|
|
19385
20293
|
{
|
|
19386
20294
|
id: gradientId,
|
|
@@ -19389,7 +20297,7 @@ function SectorShape({
|
|
|
19389
20297
|
x2: "0",
|
|
19390
20298
|
y2: -radius,
|
|
19391
20299
|
gradientUnits: "userSpaceOnUse",
|
|
19392
|
-
children: gradient.stops.map((stop, index) => /* @__PURE__ */
|
|
20300
|
+
children: gradient.stops.map((stop, index) => /* @__PURE__ */ jsx43(
|
|
19393
20301
|
"stop",
|
|
19394
20302
|
{
|
|
19395
20303
|
offset: `${stop.offset * 100}%`,
|
|
@@ -19400,7 +20308,7 @@ function SectorShape({
|
|
|
19400
20308
|
))
|
|
19401
20309
|
}
|
|
19402
20310
|
) }) : null,
|
|
19403
|
-
/* @__PURE__ */
|
|
20311
|
+
/* @__PURE__ */ jsx43(
|
|
19404
20312
|
"path",
|
|
19405
20313
|
{
|
|
19406
20314
|
d: path,
|
|
@@ -19420,7 +20328,7 @@ function SectorShape({
|
|
|
19420
20328
|
] });
|
|
19421
20329
|
}
|
|
19422
20330
|
function DefaultSpotIcon({ active, size }) {
|
|
19423
|
-
return /* @__PURE__ */
|
|
20331
|
+
return /* @__PURE__ */ jsxs24(
|
|
19424
20332
|
"svg",
|
|
19425
20333
|
{
|
|
19426
20334
|
width: size,
|
|
@@ -19429,7 +20337,7 @@ function DefaultSpotIcon({ active, size }) {
|
|
|
19429
20337
|
"aria-hidden": "true",
|
|
19430
20338
|
style: { display: "block" },
|
|
19431
20339
|
children: [
|
|
19432
|
-
/* @__PURE__ */
|
|
20340
|
+
/* @__PURE__ */ jsx43(
|
|
19433
20341
|
"rect",
|
|
19434
20342
|
{
|
|
19435
20343
|
x: "3",
|
|
@@ -19442,8 +20350,8 @@ function DefaultSpotIcon({ active, size }) {
|
|
|
19442
20350
|
strokeWidth: "2"
|
|
19443
20351
|
}
|
|
19444
20352
|
),
|
|
19445
|
-
/* @__PURE__ */
|
|
19446
|
-
/* @__PURE__ */
|
|
20353
|
+
/* @__PURE__ */ jsx43("circle", { cx: "16", cy: "16", r: "5", fill: "none", stroke: "rgba(255,255,255,0.92)", strokeWidth: "2" }),
|
|
20354
|
+
/* @__PURE__ */ jsx43("circle", { cx: "16", cy: "16", r: "2", fill: active ? "#ef4444" : "rgba(255,255,255,0.85)" })
|
|
19447
20355
|
]
|
|
19448
20356
|
}
|
|
19449
20357
|
);
|
|
@@ -19464,38 +20372,51 @@ function PanoMap({
|
|
|
19464
20372
|
showCollapseControl,
|
|
19465
20373
|
collapsed: controlledCollapsed,
|
|
19466
20374
|
onCollapsedChange,
|
|
19467
|
-
renderChrome
|
|
20375
|
+
renderChrome,
|
|
20376
|
+
initialScale
|
|
19468
20377
|
}) {
|
|
19469
|
-
const reactId =
|
|
20378
|
+
const reactId = useId4().replace(/:/g, "");
|
|
19470
20379
|
const view = useMapView(controlledView);
|
|
19471
|
-
const rootRef =
|
|
19472
|
-
const containerRef =
|
|
19473
|
-
const sectorNodeRef =
|
|
19474
|
-
const yawRef =
|
|
19475
|
-
const [size, setSize] =
|
|
19476
|
-
const [imageSize2, setImageSize] =
|
|
19477
|
-
const [scale, setScale] =
|
|
19478
|
-
const [pan, setPan] =
|
|
19479
|
-
const [uncontrolledCollapsed, setUncontrolledCollapsed] =
|
|
19480
|
-
const dragRef =
|
|
20380
|
+
const rootRef = useRef44(null);
|
|
20381
|
+
const containerRef = useRef44(null);
|
|
20382
|
+
const sectorNodeRef = useRef44(null);
|
|
20383
|
+
const yawRef = useRef44(view.yaw);
|
|
20384
|
+
const [size, setSize] = useState28({ width: 0, height: 0 });
|
|
20385
|
+
const [imageSize2, setImageSize] = useState28({ width: 0, height: 0 });
|
|
20386
|
+
const [scale, setScale] = useState28(1);
|
|
20387
|
+
const [pan, setPan] = useState28({ x: 0, y: 0 });
|
|
20388
|
+
const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState28(false);
|
|
20389
|
+
const dragRef = useRef44(null);
|
|
20390
|
+
const panAnimRef = useRef44(null);
|
|
20391
|
+
const panRef = useRef44(pan);
|
|
20392
|
+
const scaleRef = useRef44(scale);
|
|
20393
|
+
const initialViewKeyRef = useRef44(null);
|
|
19481
20394
|
const spots = map.spots;
|
|
19482
20395
|
const iconSize = map.iconSize ?? DEFAULT_ICON_SIZE2;
|
|
19483
20396
|
const interaction = map.interaction ?? "fixed";
|
|
19484
20397
|
const gestureZoom = interaction === "zoom";
|
|
20398
|
+
const dragMotion = resolveDragMotion(map.dragMotion);
|
|
19485
20399
|
const maxScale = Math.max(MIN_SCALE, map.maxScale ?? DEFAULT_MAX_SCALE);
|
|
20400
|
+
const resolvedInitialScale = Math.min(
|
|
20401
|
+
maxScale,
|
|
20402
|
+
Math.max(
|
|
20403
|
+
MIN_SCALE,
|
|
20404
|
+
Number.isFinite(initialScale) ? initialScale : MIN_SCALE
|
|
20405
|
+
)
|
|
20406
|
+
);
|
|
19486
20407
|
const zoomControls = gestureZoom && (showZoomControls ?? map.controls?.zoom === true);
|
|
19487
20408
|
const collapseControl = showCollapseControl ?? map.controls?.collapse === true;
|
|
19488
20409
|
const collapsed = controlledCollapsed ?? uncontrolledCollapsed;
|
|
19489
20410
|
const editing = mode === "edit";
|
|
19490
|
-
const fit =
|
|
20411
|
+
const fit = useMemo30(
|
|
19491
20412
|
() => containRect(size.width, size.height, imageSize2.width, imageSize2.height),
|
|
19492
20413
|
[size, imageSize2]
|
|
19493
20414
|
);
|
|
19494
|
-
const viewport =
|
|
20415
|
+
const viewport = useMemo30(
|
|
19495
20416
|
() => ({ fit, scale, panX: pan.x, panY: pan.y }),
|
|
19496
20417
|
[fit, scale, pan]
|
|
19497
20418
|
);
|
|
19498
|
-
|
|
20419
|
+
useLayoutEffect11(() => {
|
|
19499
20420
|
if (collapsed) return;
|
|
19500
20421
|
const node = containerRef.current;
|
|
19501
20422
|
if (!node) return;
|
|
@@ -19512,7 +20433,7 @@ function PanoMap({
|
|
|
19512
20433
|
observer.observe(node);
|
|
19513
20434
|
return () => observer.disconnect();
|
|
19514
20435
|
}, [collapsed]);
|
|
19515
|
-
|
|
20436
|
+
useEffect44(() => {
|
|
19516
20437
|
yawRef.current = view.yaw;
|
|
19517
20438
|
const node = sectorNodeRef.current;
|
|
19518
20439
|
if (!node) return;
|
|
@@ -19527,24 +20448,108 @@ function PanoMap({
|
|
|
19527
20448
|
onCollapsedChange?.(next);
|
|
19528
20449
|
if (controlledCollapsed === void 0) setUncontrolledCollapsed(next);
|
|
19529
20450
|
};
|
|
19530
|
-
|
|
19531
|
-
|
|
20451
|
+
panRef.current = pan;
|
|
20452
|
+
scaleRef.current = scale;
|
|
20453
|
+
const panBoundsFor = useCallback13(
|
|
20454
|
+
(nextScale) => {
|
|
19532
20455
|
const width = fit.width * nextScale;
|
|
19533
20456
|
const height = fit.height * nextScale;
|
|
19534
|
-
if (!(fit.width > 0) || !(fit.height > 0))
|
|
19535
|
-
|
|
19536
|
-
|
|
19537
|
-
const minY = Math.min(0, size.height - (fit.top + height));
|
|
19538
|
-
const maxY = Math.max(0, -fit.top);
|
|
20457
|
+
if (!(fit.width > 0) || !(fit.height > 0)) {
|
|
20458
|
+
return { minX: 0, maxX: 0, minY: 0, maxY: 0 };
|
|
20459
|
+
}
|
|
19539
20460
|
return {
|
|
19540
|
-
|
|
19541
|
-
|
|
20461
|
+
minX: Math.min(0, size.width - (fit.left + width)),
|
|
20462
|
+
maxX: Math.max(0, -fit.left),
|
|
20463
|
+
minY: Math.min(0, size.height - (fit.top + height)),
|
|
20464
|
+
maxY: Math.max(0, -fit.top)
|
|
19542
20465
|
};
|
|
19543
20466
|
},
|
|
19544
20467
|
[fit, size]
|
|
19545
20468
|
);
|
|
19546
|
-
|
|
20469
|
+
const clampPan = useCallback13(
|
|
20470
|
+
(nextScale, nextPan) => {
|
|
20471
|
+
const bounds = panBoundsFor(nextScale);
|
|
20472
|
+
return {
|
|
20473
|
+
x: Math.min(bounds.maxX, Math.max(bounds.minX, nextPan.x)),
|
|
20474
|
+
y: Math.min(bounds.maxY, Math.max(bounds.minY, nextPan.y))
|
|
20475
|
+
};
|
|
20476
|
+
},
|
|
20477
|
+
[panBoundsFor]
|
|
20478
|
+
);
|
|
20479
|
+
const cancelPanAnimation = useCallback13(() => {
|
|
20480
|
+
const anim = panAnimRef.current;
|
|
20481
|
+
if (anim?.raf != null) {
|
|
20482
|
+
cancelAnimationFrame(anim.raf);
|
|
20483
|
+
}
|
|
20484
|
+
panAnimRef.current = null;
|
|
20485
|
+
}, []);
|
|
20486
|
+
const startPanAnimation = useCallback13(
|
|
20487
|
+
(velocity) => {
|
|
20488
|
+
cancelPanAnimation();
|
|
20489
|
+
const current = panRef.current;
|
|
20490
|
+
const currentScale = scaleRef.current;
|
|
20491
|
+
const bounds = panBoundsFor(currentScale);
|
|
20492
|
+
const needsSpring = dragMotion.bounce && (current.x < bounds.minX || current.x > bounds.maxX || current.y < bounds.minY || current.y > bounds.maxY);
|
|
20493
|
+
const vx = dragMotion.inertia ? velocity.x : 0;
|
|
20494
|
+
const vy = dragMotion.inertia ? velocity.y : 0;
|
|
20495
|
+
if (!needsSpring && Math.abs(vx) < 1 && Math.abs(vy) < 1) {
|
|
20496
|
+
setPan(clampPan(currentScale, current));
|
|
20497
|
+
return;
|
|
20498
|
+
}
|
|
20499
|
+
if (!dragMotion.inertia && !dragMotion.bounce) {
|
|
20500
|
+
setPan(clampPan(currentScale, current));
|
|
20501
|
+
return;
|
|
20502
|
+
}
|
|
20503
|
+
const anim = {
|
|
20504
|
+
raf: null,
|
|
20505
|
+
lastTime: performance.now(),
|
|
20506
|
+
x: { position: current.x, velocity: vx },
|
|
20507
|
+
y: { position: current.y, velocity: vy }
|
|
20508
|
+
};
|
|
20509
|
+
panAnimRef.current = anim;
|
|
20510
|
+
const tick = (now) => {
|
|
20511
|
+
if (panAnimRef.current !== anim) return;
|
|
20512
|
+
const dt = Math.min(0.064, Math.max(0, (now - anim.lastTime) / 1e3));
|
|
20513
|
+
anim.lastTime = now;
|
|
20514
|
+
const liveBounds = panBoundsFor(scaleRef.current);
|
|
20515
|
+
const nextX = integrateAxis(anim.x, dt, {
|
|
20516
|
+
min: liveBounds.minX,
|
|
20517
|
+
max: liveBounds.maxX,
|
|
20518
|
+
inertia: dragMotion.inertia,
|
|
20519
|
+
bounce: dragMotion.bounce
|
|
20520
|
+
});
|
|
20521
|
+
const nextY = integrateAxis(anim.y, dt, {
|
|
20522
|
+
min: liveBounds.minY,
|
|
20523
|
+
max: liveBounds.maxY,
|
|
20524
|
+
inertia: dragMotion.inertia,
|
|
20525
|
+
bounce: dragMotion.bounce
|
|
20526
|
+
});
|
|
20527
|
+
anim.x = { position: nextX.position, velocity: nextX.velocity };
|
|
20528
|
+
anim.y = { position: nextY.position, velocity: nextY.velocity };
|
|
20529
|
+
setPan({ x: nextX.position, y: nextY.position });
|
|
20530
|
+
if (nextX.settled && nextY.settled) {
|
|
20531
|
+
setPan(
|
|
20532
|
+
clampPan(scaleRef.current, {
|
|
20533
|
+
x: nextX.position,
|
|
20534
|
+
y: nextY.position
|
|
20535
|
+
})
|
|
20536
|
+
);
|
|
20537
|
+
panAnimRef.current = null;
|
|
20538
|
+
return;
|
|
20539
|
+
}
|
|
20540
|
+
anim.raf = requestAnimationFrame(tick);
|
|
20541
|
+
};
|
|
20542
|
+
anim.raf = requestAnimationFrame(tick);
|
|
20543
|
+
},
|
|
20544
|
+
[cancelPanAnimation, clampPan, dragMotion.bounce, dragMotion.inertia, panBoundsFor]
|
|
20545
|
+
);
|
|
20546
|
+
useEffect44(() => () => cancelPanAnimation(), [cancelPanAnimation]);
|
|
20547
|
+
useEffect44(() => {
|
|
20548
|
+
if (collapsed) cancelPanAnimation();
|
|
20549
|
+
}, [cancelPanAnimation, collapsed]);
|
|
20550
|
+
useEffect44(() => {
|
|
19547
20551
|
if (!gestureZoom) {
|
|
20552
|
+
initialViewKeyRef.current = null;
|
|
19548
20553
|
setScale(1);
|
|
19549
20554
|
setPan({ x: 0, y: 0 });
|
|
19550
20555
|
return;
|
|
@@ -19557,9 +20562,37 @@ function PanoMap({
|
|
|
19557
20562
|
return next;
|
|
19558
20563
|
});
|
|
19559
20564
|
}, [clampPan, gestureZoom, maxScale]);
|
|
19560
|
-
|
|
20565
|
+
useEffect44(() => {
|
|
20566
|
+
if (!gestureZoom) return;
|
|
20567
|
+
if (!(fit.width > 0) || !(fit.height > 0)) return;
|
|
20568
|
+
if (!(size.width > 0) || !(size.height > 0)) return;
|
|
20569
|
+
const key = `${interaction}:${initialScale ?? MIN_SCALE}`;
|
|
20570
|
+
if (initialViewKeyRef.current === key) return;
|
|
20571
|
+
initialViewKeyRef.current = key;
|
|
20572
|
+
const pivot = { x: size.width / 2, y: size.height / 2 };
|
|
20573
|
+
const nextPan = {
|
|
20574
|
+
x: pivot.x - (pivot.x - fit.left) * resolvedInitialScale - fit.left,
|
|
20575
|
+
y: pivot.y - (pivot.y - fit.top) * resolvedInitialScale - fit.top
|
|
20576
|
+
};
|
|
20577
|
+
setScale(resolvedInitialScale);
|
|
20578
|
+
setPan(clampPan(resolvedInitialScale, nextPan));
|
|
20579
|
+
}, [
|
|
20580
|
+
clampPan,
|
|
20581
|
+
fit.height,
|
|
20582
|
+
fit.left,
|
|
20583
|
+
fit.top,
|
|
20584
|
+
fit.width,
|
|
20585
|
+
gestureZoom,
|
|
20586
|
+
initialScale,
|
|
20587
|
+
interaction,
|
|
20588
|
+
resolvedInitialScale,
|
|
20589
|
+
size.height,
|
|
20590
|
+
size.width
|
|
20591
|
+
]);
|
|
20592
|
+
const applyZoom = useCallback13(
|
|
19561
20593
|
(nextScale, origin) => {
|
|
19562
20594
|
if (!gestureZoom) return;
|
|
20595
|
+
cancelPanAnimation();
|
|
19563
20596
|
const clamped = Math.min(maxScale, Math.max(MIN_SCALE, nextScale));
|
|
19564
20597
|
const pivot = origin ?? { x: size.width / 2, y: size.height / 2 };
|
|
19565
20598
|
const ratio = clamped / scale;
|
|
@@ -19571,6 +20604,7 @@ function PanoMap({
|
|
|
19571
20604
|
setPan(clampPan(clamped, nextPan));
|
|
19572
20605
|
},
|
|
19573
20606
|
[
|
|
20607
|
+
cancelPanAnimation,
|
|
19574
20608
|
clampPan,
|
|
19575
20609
|
fit.left,
|
|
19576
20610
|
fit.top,
|
|
@@ -19583,7 +20617,7 @@ function PanoMap({
|
|
|
19583
20617
|
size.width
|
|
19584
20618
|
]
|
|
19585
20619
|
);
|
|
19586
|
-
|
|
20620
|
+
useEffect44(() => {
|
|
19587
20621
|
const root = rootRef.current;
|
|
19588
20622
|
if (!root) return;
|
|
19589
20623
|
const onWheel = (event) => {
|
|
@@ -19635,15 +20669,22 @@ function PanoMap({
|
|
|
19635
20669
|
return;
|
|
19636
20670
|
}
|
|
19637
20671
|
if (gestureZoom && scale > 1) {
|
|
20672
|
+
cancelPanAnimation();
|
|
20673
|
+
const now = performance.now();
|
|
19638
20674
|
dragRef.current = {
|
|
19639
20675
|
kind: "pan",
|
|
19640
20676
|
pointerId: event.pointerId,
|
|
19641
20677
|
originX: point.x,
|
|
19642
20678
|
originY: point.y,
|
|
19643
20679
|
panX: pan.x,
|
|
19644
|
-
panY: pan.y
|
|
20680
|
+
panY: pan.y,
|
|
20681
|
+
samplesX: [{ t: now, position: pan.x }],
|
|
20682
|
+
samplesY: [{ t: now, position: pan.y }]
|
|
19645
20683
|
};
|
|
19646
|
-
|
|
20684
|
+
try {
|
|
20685
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
20686
|
+
} catch {
|
|
20687
|
+
}
|
|
19647
20688
|
event.preventDefault();
|
|
19648
20689
|
event.stopPropagation();
|
|
19649
20690
|
}
|
|
@@ -19654,12 +20695,28 @@ function PanoMap({
|
|
|
19654
20695
|
const point = localPoint(event);
|
|
19655
20696
|
if (!point) return;
|
|
19656
20697
|
if (drag.kind === "pan") {
|
|
19657
|
-
|
|
19658
|
-
|
|
19659
|
-
|
|
19660
|
-
|
|
19661
|
-
|
|
19662
|
-
);
|
|
20698
|
+
const rawX = drag.panX + (point.x - drag.originX);
|
|
20699
|
+
const rawY = drag.panY + (point.y - drag.originY);
|
|
20700
|
+
const bounds = panBoundsFor(scale);
|
|
20701
|
+
const now = performance.now();
|
|
20702
|
+
drag.samplesX = pushSample(drag.samplesX, { t: now, position: rawX });
|
|
20703
|
+
drag.samplesY = pushSample(drag.samplesY, { t: now, position: rawY });
|
|
20704
|
+
setPan({
|
|
20705
|
+
x: constrainDragPosition(
|
|
20706
|
+
rawX,
|
|
20707
|
+
bounds.minX,
|
|
20708
|
+
bounds.maxX,
|
|
20709
|
+
size.width,
|
|
20710
|
+
dragMotion.bounce
|
|
20711
|
+
),
|
|
20712
|
+
y: constrainDragPosition(
|
|
20713
|
+
rawY,
|
|
20714
|
+
bounds.minY,
|
|
20715
|
+
bounds.maxY,
|
|
20716
|
+
size.height,
|
|
20717
|
+
dragMotion.bounce
|
|
20718
|
+
)
|
|
20719
|
+
});
|
|
19663
20720
|
event.preventDefault();
|
|
19664
20721
|
event.stopPropagation();
|
|
19665
20722
|
return;
|
|
@@ -19700,11 +20757,24 @@ function PanoMap({
|
|
|
19700
20757
|
event.stopPropagation();
|
|
19701
20758
|
};
|
|
19702
20759
|
const endDrag = (event) => {
|
|
19703
|
-
|
|
20760
|
+
const drag = dragRef.current;
|
|
20761
|
+
if (drag?.pointerId !== event.pointerId) return;
|
|
19704
20762
|
dragRef.current = null;
|
|
19705
|
-
|
|
19706
|
-
event.currentTarget.
|
|
20763
|
+
try {
|
|
20764
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
20765
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
20766
|
+
}
|
|
20767
|
+
} catch {
|
|
19707
20768
|
}
|
|
20769
|
+
if (drag.kind !== "pan") return;
|
|
20770
|
+
if (event.type === "pointercancel") {
|
|
20771
|
+
setPan(clampPan(scale, panRef.current));
|
|
20772
|
+
return;
|
|
20773
|
+
}
|
|
20774
|
+
startPanAnimation({
|
|
20775
|
+
x: velocityFromSamples(drag.samplesX),
|
|
20776
|
+
y: velocityFromSamples(drag.samplesY)
|
|
20777
|
+
});
|
|
19708
20778
|
};
|
|
19709
20779
|
const sectorAngle = (() => {
|
|
19710
20780
|
if (!map.sector) return 0;
|
|
@@ -19714,8 +20784,8 @@ function PanoMap({
|
|
|
19714
20784
|
})();
|
|
19715
20785
|
const activeSpot = spots.find((spot) => spot.sceneId === activeSceneId);
|
|
19716
20786
|
const selectedSpot = spots.find((spot) => spot.id === selectedSpotId);
|
|
19717
|
-
const controls = /* @__PURE__ */
|
|
19718
|
-
collapseControl ? /* @__PURE__ */
|
|
20787
|
+
const controls = /* @__PURE__ */ jsxs24("div", { className: "pano-map-controls", style: { pointerEvents: "auto" }, children: [
|
|
20788
|
+
collapseControl ? /* @__PURE__ */ jsx43(
|
|
19719
20789
|
"button",
|
|
19720
20790
|
{
|
|
19721
20791
|
type: "button",
|
|
@@ -19731,8 +20801,8 @@ function PanoMap({
|
|
|
19731
20801
|
children: collapsed ? "\u25A3" : "\u25A2"
|
|
19732
20802
|
}
|
|
19733
20803
|
) : null,
|
|
19734
|
-
zoomControls && !collapsed ? /* @__PURE__ */
|
|
19735
|
-
/* @__PURE__ */
|
|
20804
|
+
zoomControls && !collapsed ? /* @__PURE__ */ jsxs24(Fragment8, { children: [
|
|
20805
|
+
/* @__PURE__ */ jsx43(
|
|
19736
20806
|
"button",
|
|
19737
20807
|
{
|
|
19738
20808
|
type: "button",
|
|
@@ -19747,7 +20817,7 @@ function PanoMap({
|
|
|
19747
20817
|
children: "+"
|
|
19748
20818
|
}
|
|
19749
20819
|
),
|
|
19750
|
-
/* @__PURE__ */
|
|
20820
|
+
/* @__PURE__ */ jsx43(
|
|
19751
20821
|
"button",
|
|
19752
20822
|
{
|
|
19753
20823
|
type: "button",
|
|
@@ -19770,7 +20840,7 @@ function PanoMap({
|
|
|
19770
20840
|
(previous) => previous.width === image.naturalWidth && previous.height === image.naturalHeight ? previous : { width: image.naturalWidth, height: image.naturalHeight }
|
|
19771
20841
|
);
|
|
19772
20842
|
};
|
|
19773
|
-
return /* @__PURE__ */
|
|
20843
|
+
return /* @__PURE__ */ jsxs24(
|
|
19774
20844
|
"div",
|
|
19775
20845
|
{
|
|
19776
20846
|
ref: rootRef,
|
|
@@ -19788,8 +20858,8 @@ function PanoMap({
|
|
|
19788
20858
|
"data-mode": mode,
|
|
19789
20859
|
"data-collapsed": collapsed ? "true" : void 0,
|
|
19790
20860
|
children: [
|
|
19791
|
-
renderChrome ? renderChrome(controls) : /* @__PURE__ */
|
|
19792
|
-
/* @__PURE__ */
|
|
20861
|
+
renderChrome ? renderChrome(controls) : /* @__PURE__ */ jsx43("div", { className: "pano-map-chrome", children: controls }),
|
|
20862
|
+
/* @__PURE__ */ jsxs24(
|
|
19793
20863
|
"div",
|
|
19794
20864
|
{
|
|
19795
20865
|
ref: containerRef,
|
|
@@ -19806,7 +20876,7 @@ function PanoMap({
|
|
|
19806
20876
|
onPointerUp: endDrag,
|
|
19807
20877
|
onPointerCancel: endDrag,
|
|
19808
20878
|
children: [
|
|
19809
|
-
fit.width > 0 && fit.height > 0 ? /* @__PURE__ */
|
|
20879
|
+
fit.width > 0 && fit.height > 0 ? /* @__PURE__ */ jsx43(
|
|
19810
20880
|
"div",
|
|
19811
20881
|
{
|
|
19812
20882
|
className: "pano-map-image-layer",
|
|
@@ -19818,7 +20888,7 @@ function PanoMap({
|
|
|
19818
20888
|
height: fit.height * scale,
|
|
19819
20889
|
transformOrigin: "0 0"
|
|
19820
20890
|
},
|
|
19821
|
-
children: /* @__PURE__ */
|
|
20891
|
+
children: /* @__PURE__ */ jsx43(
|
|
19822
20892
|
"img",
|
|
19823
20893
|
{
|
|
19824
20894
|
src: map.image,
|
|
@@ -19840,7 +20910,7 @@ function PanoMap({
|
|
|
19840
20910
|
}
|
|
19841
20911
|
)
|
|
19842
20912
|
}
|
|
19843
|
-
) : /* @__PURE__ */
|
|
20913
|
+
) : /* @__PURE__ */ jsx43(
|
|
19844
20914
|
"img",
|
|
19845
20915
|
{
|
|
19846
20916
|
src: map.image,
|
|
@@ -19854,7 +20924,7 @@ function PanoMap({
|
|
|
19854
20924
|
}
|
|
19855
20925
|
}
|
|
19856
20926
|
),
|
|
19857
|
-
activeSpot && map.sector ? /* @__PURE__ */
|
|
20927
|
+
activeSpot && map.sector ? /* @__PURE__ */ jsx43(
|
|
19858
20928
|
"svg",
|
|
19859
20929
|
{
|
|
19860
20930
|
className: "pano-map-sector-layer",
|
|
@@ -19866,11 +20936,11 @@ function PanoMap({
|
|
|
19866
20936
|
overflow: "visible",
|
|
19867
20937
|
pointerEvents: "none"
|
|
19868
20938
|
},
|
|
19869
|
-
children: /* @__PURE__ */
|
|
20939
|
+
children: /* @__PURE__ */ jsx43(
|
|
19870
20940
|
"g",
|
|
19871
20941
|
{
|
|
19872
20942
|
transform: `translate(${imagePointToContainer(activeSpot, viewport).x} ${imagePointToContainer(activeSpot, viewport).y})`,
|
|
19873
|
-
children: /* @__PURE__ */
|
|
20943
|
+
children: /* @__PURE__ */ jsx43(
|
|
19874
20944
|
SectorShape,
|
|
19875
20945
|
{
|
|
19876
20946
|
sector: map.sector,
|
|
@@ -19902,7 +20972,7 @@ function PanoMap({
|
|
|
19902
20972
|
const point = imagePointToContainer(spot, viewport);
|
|
19903
20973
|
const active = spot.sceneId === activeSceneId;
|
|
19904
20974
|
const selected = spot.id === selectedSpotId;
|
|
19905
|
-
return /* @__PURE__ */
|
|
20975
|
+
return /* @__PURE__ */ jsx43(
|
|
19906
20976
|
"button",
|
|
19907
20977
|
{
|
|
19908
20978
|
type: "button",
|
|
@@ -19947,7 +21017,7 @@ function PanoMap({
|
|
|
19947
21017
|
if (editing) return;
|
|
19948
21018
|
onSelectScene?.(spot.sceneId, spot);
|
|
19949
21019
|
},
|
|
19950
|
-
children: spot.icon ? /* @__PURE__ */
|
|
21020
|
+
children: spot.icon ? /* @__PURE__ */ jsx43(
|
|
19951
21021
|
"img",
|
|
19952
21022
|
{
|
|
19953
21023
|
src: spot.icon,
|
|
@@ -19955,7 +21025,7 @@ function PanoMap({
|
|
|
19955
21025
|
draggable: false,
|
|
19956
21026
|
style: { width: "100%", height: "100%", display: "block", pointerEvents: "none" }
|
|
19957
21027
|
}
|
|
19958
|
-
) : /* @__PURE__ */
|
|
21028
|
+
) : /* @__PURE__ */ jsx43(DefaultSpotIcon, { active, size: iconSize })
|
|
19959
21029
|
},
|
|
19960
21030
|
spot.id
|
|
19961
21031
|
);
|
|
@@ -19970,13 +21040,15 @@ function PanoMap({
|
|
|
19970
21040
|
|
|
19971
21041
|
// src/map/pano-map-overlay.tsx
|
|
19972
21042
|
import {
|
|
19973
|
-
useEffect as
|
|
19974
|
-
useId as
|
|
19975
|
-
useMemo as
|
|
19976
|
-
useRef as
|
|
19977
|
-
useState as
|
|
21043
|
+
useEffect as useEffect45,
|
|
21044
|
+
useId as useId5,
|
|
21045
|
+
useMemo as useMemo31,
|
|
21046
|
+
useRef as useRef45,
|
|
21047
|
+
useState as useState29
|
|
19978
21048
|
} from "react";
|
|
19979
|
-
import { Fragment as Fragment9, jsx as
|
|
21049
|
+
import { Fragment as Fragment9, jsx as jsx44, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
21050
|
+
var DEFAULT_DIALOG_WIDTH = 720;
|
|
21051
|
+
var DEFAULT_DIALOG_HEIGHT = 520;
|
|
19980
21052
|
function dockedBox(corner, offsetX, offsetY, width, height) {
|
|
19981
21053
|
const horizontal = corner === "top-right" || corner === "bottom-right" ? { left: "auto", right: offsetX } : { left: offsetX, right: "auto" };
|
|
19982
21054
|
const vertical = corner === "bottom-left" || corner === "bottom-right" ? { top: "auto", bottom: offsetY } : { top: offsetY, bottom: "auto" };
|
|
@@ -19987,14 +21059,16 @@ function PanoMapDialogShell({
|
|
|
19987
21059
|
onOpenChange,
|
|
19988
21060
|
title,
|
|
19989
21061
|
closeLabel,
|
|
21062
|
+
dialogWidth,
|
|
21063
|
+
dialogHeight,
|
|
19990
21064
|
children
|
|
19991
21065
|
}) {
|
|
19992
21066
|
usePanoModal(open);
|
|
19993
21067
|
const { size } = usePanoOverlay();
|
|
19994
|
-
const titleId =
|
|
19995
|
-
const panelRef =
|
|
19996
|
-
const previouslyFocused =
|
|
19997
|
-
|
|
21068
|
+
const titleId = useId5();
|
|
21069
|
+
const panelRef = useRef45(null);
|
|
21070
|
+
const previouslyFocused = useRef45(null);
|
|
21071
|
+
useEffect45(() => {
|
|
19998
21072
|
if (!open) return;
|
|
19999
21073
|
const active = panelRef.current?.ownerDocument.activeElement;
|
|
20000
21074
|
previouslyFocused.current = active instanceof HTMLElement ? active : null;
|
|
@@ -20016,12 +21090,14 @@ function PanoMapDialogShell({
|
|
|
20016
21090
|
};
|
|
20017
21091
|
}, [open, onOpenChange]);
|
|
20018
21092
|
if (!open) return null;
|
|
20019
|
-
const
|
|
20020
|
-
const
|
|
21093
|
+
const preferredWidth = Number.isFinite(dialogWidth) && dialogWidth > 0 ? dialogWidth : DEFAULT_DIALOG_WIDTH;
|
|
21094
|
+
const preferredHeight = Number.isFinite(dialogHeight) && dialogHeight > 0 ? dialogHeight : DEFAULT_DIALOG_HEIGHT;
|
|
21095
|
+
const width = Math.min(preferredWidth, Math.max(0, size.width - 32));
|
|
21096
|
+
const height = Math.min(preferredHeight, Math.max(0, size.height - 32));
|
|
20021
21097
|
const left = Math.max(0, (size.width - width) / 2);
|
|
20022
21098
|
const top = Math.max(0, (size.height - height) / 2);
|
|
20023
|
-
return /* @__PURE__ */
|
|
20024
|
-
/* @__PURE__ */
|
|
21099
|
+
return /* @__PURE__ */ jsxs25(Fragment9, { children: [
|
|
21100
|
+
/* @__PURE__ */ jsx44(
|
|
20025
21101
|
"div",
|
|
20026
21102
|
{
|
|
20027
21103
|
className: "pano-map-dialog-backdrop",
|
|
@@ -20034,7 +21110,7 @@ function PanoMapDialogShell({
|
|
|
20034
21110
|
onClick: () => onOpenChange(false)
|
|
20035
21111
|
}
|
|
20036
21112
|
),
|
|
20037
|
-
/* @__PURE__ */
|
|
21113
|
+
/* @__PURE__ */ jsxs25(
|
|
20038
21114
|
"div",
|
|
20039
21115
|
{
|
|
20040
21116
|
ref: panelRef,
|
|
@@ -20057,9 +21133,9 @@ function PanoMapDialogShell({
|
|
|
20057
21133
|
zIndex: 1
|
|
20058
21134
|
},
|
|
20059
21135
|
children: [
|
|
20060
|
-
/* @__PURE__ */
|
|
20061
|
-
/* @__PURE__ */
|
|
20062
|
-
/* @__PURE__ */
|
|
21136
|
+
/* @__PURE__ */ jsxs25("header", { className: "pano-map-dialog-header", style: { flexShrink: 0 }, children: [
|
|
21137
|
+
/* @__PURE__ */ jsx44("h2", { id: titleId, className: "pano-map-dialog-title", children: title }),
|
|
21138
|
+
/* @__PURE__ */ jsx44(
|
|
20063
21139
|
"button",
|
|
20064
21140
|
{
|
|
20065
21141
|
type: "button",
|
|
@@ -20067,11 +21143,11 @@ function PanoMapDialogShell({
|
|
|
20067
21143
|
"data-pano-map-dialog-close": "",
|
|
20068
21144
|
"aria-label": closeLabel,
|
|
20069
21145
|
onClick: () => onOpenChange(false),
|
|
20070
|
-
children: /* @__PURE__ */
|
|
21146
|
+
children: /* @__PURE__ */ jsx44("svg", { "aria-hidden": "true", width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsx44("path", { d: "m4 4 8 8M12 4l-8 8" }) })
|
|
20071
21147
|
}
|
|
20072
21148
|
)
|
|
20073
21149
|
] }),
|
|
20074
|
-
/* @__PURE__ */
|
|
21150
|
+
/* @__PURE__ */ jsx44("div", { className: "pano-map-dialog-body", style: { minHeight: 0, flex: 1 }, children })
|
|
20075
21151
|
]
|
|
20076
21152
|
}
|
|
20077
21153
|
)
|
|
@@ -20088,6 +21164,20 @@ function PanoMapOverlay({
|
|
|
20088
21164
|
onEditChange,
|
|
20089
21165
|
placementSceneId,
|
|
20090
21166
|
presentationOverride,
|
|
21167
|
+
presentation: presentationModeProp,
|
|
21168
|
+
corner: cornerProp,
|
|
21169
|
+
width: widthProp,
|
|
21170
|
+
height: heightProp,
|
|
21171
|
+
offsetX: offsetXProp,
|
|
21172
|
+
offsetY: offsetYProp,
|
|
21173
|
+
dialogWidth = DEFAULT_DIALOG_WIDTH,
|
|
21174
|
+
dialogHeight = DEFAULT_DIALOG_HEIGHT,
|
|
21175
|
+
interaction,
|
|
21176
|
+
maxScale,
|
|
21177
|
+
initialScale,
|
|
21178
|
+
showZoomControls,
|
|
21179
|
+
showCollapseControl,
|
|
21180
|
+
iconSize,
|
|
20091
21181
|
openLabel = "Map",
|
|
20092
21182
|
closeLabel = "Close",
|
|
20093
21183
|
title = "Map",
|
|
@@ -20096,9 +21186,9 @@ function PanoMapOverlay({
|
|
|
20096
21186
|
editorSurface = false
|
|
20097
21187
|
}) {
|
|
20098
21188
|
const { size } = usePanoOverlay();
|
|
20099
|
-
const [open, setOpen] =
|
|
20100
|
-
const [collapsed, setCollapsed] =
|
|
20101
|
-
const
|
|
21189
|
+
const [open, setOpen] = useState29(false);
|
|
21190
|
+
const [collapsed, setCollapsed] = useState29(false);
|
|
21191
|
+
const basePresentation = presentationOverride ?? map.presentation ?? {
|
|
20102
21192
|
mode: "docked",
|
|
20103
21193
|
corner: "bottom-left",
|
|
20104
21194
|
width: 220,
|
|
@@ -20106,13 +21196,25 @@ function PanoMapOverlay({
|
|
|
20106
21196
|
offsetX: 16,
|
|
20107
21197
|
offsetY: 16
|
|
20108
21198
|
};
|
|
20109
|
-
const
|
|
20110
|
-
const
|
|
20111
|
-
const
|
|
20112
|
-
const
|
|
20113
|
-
const
|
|
21199
|
+
const presentationMode = presentationModeProp ?? basePresentation.mode;
|
|
21200
|
+
const corner = cornerProp ?? basePresentation.corner ?? "bottom-left";
|
|
21201
|
+
const offsetX = offsetXProp ?? basePresentation.offsetX ?? 16;
|
|
21202
|
+
const offsetY = offsetYProp ?? basePresentation.offsetY ?? 16;
|
|
21203
|
+
const width = widthProp ?? basePresentation.width ?? (presentationMode === "dialog" ? 48 : 220);
|
|
21204
|
+
const height = heightProp ?? basePresentation.height ?? (presentationMode === "dialog" ? 48 : 160);
|
|
21205
|
+
const resolvedMap = useMemo31(() => {
|
|
21206
|
+
if (interaction === void 0 && maxScale === void 0 && iconSize === void 0) {
|
|
21207
|
+
return map;
|
|
21208
|
+
}
|
|
21209
|
+
return {
|
|
21210
|
+
...map,
|
|
21211
|
+
...interaction === void 0 ? {} : { interaction },
|
|
21212
|
+
...maxScale === void 0 ? {} : { maxScale },
|
|
21213
|
+
...iconSize === void 0 ? {} : { iconSize }
|
|
21214
|
+
};
|
|
21215
|
+
}, [iconSize, interaction, map, maxScale]);
|
|
20114
21216
|
const mapProps = {
|
|
20115
|
-
map,
|
|
21217
|
+
map: resolvedMap,
|
|
20116
21218
|
activeSceneId,
|
|
20117
21219
|
view,
|
|
20118
21220
|
mode,
|
|
@@ -20120,14 +21222,17 @@ function PanoMapOverlay({
|
|
|
20120
21222
|
onSelectedSpotIdChange,
|
|
20121
21223
|
onEditChange,
|
|
20122
21224
|
placementSceneId,
|
|
21225
|
+
initialScale,
|
|
21226
|
+
showZoomControls,
|
|
21227
|
+
showCollapseControl,
|
|
20123
21228
|
onSelectScene: (sceneId, spot) => {
|
|
20124
21229
|
onSelectScene?.(sceneId, spot);
|
|
20125
|
-
if (
|
|
21230
|
+
if (presentationMode === "dialog") setOpen(false);
|
|
20126
21231
|
}
|
|
20127
21232
|
};
|
|
20128
|
-
const editorBox =
|
|
20129
|
-
const panelWidth2 = Math.min(420, Math.max(240, size.width * 0.45));
|
|
20130
|
-
const panelHeight2 = Math.min(320, Math.max(180, size.height * 0.45));
|
|
21233
|
+
const editorBox = useMemo31(() => {
|
|
21234
|
+
const panelWidth2 = widthProp !== void 0 && Number.isFinite(widthProp) && widthProp > 0 ? widthProp : Math.min(420, Math.max(240, size.width * 0.45));
|
|
21235
|
+
const panelHeight2 = heightProp !== void 0 && Number.isFinite(heightProp) && heightProp > 0 ? heightProp : Math.min(320, Math.max(180, size.height * 0.45));
|
|
20131
21236
|
return {
|
|
20132
21237
|
left: 16,
|
|
20133
21238
|
right: "auto",
|
|
@@ -20136,9 +21241,9 @@ function PanoMapOverlay({
|
|
|
20136
21241
|
width: panelWidth2,
|
|
20137
21242
|
height: panelHeight2
|
|
20138
21243
|
};
|
|
20139
|
-
}, [size.height, size.width]);
|
|
21244
|
+
}, [heightProp, size.height, size.width, widthProp]);
|
|
20140
21245
|
if (editorSurface) {
|
|
20141
|
-
return /* @__PURE__ */
|
|
21246
|
+
return /* @__PURE__ */ jsx44(
|
|
20142
21247
|
"div",
|
|
20143
21248
|
{
|
|
20144
21249
|
className: ["pano-map-overlay", "pano-map-overlay-editor", className].filter(Boolean).join(" "),
|
|
@@ -20149,14 +21254,14 @@ function PanoMapOverlay({
|
|
|
20149
21254
|
...style
|
|
20150
21255
|
},
|
|
20151
21256
|
"data-pano-map-overlay": "",
|
|
20152
|
-
children: /* @__PURE__ */
|
|
21257
|
+
children: /* @__PURE__ */ jsx44(PanoMap, { ...mapProps, showCollapseControl: false })
|
|
20153
21258
|
}
|
|
20154
21259
|
);
|
|
20155
21260
|
}
|
|
20156
|
-
if (
|
|
21261
|
+
if (presentationMode === "dialog") {
|
|
20157
21262
|
const launcherBox = dockedBox(corner, offsetX, offsetY, width, height);
|
|
20158
|
-
return /* @__PURE__ */
|
|
20159
|
-
/* @__PURE__ */
|
|
21263
|
+
return /* @__PURE__ */ jsxs25("div", { className: ["pano-map-overlay", className].filter(Boolean).join(" "), "data-pano-map-overlay": "", children: [
|
|
21264
|
+
/* @__PURE__ */ jsx44(
|
|
20160
21265
|
"button",
|
|
20161
21266
|
{
|
|
20162
21267
|
type: "button",
|
|
@@ -20172,14 +21277,16 @@ function PanoMapOverlay({
|
|
|
20172
21277
|
children: openLabel
|
|
20173
21278
|
}
|
|
20174
21279
|
),
|
|
20175
|
-
/* @__PURE__ */
|
|
21280
|
+
/* @__PURE__ */ jsx44(
|
|
20176
21281
|
PanoMapDialogShell,
|
|
20177
21282
|
{
|
|
20178
21283
|
open,
|
|
20179
21284
|
onOpenChange: setOpen,
|
|
20180
21285
|
title,
|
|
20181
21286
|
closeLabel,
|
|
20182
|
-
|
|
21287
|
+
dialogWidth,
|
|
21288
|
+
dialogHeight,
|
|
21289
|
+
children: /* @__PURE__ */ jsx44("div", { style: { height: "100%" }, children: /* @__PURE__ */ jsx44(PanoMap, { ...mapProps, showCollapseControl: false }) })
|
|
20183
21290
|
}
|
|
20184
21291
|
)
|
|
20185
21292
|
] });
|
|
@@ -20187,7 +21294,7 @@ function PanoMapOverlay({
|
|
|
20187
21294
|
const panelWidth = collapsed ? Math.max(44, Math.min(width, 56)) : width;
|
|
20188
21295
|
const panelHeight = collapsed ? Math.max(44, Math.min(height, 56)) : height;
|
|
20189
21296
|
const box = dockedBox(corner, offsetX, offsetY, panelWidth, panelHeight);
|
|
20190
|
-
return /* @__PURE__ */
|
|
21297
|
+
return /* @__PURE__ */ jsx44(
|
|
20191
21298
|
"div",
|
|
20192
21299
|
{
|
|
20193
21300
|
className: ["pano-map-overlay", className].filter(Boolean).join(" "),
|
|
@@ -20199,7 +21306,7 @@ function PanoMapOverlay({
|
|
|
20199
21306
|
},
|
|
20200
21307
|
"data-pano-map-overlay": "",
|
|
20201
21308
|
"data-presentation": "docked",
|
|
20202
|
-
children: /* @__PURE__ */
|
|
21309
|
+
children: /* @__PURE__ */ jsx44(
|
|
20203
21310
|
PanoMap,
|
|
20204
21311
|
{
|
|
20205
21312
|
...mapProps,
|
|
@@ -20217,6 +21324,7 @@ export {
|
|
|
20217
21324
|
DEFAULT_HOTSPOT_TOOLTIP_APPEARANCE,
|
|
20218
21325
|
DEFAULT_HOTSPOT_TOOLTIP_OFFSET,
|
|
20219
21326
|
DEFAULT_PANO_CURSORS,
|
|
21327
|
+
DEFAULT_PANO_SCENE_MENU_APPEARANCE,
|
|
20220
21328
|
DEFAULT_PANO_VIDEO_CAPTION_APPEARANCE,
|
|
20221
21329
|
DEFAULT_PANO_VIDEO_CONTROLS_APPEARANCE,
|
|
20222
21330
|
DEFAULT_PANO_VIDEO_PLAYBACK_RATES,
|
|
@@ -20237,6 +21345,7 @@ export {
|
|
|
20237
21345
|
PanoMap,
|
|
20238
21346
|
PanoMapOverlay,
|
|
20239
21347
|
PanoOverlayPortalProvider,
|
|
21348
|
+
PanoSceneMenu,
|
|
20240
21349
|
PanoVideo,
|
|
20241
21350
|
PanoVideoControls,
|
|
20242
21351
|
PanoViewer,
|