@ohhwells/bridge 0.1.132 → 0.1.133
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/dist/index.cjs +181 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +181 -20
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -4067,18 +4067,25 @@ function FadeSlideshow({ node, ctx, path }) {
|
|
|
4067
4067
|
(dir) => onInteract(stepViableSlide(index, failed, count, dir, loop)),
|
|
4068
4068
|
[count, failed, index, loop, onInteract]
|
|
4069
4069
|
);
|
|
4070
|
+
const prefetchRef = React.useRef(prefetch);
|
|
4071
|
+
React.useEffect(() => {
|
|
4072
|
+
prefetchRef.current = prefetch;
|
|
4073
|
+
});
|
|
4074
|
+
React.useEffect(() => {
|
|
4075
|
+
if (autoplay) hasInteractedRef.current = false;
|
|
4076
|
+
}, [autoplay]);
|
|
4070
4077
|
React.useEffect(() => {
|
|
4071
4078
|
if (!autoplay) return;
|
|
4072
4079
|
const id = window.setInterval(() => {
|
|
4073
4080
|
if (hasInteractedRef.current || hoveredRef.current) return;
|
|
4074
4081
|
setIndex((i) => loop ? (i + 1) % count : Math.min(count - 1, i + 1));
|
|
4075
4082
|
}, intervalMs);
|
|
4076
|
-
const warmId = window.setTimeout(() =>
|
|
4083
|
+
const warmId = window.setTimeout(() => prefetchRef.current(1 % count), Math.min(1500, intervalMs / 2));
|
|
4077
4084
|
return () => {
|
|
4078
4085
|
window.clearInterval(id);
|
|
4079
4086
|
window.clearTimeout(warmId);
|
|
4080
4087
|
};
|
|
4081
|
-
}, [autoplay, count, intervalMs, loop
|
|
4088
|
+
}, [autoplay, count, intervalMs, loop]);
|
|
4082
4089
|
const hasMovedRef = React.useRef(false);
|
|
4083
4090
|
React.useEffect(() => {
|
|
4084
4091
|
if (!hasMovedRef.current) {
|
|
@@ -13283,17 +13290,9 @@ var Button = React7.forwardRef(
|
|
|
13283
13290
|
);
|
|
13284
13291
|
Button.displayName = "Button";
|
|
13285
13292
|
|
|
13286
|
-
// src/ui/
|
|
13287
|
-
import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
13293
|
+
// src/ui/media-skeleton.ts
|
|
13288
13294
|
var MEDIA_UPLOAD_FADE_MS = 300;
|
|
13289
|
-
var
|
|
13290
|
-
var OVERLAY_BUTTON_STYLE = {
|
|
13291
|
-
pointerEvents: "auto",
|
|
13292
|
-
fontFamily: "Inter, sans-serif",
|
|
13293
|
-
fontSize: 12,
|
|
13294
|
-
color: "#000"
|
|
13295
|
-
};
|
|
13296
|
-
var SKELETON_CSS = `
|
|
13295
|
+
var MEDIA_SKELETON_CSS = `
|
|
13297
13296
|
@keyframes ohw-media-shimmer {
|
|
13298
13297
|
0% { transform: translateX(-100%); }
|
|
13299
13298
|
100% { transform: translateX(100%); }
|
|
@@ -13310,6 +13309,16 @@ var SKELETON_CSS = `
|
|
|
13310
13309
|
animation: ohw-media-shimmer 1.4s infinite;
|
|
13311
13310
|
}
|
|
13312
13311
|
`;
|
|
13312
|
+
|
|
13313
|
+
// src/ui/MediaOverlay.tsx
|
|
13314
|
+
import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
13315
|
+
var VIDEO_SETTINGS_BAR_INSET = 8;
|
|
13316
|
+
var OVERLAY_BUTTON_STYLE = {
|
|
13317
|
+
pointerEvents: "auto",
|
|
13318
|
+
fontFamily: "Inter, sans-serif",
|
|
13319
|
+
fontSize: 12,
|
|
13320
|
+
color: "#000"
|
|
13321
|
+
};
|
|
13313
13322
|
var REPLACE_BUTTON_INSET = 12;
|
|
13314
13323
|
function replaceButtonMode(image, button) {
|
|
13315
13324
|
if (!button.fullWidth || !button.height) return "none";
|
|
@@ -13377,7 +13386,7 @@ function MediaOverlay({
|
|
|
13377
13386
|
"data-ohw-media-skeleton": "",
|
|
13378
13387
|
"aria-hidden": true,
|
|
13379
13388
|
style: { ...box, pointerEvents: "none" },
|
|
13380
|
-
children: /* @__PURE__ */ jsx16("style", { children:
|
|
13389
|
+
children: /* @__PURE__ */ jsx16("style", { children: MEDIA_SKELETON_CSS })
|
|
13381
13390
|
}
|
|
13382
13391
|
);
|
|
13383
13392
|
}
|
|
@@ -15807,6 +15816,17 @@ function setCarouselSlideAsset(tree, index, assetId) {
|
|
|
15807
15816
|
return true;
|
|
15808
15817
|
});
|
|
15809
15818
|
}
|
|
15819
|
+
function carouselAutoplay(tree) {
|
|
15820
|
+
return findCarouselBlock(tree)?.slots?.autoplay === true;
|
|
15821
|
+
}
|
|
15822
|
+
function setCarouselAutoplay(tree, on) {
|
|
15823
|
+
return withCarousel(tree, (block) => {
|
|
15824
|
+
const slots = { ...block.slots, autoplay: on };
|
|
15825
|
+
if (!on) delete slots.interval;
|
|
15826
|
+
block.slots = slots;
|
|
15827
|
+
return true;
|
|
15828
|
+
});
|
|
15829
|
+
}
|
|
15810
15830
|
|
|
15811
15831
|
// src/ui/ai-section/AiFadeCarouselOverlay.tsx
|
|
15812
15832
|
import { Fragment as Fragment9, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
@@ -15920,10 +15940,85 @@ function Pill4({ label, onClick, disabled }) {
|
|
|
15920
15940
|
}
|
|
15921
15941
|
);
|
|
15922
15942
|
}
|
|
15943
|
+
function TogglePill({
|
|
15944
|
+
label,
|
|
15945
|
+
on,
|
|
15946
|
+
onToggle,
|
|
15947
|
+
disabled
|
|
15948
|
+
}) {
|
|
15949
|
+
return /* @__PURE__ */ jsxs13(
|
|
15950
|
+
"button",
|
|
15951
|
+
{
|
|
15952
|
+
type: "button",
|
|
15953
|
+
role: "switch",
|
|
15954
|
+
"aria-checked": on,
|
|
15955
|
+
onClick: onToggle,
|
|
15956
|
+
disabled,
|
|
15957
|
+
title: on ? `${label} on \u2014 click to turn off` : `${label} off \u2014 click to turn on`,
|
|
15958
|
+
style: {
|
|
15959
|
+
height: 28,
|
|
15960
|
+
padding: "0 8px 0 10px",
|
|
15961
|
+
display: "inline-flex",
|
|
15962
|
+
alignItems: "center",
|
|
15963
|
+
gap: 8,
|
|
15964
|
+
borderRadius: 999,
|
|
15965
|
+
border: "none",
|
|
15966
|
+
cursor: disabled ? "default" : "pointer",
|
|
15967
|
+
background: "#ffffff",
|
|
15968
|
+
color: OHW_BLUE_DARK4,
|
|
15969
|
+
opacity: disabled ? 0.4 : 1,
|
|
15970
|
+
fontSize: 12,
|
|
15971
|
+
lineHeight: "16px",
|
|
15972
|
+
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
15973
|
+
whiteSpace: "nowrap",
|
|
15974
|
+
flex: "0 0 auto"
|
|
15975
|
+
},
|
|
15976
|
+
children: [
|
|
15977
|
+
label,
|
|
15978
|
+
/* @__PURE__ */ jsx22(
|
|
15979
|
+
"span",
|
|
15980
|
+
{
|
|
15981
|
+
"aria-hidden": true,
|
|
15982
|
+
style: {
|
|
15983
|
+
position: "relative",
|
|
15984
|
+
width: 26,
|
|
15985
|
+
height: 15,
|
|
15986
|
+
borderRadius: 999,
|
|
15987
|
+
flex: "0 0 auto",
|
|
15988
|
+
// Off is a grey track, not a washed-out blue: the pill's own white background already
|
|
15989
|
+
// carries the brand colour in the text, and a pale blue track next to it read as
|
|
15990
|
+
// "disabled control" rather than "switch that is off".
|
|
15991
|
+
background: on ? OHW_BLUE_DARK4 : "#CBD5E1",
|
|
15992
|
+
transition: "background 120ms ease"
|
|
15993
|
+
},
|
|
15994
|
+
children: /* @__PURE__ */ jsx22(
|
|
15995
|
+
"span",
|
|
15996
|
+
{
|
|
15997
|
+
style: {
|
|
15998
|
+
position: "absolute",
|
|
15999
|
+
top: 2,
|
|
16000
|
+
left: on ? 13 : 2,
|
|
16001
|
+
width: 11,
|
|
16002
|
+
height: 11,
|
|
16003
|
+
borderRadius: "50%",
|
|
16004
|
+
background: "#ffffff",
|
|
16005
|
+
boxShadow: "0 1px 2px rgba(0,0,0,0.3)",
|
|
16006
|
+
transition: "left 120ms ease"
|
|
16007
|
+
}
|
|
16008
|
+
}
|
|
16009
|
+
)
|
|
16010
|
+
}
|
|
16011
|
+
)
|
|
16012
|
+
]
|
|
16013
|
+
}
|
|
16014
|
+
);
|
|
16015
|
+
}
|
|
15923
16016
|
function CarouselSlideToolbar({
|
|
15924
16017
|
pending,
|
|
15925
16018
|
error,
|
|
15926
|
-
|
|
16019
|
+
autoplay,
|
|
16020
|
+
onChangeImage,
|
|
16021
|
+
onToggleAutoplay
|
|
15927
16022
|
}) {
|
|
15928
16023
|
return /* @__PURE__ */ jsxs13(
|
|
15929
16024
|
"div",
|
|
@@ -15940,11 +16035,18 @@ function CarouselSlideToolbar({
|
|
|
15940
16035
|
padding: 8,
|
|
15941
16036
|
borderRadius: 12,
|
|
15942
16037
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
15943
|
-
|
|
15944
|
-
|
|
16038
|
+
// Not dimmed while pending, only inert. The toolbar used to drop to 0.6 opacity for the
|
|
16039
|
+
// length of the validate round-trip, which on a local backend is short enough that the
|
|
16040
|
+
// autoplay toggle just flashed — a dim and an un-dim with nothing in between. Progress is
|
|
16041
|
+
// reported where the change is: the switch moves at once (optimistically), and an image
|
|
16042
|
+
// swap raises the skeleton over the slide.
|
|
16043
|
+
pointerEvents: pending ? "none" : "auto"
|
|
15945
16044
|
},
|
|
15946
16045
|
children: [
|
|
15947
|
-
/* @__PURE__ */
|
|
16046
|
+
/* @__PURE__ */ jsxs13("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
|
|
16047
|
+
/* @__PURE__ */ jsx22(Pill4, { label: "Change Image", onClick: onChangeImage }),
|
|
16048
|
+
/* @__PURE__ */ jsx22(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
|
|
16049
|
+
] }),
|
|
15948
16050
|
error && /* @__PURE__ */ jsx22("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
15949
16051
|
]
|
|
15950
16052
|
}
|
|
@@ -15960,8 +16062,24 @@ function AiFadeCarouselOverlay({
|
|
|
15960
16062
|
const [active, setActive] = useState10(null);
|
|
15961
16063
|
const [pending, setPending] = useState10(false);
|
|
15962
16064
|
const [error, setError] = useState10(null);
|
|
16065
|
+
const [autoplayOverride, setAutoplayOverride] = useState10(null);
|
|
16066
|
+
const [swapping, setSwapping] = useState10(null);
|
|
16067
|
+
const skeletonRef = useRef8(null);
|
|
15963
16068
|
const activeRef = useRef8(null);
|
|
15964
16069
|
activeRef.current = active;
|
|
16070
|
+
useEffect8(() => {
|
|
16071
|
+
setAutoplayOverride(null);
|
|
16072
|
+
}, [active?.sectionId, active?.index]);
|
|
16073
|
+
useEffect8(() => {
|
|
16074
|
+
if (!swapping?.fadingOut || !skeletonRef.current) return;
|
|
16075
|
+
const anim = skeletonRef.current.animate([{ opacity: 1 }, { opacity: 0 }], {
|
|
16076
|
+
duration: MEDIA_UPLOAD_FADE_MS,
|
|
16077
|
+
easing: "ease-out",
|
|
16078
|
+
fill: "forwards"
|
|
16079
|
+
});
|
|
16080
|
+
anim.finished.then(() => setSwapping(null)).catch(() => setSwapping(null));
|
|
16081
|
+
return () => anim.cancel();
|
|
16082
|
+
}, [swapping?.fadingOut]);
|
|
15965
16083
|
useEffect8(() => {
|
|
15966
16084
|
const onMove = (e) => {
|
|
15967
16085
|
const t = e.target;
|
|
@@ -16102,6 +16220,27 @@ function AiFadeCarouselOverlay({
|
|
|
16102
16220
|
children: /* @__PURE__ */ jsx22(Star4, { size: 14, style: { pointerEvents: "none" } })
|
|
16103
16221
|
}
|
|
16104
16222
|
),
|
|
16223
|
+
swapping && /* @__PURE__ */ jsx22(
|
|
16224
|
+
"div",
|
|
16225
|
+
{
|
|
16226
|
+
ref: skeletonRef,
|
|
16227
|
+
"data-ohw-bridge": "",
|
|
16228
|
+
"data-ohw-media-skeleton": "",
|
|
16229
|
+
"aria-hidden": true,
|
|
16230
|
+
style: {
|
|
16231
|
+
position: "fixed",
|
|
16232
|
+
top: swapping.rect.top,
|
|
16233
|
+
left: swapping.rect.left,
|
|
16234
|
+
width: swapping.rect.width,
|
|
16235
|
+
height: swapping.rect.height,
|
|
16236
|
+
// Under the toolbar (2147483647) so its controls stay visible and clickable over the
|
|
16237
|
+
// slide being swapped, and inert so it cannot eat the click that dismisses them.
|
|
16238
|
+
zIndex: 2147483646,
|
|
16239
|
+
pointerEvents: "none"
|
|
16240
|
+
},
|
|
16241
|
+
children: /* @__PURE__ */ jsx22("style", { children: MEDIA_SKELETON_CSS })
|
|
16242
|
+
}
|
|
16243
|
+
),
|
|
16105
16244
|
activeItemRect && active && activeEntry && /* @__PURE__ */ jsx22(
|
|
16106
16245
|
ItemInteractionLayer,
|
|
16107
16246
|
{
|
|
@@ -16112,14 +16251,36 @@ function AiFadeCarouselOverlay({
|
|
|
16112
16251
|
{
|
|
16113
16252
|
pending,
|
|
16114
16253
|
error,
|
|
16254
|
+
autoplay: autoplayOverride ?? carouselAutoplay(activeEntry.tree),
|
|
16255
|
+
onToggleAutoplay: () => {
|
|
16256
|
+
const next = !(autoplayOverride ?? carouselAutoplay(activeEntry.tree));
|
|
16257
|
+
setAutoplayOverride(next);
|
|
16258
|
+
void runMutation(active.sectionId, (tree) => setCarouselAutoplay(tree, next)).then(
|
|
16259
|
+
(ok) => {
|
|
16260
|
+
if (!ok) setAutoplayOverride(null);
|
|
16261
|
+
}
|
|
16262
|
+
);
|
|
16263
|
+
},
|
|
16115
16264
|
onChangeImage: () => {
|
|
16116
|
-
void requestAssetPick2(postToParent2).then((picked) => {
|
|
16265
|
+
void requestAssetPick2(postToParent2).then(async (picked) => {
|
|
16117
16266
|
if (!picked) return;
|
|
16118
|
-
|
|
16267
|
+
const slideRect = readRect5(active);
|
|
16268
|
+
if (slideRect) setSwapping({ rect: slideRect, fadingOut: false });
|
|
16269
|
+
const ok = await runMutation(
|
|
16119
16270
|
active.sectionId,
|
|
16120
16271
|
(tree) => setCarouselSlideAsset(tree, active.index, picked.assetId),
|
|
16121
16272
|
{ [picked.assetId]: picked.url }
|
|
16122
16273
|
);
|
|
16274
|
+
if (!ok) {
|
|
16275
|
+
setSwapping(null);
|
|
16276
|
+
return;
|
|
16277
|
+
}
|
|
16278
|
+
const preload = new Image();
|
|
16279
|
+
const done = () => setSwapping((s) => s ? { ...s, fadingOut: true } : s);
|
|
16280
|
+
preload.onload = done;
|
|
16281
|
+
preload.onerror = done;
|
|
16282
|
+
preload.src = picked.url;
|
|
16283
|
+
if (preload.complete) done();
|
|
16123
16284
|
});
|
|
16124
16285
|
}
|
|
16125
16286
|
}
|
|
@@ -30067,7 +30228,7 @@ function OhhwellsBridge() {
|
|
|
30067
30228
|
postToParent2({
|
|
30068
30229
|
type: "ow:ready",
|
|
30069
30230
|
version: "1",
|
|
30070
|
-
bridgeVersion: "0.1.
|
|
30231
|
+
bridgeVersion: "0.1.132",
|
|
30071
30232
|
path: pathname,
|
|
30072
30233
|
nodes: collectEditableNodes(editContentRef.current),
|
|
30073
30234
|
sections
|