@ohhwells/bridge 0.1.38-next.58 → 0.1.38-next.60

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 CHANGED
@@ -57,12 +57,13 @@ __export(index_exports, {
57
57
  isValidUrl: () => isValidUrl,
58
58
  parseTarget: () => parseTarget,
59
59
  toggleVariants: () => toggleVariants,
60
+ useOhwCarousel: () => useOhwCarousel,
60
61
  validateUrlInput: () => validateUrlInput
61
62
  });
62
63
  module.exports = __toCommonJS(index_exports);
63
64
 
64
65
  // src/OhhwellsBridge.tsx
65
- var import_react8 = __toESM(require("react"), 1);
66
+ var import_react9 = __toESM(require("react"), 1);
66
67
  var import_client = require("react-dom/client");
67
68
  var import_react_dom2 = require("react-dom");
68
69
 
@@ -4861,6 +4862,61 @@ function MediaOverlay({
4861
4862
  ] });
4862
4863
  }
4863
4864
 
4865
+ // src/ui/CarouselOverlay.tsx
4866
+ var import_lucide_react4 = require("lucide-react");
4867
+ var import_jsx_runtime12 = require("react/jsx-runtime");
4868
+ var OVERLAY_BUTTON_STYLE2 = {
4869
+ pointerEvents: "auto",
4870
+ fontFamily: "Inter, sans-serif",
4871
+ fontSize: 12,
4872
+ color: "#000"
4873
+ };
4874
+ function CarouselOverlay({
4875
+ hover,
4876
+ onEdit
4877
+ }) {
4878
+ const { rect } = hover;
4879
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4880
+ "div",
4881
+ {
4882
+ "data-ohw-bridge": "",
4883
+ "data-ohw-carousel-overlay": "",
4884
+ className: "flex cursor-pointer items-center justify-center",
4885
+ style: {
4886
+ position: "fixed",
4887
+ top: rect.top,
4888
+ left: rect.left,
4889
+ width: rect.width,
4890
+ height: rect.height,
4891
+ zIndex: 2147483646,
4892
+ pointerEvents: "auto",
4893
+ boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
4894
+ background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
4895
+ },
4896
+ onClick: () => onEdit(hover.key),
4897
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4898
+ Button,
4899
+ {
4900
+ "data-ohw-carousel-overlay": "",
4901
+ variant: "outline",
4902
+ size: "sm",
4903
+ className: "cursor-pointer gap-1.5 hover:bg-background",
4904
+ style: OVERLAY_BUTTON_STYLE2,
4905
+ onMouseDown: (e) => e.preventDefault(),
4906
+ onClick: (e) => {
4907
+ e.stopPropagation();
4908
+ onEdit(hover.key);
4909
+ },
4910
+ children: [
4911
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.GalleryHorizontal, { size: 14 }),
4912
+ "Edit gallery"
4913
+ ]
4914
+ }
4915
+ )
4916
+ }
4917
+ );
4918
+ }
4919
+
4864
4920
  // src/OhhwellsBridge.tsx
4865
4921
  var import_react_dom3 = require("react-dom");
4866
4922
  var import_navigation2 = require("next/navigation");
@@ -5145,23 +5201,23 @@ var import_react7 = require("react");
5145
5201
  // src/ui/dialog.tsx
5146
5202
  var React7 = __toESM(require("react"), 1);
5147
5203
  var import_radix_ui5 = require("radix-ui");
5148
- var import_lucide_react4 = require("lucide-react");
5149
- var import_jsx_runtime12 = require("react/jsx-runtime");
5204
+ var import_lucide_react5 = require("lucide-react");
5205
+ var import_jsx_runtime13 = require("react/jsx-runtime");
5150
5206
  function Dialog2({
5151
5207
  ...props
5152
5208
  }) {
5153
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_radix_ui5.Dialog.Root, { "data-slot": "dialog", ...props });
5209
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_radix_ui5.Dialog.Root, { "data-slot": "dialog", ...props });
5154
5210
  }
5155
5211
  function DialogPortal({
5156
5212
  ...props
5157
5213
  }) {
5158
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_radix_ui5.Dialog.Portal, { ...props });
5214
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_radix_ui5.Dialog.Portal, { ...props });
5159
5215
  }
5160
5216
  function DialogOverlay({
5161
5217
  className,
5162
5218
  ...props
5163
5219
  }) {
5164
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5220
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5165
5221
  import_radix_ui5.Dialog.Overlay,
5166
5222
  {
5167
5223
  "data-slot": "dialog-overlay",
@@ -5174,9 +5230,9 @@ function DialogOverlay({
5174
5230
  var DialogContent = React7.forwardRef(
5175
5231
  ({ className, children, showCloseButton = true, container, ...props }, ref) => {
5176
5232
  const positionMode = container ? "absolute" : "fixed";
5177
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(DialogPortal, { container: container ?? void 0, children: [
5178
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
5179
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
5233
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DialogPortal, { container: container ?? void 0, children: [
5234
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
5235
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
5180
5236
  import_radix_ui5.Dialog.Content,
5181
5237
  {
5182
5238
  ref,
@@ -5192,13 +5248,13 @@ var DialogContent = React7.forwardRef(
5192
5248
  ...props,
5193
5249
  children: [
5194
5250
  children,
5195
- showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5251
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5196
5252
  import_radix_ui5.Dialog.Close,
5197
5253
  {
5198
5254
  type: "button",
5199
5255
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
5200
5256
  "aria-label": "Close",
5201
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.X, { size: 16, "aria-hidden": true })
5257
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react5.X, { size: 16, "aria-hidden": true })
5202
5258
  }
5203
5259
  ) : null
5204
5260
  ]
@@ -5212,13 +5268,13 @@ function DialogHeader({
5212
5268
  className,
5213
5269
  ...props
5214
5270
  }) {
5215
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5271
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5216
5272
  }
5217
5273
  function DialogFooter({
5218
5274
  className,
5219
5275
  ...props
5220
5276
  }) {
5221
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5277
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5222
5278
  "div",
5223
5279
  {
5224
5280
  className: cn("flex items-center justify-end gap-2", className),
@@ -5226,7 +5282,7 @@ function DialogFooter({
5226
5282
  }
5227
5283
  );
5228
5284
  }
5229
- var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5285
+ var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5230
5286
  import_radix_ui5.Dialog.Title,
5231
5287
  {
5232
5288
  ref,
@@ -5238,7 +5294,7 @@ var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE
5238
5294
  }
5239
5295
  ));
5240
5296
  DialogTitle.displayName = import_radix_ui5.Dialog.Title.displayName;
5241
- var DialogDescription = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5297
+ var DialogDescription = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5242
5298
  import_radix_ui5.Dialog.Description,
5243
5299
  {
5244
5300
  ref,
@@ -5250,63 +5306,63 @@ DialogDescription.displayName = import_radix_ui5.Dialog.Description.displayName;
5250
5306
  var DialogClose = import_radix_ui5.Dialog.Close;
5251
5307
 
5252
5308
  // src/ui/link-modal/LinkEditorPanel.tsx
5253
- var import_lucide_react8 = require("lucide-react");
5309
+ var import_lucide_react9 = require("lucide-react");
5254
5310
 
5255
5311
  // src/ui/link-modal/DestinationBreadcrumb.tsx
5256
- var import_lucide_react5 = require("lucide-react");
5257
- var import_jsx_runtime13 = require("react/jsx-runtime");
5312
+ var import_lucide_react6 = require("lucide-react");
5313
+ var import_jsx_runtime14 = require("react/jsx-runtime");
5258
5314
  function DestinationBreadcrumb({
5259
5315
  pageTitle,
5260
5316
  sectionLabel
5261
5317
  }) {
5262
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
5263
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
5264
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-3", children: [
5265
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", children: [
5266
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react5.File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
5267
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
5318
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
5319
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
5320
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-3", children: [
5321
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-2", children: [
5322
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
5323
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
5268
5324
  ] }),
5269
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5270
- import_lucide_react5.ArrowRight,
5325
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5326
+ import_lucide_react6.ArrowRight,
5271
5327
  {
5272
5328
  size: 16,
5273
5329
  className: "shrink-0 text-muted-foreground",
5274
5330
  "aria-hidden": true
5275
5331
  }
5276
5332
  ),
5277
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
5278
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5279
- import_lucide_react5.GalleryVertical,
5333
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
5334
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5335
+ import_lucide_react6.GalleryVertical,
5280
5336
  {
5281
5337
  size: 16,
5282
5338
  className: "shrink-0 text-foreground",
5283
5339
  "aria-hidden": true
5284
5340
  }
5285
5341
  ),
5286
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
5342
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
5287
5343
  ] })
5288
5344
  ] })
5289
5345
  ] });
5290
5346
  }
5291
5347
 
5292
5348
  // src/ui/link-modal/SectionTreeItem.tsx
5293
- var import_lucide_react6 = require("lucide-react");
5294
- var import_jsx_runtime14 = require("react/jsx-runtime");
5349
+ var import_lucide_react7 = require("lucide-react");
5350
+ var import_jsx_runtime15 = require("react/jsx-runtime");
5295
5351
  function SectionTreeItem({
5296
5352
  section,
5297
5353
  onSelect,
5298
5354
  selected
5299
5355
  }) {
5300
5356
  const interactive = Boolean(onSelect);
5301
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
5302
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5357
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
5358
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5303
5359
  "div",
5304
5360
  {
5305
5361
  className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
5306
5362
  "aria-hidden": true
5307
5363
  }
5308
5364
  ),
5309
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
5365
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5310
5366
  "div",
5311
5367
  {
5312
5368
  role: interactive ? "button" : void 0,
@@ -5324,15 +5380,15 @@ function SectionTreeItem({
5324
5380
  interactive && selected && "border-primary"
5325
5381
  ),
5326
5382
  children: [
5327
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5328
- import_lucide_react6.GalleryVertical,
5383
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5384
+ import_lucide_react7.GalleryVertical,
5329
5385
  {
5330
5386
  size: 16,
5331
5387
  className: "shrink-0 text-foreground",
5332
5388
  "aria-hidden": true
5333
5389
  }
5334
5390
  ),
5335
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
5391
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
5336
5392
  ]
5337
5393
  }
5338
5394
  )
@@ -5344,10 +5400,10 @@ var import_react4 = require("react");
5344
5400
 
5345
5401
  // src/ui/input.tsx
5346
5402
  var React8 = __toESM(require("react"), 1);
5347
- var import_jsx_runtime15 = require("react/jsx-runtime");
5403
+ var import_jsx_runtime16 = require("react/jsx-runtime");
5348
5404
  var Input = React8.forwardRef(
5349
5405
  ({ className, type, ...props }, ref) => {
5350
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5406
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5351
5407
  "input",
5352
5408
  {
5353
5409
  type,
@@ -5366,9 +5422,9 @@ Input.displayName = "Input";
5366
5422
 
5367
5423
  // src/ui/label.tsx
5368
5424
  var import_radix_ui6 = require("radix-ui");
5369
- var import_jsx_runtime16 = require("react/jsx-runtime");
5425
+ var import_jsx_runtime17 = require("react/jsx-runtime");
5370
5426
  function Label({ className, ...props }) {
5371
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5427
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5372
5428
  import_radix_ui6.Label.Root,
5373
5429
  {
5374
5430
  "data-slot": "label",
@@ -5379,12 +5435,12 @@ function Label({ className, ...props }) {
5379
5435
  }
5380
5436
 
5381
5437
  // src/ui/link-modal/UrlOrPageInput.tsx
5382
- var import_lucide_react7 = require("lucide-react");
5383
- var import_jsx_runtime17 = require("react/jsx-runtime");
5438
+ var import_lucide_react8 = require("lucide-react");
5439
+ var import_jsx_runtime18 = require("react/jsx-runtime");
5384
5440
  function FieldChevron({
5385
5441
  onClick
5386
5442
  }) {
5387
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5443
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5388
5444
  "button",
5389
5445
  {
5390
5446
  type: "button",
@@ -5392,7 +5448,7 @@ function FieldChevron({
5392
5448
  onClick,
5393
5449
  "aria-label": "Open page list",
5394
5450
  tabIndex: -1,
5395
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.ChevronDown, { size: 16 })
5451
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.ChevronDown, { size: 16 })
5396
5452
  }
5397
5453
  );
5398
5454
  }
@@ -5453,19 +5509,19 @@ function UrlOrPageInput({
5453
5509
  "data-ohw-link-field flex h-[36px] w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
5454
5510
  urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
5455
5511
  );
5456
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
5457
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
5458
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { ref: rootRef, className: "relative w-full", children: [
5459
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
5460
- selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5461
- import_lucide_react7.File,
5512
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
5513
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
5514
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { ref: rootRef, className: "relative w-full", children: [
5515
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
5516
+ selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5517
+ import_lucide_react8.File,
5462
5518
  {
5463
5519
  size: 16,
5464
5520
  className: "shrink-0 text-foreground",
5465
5521
  "aria-hidden": true
5466
5522
  }
5467
5523
  ) }) : null,
5468
- readOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5524
+ readOnly ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5469
5525
  Input,
5470
5526
  {
5471
5527
  ref: inputRef,
@@ -5491,7 +5547,7 @@ function UrlOrPageInput({
5491
5547
  )
5492
5548
  }
5493
5549
  ),
5494
- selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5550
+ selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5495
5551
  "button",
5496
5552
  {
5497
5553
  type: "button",
@@ -5499,26 +5555,26 @@ function UrlOrPageInput({
5499
5555
  onMouseDown: clearSelection,
5500
5556
  "aria-label": "Clear selected page",
5501
5557
  tabIndex: -1,
5502
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.X, { size: 16, "aria-hidden": true })
5558
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
5503
5559
  }
5504
5560
  ) : null,
5505
- !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
5561
+ !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
5506
5562
  ] }),
5507
- dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5563
+ dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5508
5564
  "div",
5509
5565
  {
5510
5566
  "data-ohw-link-page-dropdown": "",
5511
5567
  className: "absolute left-0 right-0 top-[calc(100%+4px)] z-50 max-h-48 overflow-auto rounded-lg border border-border bg-popover py-1 shadow-lg",
5512
5568
  onMouseDown: (e) => e.preventDefault(),
5513
- children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
5569
+ children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5514
5570
  "button",
5515
5571
  {
5516
5572
  type: "button",
5517
5573
  className: "flex h-9 w-full items-center gap-2 border-0 bg-transparent px-3 text-left text-sm leading-5 text-foreground outline-none hover:bg-muted",
5518
5574
  onClick: () => onPageSelect(page),
5519
5575
  children: [
5520
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.File, { size: 16, className: "shrink-0", "aria-hidden": true }),
5521
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "truncate", children: page.title })
5576
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.File, { size: 16, className: "shrink-0", "aria-hidden": true }),
5577
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate", children: page.title })
5522
5578
  ]
5523
5579
  },
5524
5580
  page.path
@@ -5526,34 +5582,34 @@ function UrlOrPageInput({
5526
5582
  }
5527
5583
  ) : null
5528
5584
  ] }),
5529
- urlError ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
5585
+ urlError ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
5530
5586
  ] });
5531
5587
  }
5532
5588
 
5533
5589
  // src/ui/link-modal/LinkEditorPanel.tsx
5534
- var import_jsx_runtime18 = require("react/jsx-runtime");
5590
+ var import_jsx_runtime19 = require("react/jsx-runtime");
5535
5591
  function LinkEditorPanel({ state, onClose }) {
5536
5592
  const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
5537
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
5538
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5593
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5594
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5539
5595
  "button",
5540
5596
  {
5541
5597
  type: "button",
5542
5598
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
5543
5599
  "aria-label": "Close",
5544
5600
  onClick: onClose,
5545
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
5601
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.X, { size: 16, "aria-hidden": true })
5546
5602
  }
5547
5603
  ) }),
5548
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
5549
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5550
- state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5604
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
5605
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5606
+ state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5551
5607
  DestinationBreadcrumb,
5552
5608
  {
5553
5609
  pageTitle: state.selectedPage.title,
5554
5610
  sectionLabel: state.selectedSection.label
5555
5611
  }
5556
- ) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5612
+ ) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5557
5613
  UrlOrPageInput,
5558
5614
  {
5559
5615
  value: state.searchValue,
@@ -5566,8 +5622,8 @@ function LinkEditorPanel({ state, onClose }) {
5566
5622
  urlError: state.urlError
5567
5623
  }
5568
5624
  ),
5569
- state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
5570
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5625
+ state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
5626
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5571
5627
  Button,
5572
5628
  {
5573
5629
  type: "button",
@@ -5578,15 +5634,15 @@ function LinkEditorPanel({ state, onClose }) {
5578
5634
  children: "Choose a section"
5579
5635
  }
5580
5636
  ),
5581
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5582
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
5583
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "Pick a section this link should scroll to." })
5637
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5638
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
5639
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "Pick a section this link should scroll to." })
5584
5640
  ] })
5585
5641
  ] }) : null,
5586
- state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5642
+ state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5587
5643
  ] }),
5588
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
5589
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5644
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
5645
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5590
5646
  Button,
5591
5647
  {
5592
5648
  type: "button",
@@ -5601,7 +5657,7 @@ function LinkEditorPanel({ state, onClose }) {
5601
5657
  children: state.secondaryLabel
5602
5658
  }
5603
5659
  ),
5604
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5660
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5605
5661
  Button,
5606
5662
  {
5607
5663
  type: "button",
@@ -5622,9 +5678,9 @@ function LinkEditorPanel({ state, onClose }) {
5622
5678
  // src/ui/link-modal/SectionPickerOverlay.tsx
5623
5679
  var import_react5 = require("react");
5624
5680
  var import_react_dom = require("react-dom");
5625
- var import_lucide_react9 = require("lucide-react");
5681
+ var import_lucide_react10 = require("lucide-react");
5626
5682
  var import_navigation = require("next/navigation");
5627
- var import_jsx_runtime19 = require("react/jsx-runtime");
5683
+ var import_jsx_runtime20 = require("react/jsx-runtime");
5628
5684
  var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
5629
5685
  function rectsEqual(a, b) {
5630
5686
  if (a.size !== b.size) return false;
@@ -5748,12 +5804,15 @@ function SectionPickerOverlay({
5748
5804
  );
5749
5805
  sectionIdsRef.current = sectionIds;
5750
5806
  const rects = useSectionRects(sectionIdsKey, isOnTargetPage);
5751
- const applyHoverAt = (0, import_react5.useCallback)((x, y, liveRects) => {
5752
- const ids = sectionIdsRef.current;
5753
- const map = liveRects ?? readSectionRects(ids);
5754
- const next = hitTestSectionId(x, y, ids, map);
5755
- setHoveredId((prev) => prev === next ? prev : next);
5756
- }, []);
5807
+ const applyHoverAt = (0, import_react5.useCallback)(
5808
+ (x, y, liveRects) => {
5809
+ const ids = sectionIdsRef.current;
5810
+ const map = liveRects ?? readSectionRects(ids);
5811
+ const next = hitTestSectionId(x, y, ids, map);
5812
+ setHoveredId((prev) => prev === next ? prev : next);
5813
+ },
5814
+ []
5815
+ );
5757
5816
  (0, import_react5.useEffect)(() => {
5758
5817
  const applyClip = (iframeOffsetTop, visibleCanvasTop, canvasH) => {
5759
5818
  const top = Math.max(0, visibleCanvasTop - iframeOffsetTop);
@@ -5847,7 +5906,7 @@ function SectionPickerOverlay({
5847
5906
  const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
5848
5907
  if (!portalRoot) return null;
5849
5908
  return (0, import_react_dom.createPortal)(
5850
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5909
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
5851
5910
  "div",
5852
5911
  {
5853
5912
  "data-ohw-section-picker": "",
@@ -5857,12 +5916,12 @@ function SectionPickerOverlay({
5857
5916
  role: "dialog",
5858
5917
  "aria-label": "Choose a section",
5859
5918
  children: [
5860
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5919
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5861
5920
  "div",
5862
5921
  {
5863
5922
  className: "pointer-events-auto fixed left-5 z-[2]",
5864
5923
  style: { top: chromeClip.top + 20 },
5865
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5924
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
5866
5925
  Button,
5867
5926
  {
5868
5927
  type: "button",
@@ -5871,14 +5930,14 @@ function SectionPickerOverlay({
5871
5930
  className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
5872
5931
  onClick: onBack,
5873
5932
  children: [
5874
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
5933
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react10.ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
5875
5934
  "Back"
5876
5935
  ]
5877
5936
  }
5878
5937
  )
5879
5938
  }
5880
5939
  ),
5881
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5940
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5882
5941
  "div",
5883
5942
  {
5884
5943
  className: "pointer-events-none fixed left-1/2 z-[2] rounded-lg px-4 py-3 text-xs leading-4 tracking-[0.18px] text-white shadow-md",
@@ -5891,7 +5950,7 @@ function SectionPickerOverlay({
5891
5950
  children: "Click on section to select"
5892
5951
  }
5893
5952
  ),
5894
- !isOnTargetPage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5953
+ !isOnTargetPage ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5895
5954
  "div",
5896
5955
  {
5897
5956
  className: "pointer-events-none fixed left-1/2 z-[1] -translate-x-1/2 rounded-md bg-background/90 px-3 py-2 text-sm text-muted-foreground shadow-sm",
@@ -5899,13 +5958,14 @@ function SectionPickerOverlay({
5899
5958
  children: "Loading page preview\u2026"
5900
5959
  }
5901
5960
  ) : null,
5902
- isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
5961
+ isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
5903
5962
  isOnTargetPage ? liveSections.map((section) => {
5904
5963
  const rect = rects.get(section.id);
5905
5964
  if (!rect || rect.width <= 0 || rect.height <= 0) return null;
5906
5965
  const isSelected = selectedId === section.id;
5907
- const isLit = isSelected || hoveredId === section.id;
5908
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5966
+ const isHovered = hoveredId === section.id;
5967
+ const isLit = isSelected || isHovered;
5968
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
5909
5969
  "button",
5910
5970
  {
5911
5971
  type: "button",
@@ -5919,15 +5979,30 @@ function SectionPickerOverlay({
5919
5979
  },
5920
5980
  "aria-label": `Select section ${section.label}`,
5921
5981
  onClick: () => handleSelect(section),
5922
- children: isSelected ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5923
- "span",
5924
- {
5925
- className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
5926
- style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
5927
- "aria-hidden": true,
5928
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.Check, { className: "size-5" })
5929
- }
5930
- ) : null
5982
+ children: [
5983
+ isLit ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5984
+ "span",
5985
+ {
5986
+ className: "pointer-events-none absolute",
5987
+ style: {
5988
+ inset: 4,
5989
+ borderRadius: "var(--radius, 6px)",
5990
+ border: "1.5px dashed var(--primary, #0885FE)",
5991
+ boxSizing: "border-box"
5992
+ },
5993
+ "aria-hidden": true
5994
+ }
5995
+ ) : null,
5996
+ isSelected ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5997
+ "span",
5998
+ {
5999
+ className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
6000
+ style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
6001
+ "aria-hidden": true,
6002
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react10.Check, { className: "size-5" })
6003
+ }
6004
+ ) : null
6005
+ ]
5931
6006
  },
5932
6007
  section.id
5933
6008
  );
@@ -6104,7 +6179,7 @@ function useLinkModalState({
6104
6179
  }
6105
6180
 
6106
6181
  // src/ui/link-modal/LinkPopover.tsx
6107
- var import_jsx_runtime20 = require("react/jsx-runtime");
6182
+ var import_jsx_runtime21 = require("react/jsx-runtime");
6108
6183
  function postToParent(data) {
6109
6184
  window.parent?.postMessage(data, "*");
6110
6185
  }
@@ -6136,7 +6211,7 @@ function LinkPopover({
6136
6211
  (0, import_react7.useEffect)(() => {
6137
6212
  if (!open) return;
6138
6213
  if (sectionPickerActive) {
6139
- postToParent({ type: "ow:link-modal-lock", locked: false });
6214
+ postToParent({ type: "ui:unlock" });
6140
6215
  postToParent({ type: "ow:section-picker", active: true });
6141
6216
  document.documentElement.style.overflow = "";
6142
6217
  document.body.style.overflow = "";
@@ -6145,7 +6220,7 @@ function LinkPopover({
6145
6220
  };
6146
6221
  }
6147
6222
  postToParent({ type: "ow:section-picker", active: false });
6148
- postToParent({ type: "ow:link-modal-lock", locked: true });
6223
+ postToParent({ type: "ui:lock" });
6149
6224
  const html = document.documentElement;
6150
6225
  const body = document.body;
6151
6226
  const prevHtmlOverflow = html.style.overflow;
@@ -6183,7 +6258,7 @@ function LinkPopover({
6183
6258
  document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
6184
6259
  document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
6185
6260
  return () => {
6186
- postToParent({ type: "ow:link-modal-lock", locked: false });
6261
+ postToParent({ type: "ui:unlock" });
6187
6262
  html.style.overflow = prevHtmlOverflow;
6188
6263
  body.style.overflow = prevBodyOverflow;
6189
6264
  html.style.overscrollBehavior = prevHtmlOverscroll;
@@ -6200,15 +6275,15 @@ function LinkPopover({
6200
6275
  );
6201
6276
  };
6202
6277
  }, [open, sectionPickerActive]);
6203
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
6204
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6278
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
6279
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6205
6280
  Dialog2,
6206
6281
  {
6207
6282
  open: open && !sectionPickerActive,
6208
6283
  onOpenChange: (next) => {
6209
6284
  if (!next) onClose?.();
6210
6285
  },
6211
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6286
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6212
6287
  DialogContent,
6213
6288
  {
6214
6289
  ref: panelRef,
@@ -6218,12 +6293,12 @@ function LinkPopover({
6218
6293
  "data-ohw-bridge": "",
6219
6294
  showCloseButton: false,
6220
6295
  className: "gap-0 p-0 w-full max-w-[448px] pointer-events-auto z-[2147483646] overflow-visible",
6221
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LinkEditorPanel, { state, onClose })
6296
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LinkEditorPanel, { state, onClose })
6222
6297
  }
6223
6298
  )
6224
6299
  }
6225
6300
  ),
6226
- sectionPickerActive && state.selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6301
+ sectionPickerActive && state.selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6227
6302
  SectionPickerOverlay,
6228
6303
  {
6229
6304
  pagePath: state.selectedPage.path,
@@ -6529,15 +6604,99 @@ function insertNavbarItem(href, label, afterAnchor = null) {
6529
6604
  };
6530
6605
  }
6531
6606
 
6607
+ // src/lib/carousel.ts
6608
+ var import_react8 = require("react");
6609
+ var CAROUSEL_ATTR = "data-ohw-carousel";
6610
+ var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
6611
+ var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
6612
+ var CAROUSEL_EVENT = "ohw:carousel-change";
6613
+ function listCarouselKeys() {
6614
+ const keys = /* @__PURE__ */ new Set();
6615
+ document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
6616
+ const key = el.getAttribute("data-ohw-key");
6617
+ if (key) keys.add(key);
6618
+ });
6619
+ return [...keys];
6620
+ }
6621
+ function containersForKey(key) {
6622
+ return Array.from(
6623
+ document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
6624
+ );
6625
+ }
6626
+ function isCarouselKey(key) {
6627
+ return containersForKey(key).length > 0;
6628
+ }
6629
+ function parseSlides(raw) {
6630
+ if (!raw) return [];
6631
+ try {
6632
+ const parsed = JSON.parse(raw);
6633
+ if (!Array.isArray(parsed)) return [];
6634
+ return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
6635
+ } catch {
6636
+ return [];
6637
+ }
6638
+ }
6639
+ function readCarouselValue(key) {
6640
+ const container = containersForKey(key)[0];
6641
+ if (!container) return [];
6642
+ const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
6643
+ if (fromAttr.length > 0) return fromAttr;
6644
+ return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
6645
+ const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
6646
+ return { src: img?.src ?? "", alt: img?.alt ?? "" };
6647
+ });
6648
+ }
6649
+ function slideIndex(el) {
6650
+ const raw = el.getAttribute(CAROUSEL_SLIDE_ATTR);
6651
+ const n = raw ? parseInt(raw, 10) : NaN;
6652
+ return Number.isFinite(n) ? n : 0;
6653
+ }
6654
+ function applyCarouselValue(key, slides) {
6655
+ const value = JSON.stringify(slides);
6656
+ for (const container of containersForKey(key)) {
6657
+ if (container.getAttribute(CAROUSEL_VALUE_ATTR) === value) continue;
6658
+ container.setAttribute(CAROUSEL_VALUE_ATTR, value);
6659
+ container.dispatchEvent(
6660
+ new CustomEvent(CAROUSEL_EVENT, { detail: { images: slides } })
6661
+ );
6662
+ }
6663
+ }
6664
+ function applyCarouselNode(key, val) {
6665
+ if (!isCarouselKey(key)) return false;
6666
+ applyCarouselValue(key, parseSlides(val));
6667
+ return true;
6668
+ }
6669
+ function useOhwCarousel(key, initial) {
6670
+ const [images, setImages] = (0, import_react8.useState)(initial);
6671
+ (0, import_react8.useEffect)(() => {
6672
+ const el = document.querySelector(
6673
+ `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
6674
+ );
6675
+ if (!el) return;
6676
+ const onChange = (e) => {
6677
+ const detail = e.detail;
6678
+ if (Array.isArray(detail?.images)) setImages(detail.images);
6679
+ };
6680
+ el.addEventListener(CAROUSEL_EVENT, onChange);
6681
+ return () => el.removeEventListener(CAROUSEL_EVENT, onChange);
6682
+ }, [key]);
6683
+ const bind = {
6684
+ [CAROUSEL_ATTR]: "",
6685
+ "data-ohw-key": key,
6686
+ [CAROUSEL_VALUE_ATTR]: JSON.stringify(images)
6687
+ };
6688
+ return { images, setImages, bind };
6689
+ }
6690
+
6532
6691
  // src/ui/navbar-container-chrome.tsx
6533
- var import_lucide_react10 = require("lucide-react");
6534
- var import_jsx_runtime21 = require("react/jsx-runtime");
6692
+ var import_lucide_react11 = require("lucide-react");
6693
+ var import_jsx_runtime22 = require("react/jsx-runtime");
6535
6694
  function NavbarContainerChrome({
6536
6695
  rect,
6537
6696
  onAdd
6538
6697
  }) {
6539
6698
  const chromeGap = 6;
6540
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6699
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6541
6700
  "div",
6542
6701
  {
6543
6702
  "data-ohw-navbar-container-chrome": "",
@@ -6549,7 +6708,7 @@ function NavbarContainerChrome({
6549
6708
  width: rect.width + chromeGap * 2,
6550
6709
  height: rect.height + chromeGap * 2
6551
6710
  },
6552
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6711
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6553
6712
  "button",
6554
6713
  {
6555
6714
  type: "button",
@@ -6566,7 +6725,7 @@ function NavbarContainerChrome({
6566
6725
  e.stopPropagation();
6567
6726
  onAdd();
6568
6727
  },
6569
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
6728
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react11.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
6570
6729
  }
6571
6730
  )
6572
6731
  }
@@ -6574,7 +6733,7 @@ function NavbarContainerChrome({
6574
6733
  }
6575
6734
 
6576
6735
  // src/ui/badge.tsx
6577
- var import_jsx_runtime22 = require("react/jsx-runtime");
6736
+ var import_jsx_runtime23 = require("react/jsx-runtime");
6578
6737
  var badgeVariants = cva(
6579
6738
  "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
6580
6739
  {
@@ -6592,12 +6751,12 @@ var badgeVariants = cva(
6592
6751
  }
6593
6752
  );
6594
6753
  function Badge({ className, variant, ...props }) {
6595
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
6754
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
6596
6755
  }
6597
6756
 
6598
6757
  // src/OhhwellsBridge.tsx
6599
- var import_lucide_react11 = require("lucide-react");
6600
- var import_jsx_runtime23 = require("react/jsx-runtime");
6758
+ var import_lucide_react12 = require("lucide-react");
6759
+ var import_jsx_runtime24 = require("react/jsx-runtime");
6601
6760
  var PRIMARY2 = "#0885FE";
6602
6761
  var IMAGE_FADE_MS = 300;
6603
6762
  function runOpacityFade(el, onDone) {
@@ -6776,7 +6935,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
6776
6935
  const root = (0, import_client.createRoot)(container);
6777
6936
  (0, import_react_dom2.flushSync)(() => {
6778
6937
  root.render(
6779
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
6938
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
6780
6939
  SchedulingWidget,
6781
6940
  {
6782
6941
  notifyOnConnect,
@@ -6873,6 +7032,9 @@ function collectEditableNodes() {
6873
7032
  nodes.push({ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, type: "video-setting", text: String(video.autoplay) });
6874
7033
  nodes.push({ key: `${key}${VIDEO_MUTED_SUFFIX}`, type: "video-setting", text: String(video.muted) });
6875
7034
  });
7035
+ for (const key of listCarouselKeys()) {
7036
+ nodes.push({ key, type: "carousel", text: JSON.stringify(readCarouselValue(key)) });
7037
+ }
6876
7038
  return nodes;
6877
7039
  }
6878
7040
  function isMediaEditable(el) {
@@ -7259,7 +7421,7 @@ function EditGlowChrome({
7259
7421
  dragDisabled = false
7260
7422
  }) {
7261
7423
  const GAP = 6;
7262
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
7424
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
7263
7425
  "div",
7264
7426
  {
7265
7427
  ref: elRef,
@@ -7274,7 +7436,7 @@ function EditGlowChrome({
7274
7436
  zIndex: 2147483646
7275
7437
  },
7276
7438
  children: [
7277
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7439
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7278
7440
  "div",
7279
7441
  {
7280
7442
  style: {
@@ -7287,7 +7449,7 @@ function EditGlowChrome({
7287
7449
  }
7288
7450
  }
7289
7451
  ),
7290
- reorderHrefKey && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7452
+ reorderHrefKey && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7291
7453
  "div",
7292
7454
  {
7293
7455
  "data-ohw-drag-handle-container": "",
@@ -7299,7 +7461,7 @@ function EditGlowChrome({
7299
7461
  transform: "translate(calc(-100% - 7px), -50%)",
7300
7462
  pointerEvents: dragDisabled ? "none" : "auto"
7301
7463
  },
7302
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7464
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7303
7465
  DragHandle,
7304
7466
  {
7305
7467
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -7403,7 +7565,7 @@ function FloatingToolbar({
7403
7565
  onEditLink
7404
7566
  }) {
7405
7567
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, 330);
7406
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7568
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7407
7569
  "div",
7408
7570
  {
7409
7571
  ref: elRef,
@@ -7424,12 +7586,12 @@ function FloatingToolbar({
7424
7586
  fontFamily: "sans-serif",
7425
7587
  pointerEvents: "auto"
7426
7588
  },
7427
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CustomToolbar, { children: [
7428
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react8.default.Fragment, { children: [
7429
- gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CustomToolbarDivider, {}),
7589
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(CustomToolbar, { children: [
7590
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react9.default.Fragment, { children: [
7591
+ gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(CustomToolbarDivider, {}),
7430
7592
  btns.map((btn) => {
7431
7593
  const isActive = activeCommands.has(btn.cmd);
7432
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7594
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7433
7595
  CustomToolbarButton,
7434
7596
  {
7435
7597
  title: btn.title,
@@ -7438,7 +7600,7 @@ function FloatingToolbar({
7438
7600
  e.preventDefault();
7439
7601
  onCommand(btn.cmd);
7440
7602
  },
7441
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7603
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7442
7604
  "svg",
7443
7605
  {
7444
7606
  width: "16",
@@ -7459,7 +7621,7 @@ function FloatingToolbar({
7459
7621
  );
7460
7622
  })
7461
7623
  ] }, gi)),
7462
- showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7624
+ showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7463
7625
  CustomToolbarButton,
7464
7626
  {
7465
7627
  type: "button",
@@ -7473,7 +7635,7 @@ function FloatingToolbar({
7473
7635
  e.preventDefault();
7474
7636
  e.stopPropagation();
7475
7637
  },
7476
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.Link, { className: "size-4 shrink-0", "aria-hidden": true })
7638
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.Link, { className: "size-4 shrink-0", "aria-hidden": true })
7477
7639
  }
7478
7640
  ) : null
7479
7641
  ] })
@@ -7490,7 +7652,7 @@ function StateToggle({
7490
7652
  states,
7491
7653
  onStateChange
7492
7654
  }) {
7493
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7655
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7494
7656
  ToggleGroup,
7495
7657
  {
7496
7658
  "data-ohw-state-toggle": "",
@@ -7504,7 +7666,7 @@ function StateToggle({
7504
7666
  left: rect.right - 8,
7505
7667
  transform: "translateX(-100%)"
7506
7668
  },
7507
- children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
7669
+ children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
7508
7670
  }
7509
7671
  );
7510
7672
  }
@@ -7531,8 +7693,8 @@ function OhhwellsBridge() {
7531
7693
  const router = (0, import_navigation2.useRouter)();
7532
7694
  const searchParams = (0, import_navigation2.useSearchParams)();
7533
7695
  const isEditMode = isEditSessionActive();
7534
- const [bridgeRoot, setBridgeRoot] = (0, import_react8.useState)(null);
7535
- (0, import_react8.useEffect)(() => {
7696
+ const [bridgeRoot, setBridgeRoot] = (0, import_react9.useState)(null);
7697
+ (0, import_react9.useEffect)(() => {
7536
7698
  const figtreeFontId = "ohw-figtree-font";
7537
7699
  if (!document.getElementById(figtreeFontId)) {
7538
7700
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -7560,91 +7722,92 @@ function OhhwellsBridge() {
7560
7722
  const subdomainFromQuery = searchParams.get("subdomain");
7561
7723
  const subdomain = resolveSubdomain(subdomainFromQuery);
7562
7724
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
7563
- const postToParent2 = (0, import_react8.useCallback)((data) => {
7725
+ const postToParent2 = (0, import_react9.useCallback)((data) => {
7564
7726
  if (typeof window !== "undefined" && window.parent !== window) {
7565
7727
  window.parent.postMessage(data, "*");
7566
7728
  }
7567
7729
  }, []);
7568
- const [fetchState, setFetchState] = (0, import_react8.useState)("idle");
7569
- const autoSaveTimers = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
7570
- const activeElRef = (0, import_react8.useRef)(null);
7571
- const selectedElRef = (0, import_react8.useRef)(null);
7572
- const originalContentRef = (0, import_react8.useRef)(null);
7573
- const activeStateElRef = (0, import_react8.useRef)(null);
7574
- const parentScrollRef = (0, import_react8.useRef)(null);
7575
- const visibleViewportRef = (0, import_react8.useRef)(null);
7576
- const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react8.useState)(null);
7577
- const attachVisibleViewport = (0, import_react8.useCallback)((node) => {
7730
+ const [fetchState, setFetchState] = (0, import_react9.useState)("idle");
7731
+ const autoSaveTimers = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
7732
+ const activeElRef = (0, import_react9.useRef)(null);
7733
+ const selectedElRef = (0, import_react9.useRef)(null);
7734
+ const originalContentRef = (0, import_react9.useRef)(null);
7735
+ const activeStateElRef = (0, import_react9.useRef)(null);
7736
+ const parentScrollRef = (0, import_react9.useRef)(null);
7737
+ const visibleViewportRef = (0, import_react9.useRef)(null);
7738
+ const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react9.useState)(null);
7739
+ const attachVisibleViewport = (0, import_react9.useCallback)((node) => {
7578
7740
  visibleViewportRef.current = node;
7579
7741
  setDialogPortalContainer(node);
7580
7742
  if (node) applyVisibleViewport(node, parentScrollRef.current);
7581
7743
  }, []);
7582
- const toolbarElRef = (0, import_react8.useRef)(null);
7583
- const glowElRef = (0, import_react8.useRef)(null);
7584
- const hoveredImageRef = (0, import_react8.useRef)(null);
7585
- const hoveredImageHasTextOverlapRef = (0, import_react8.useRef)(false);
7586
- const dragOverElRef = (0, import_react8.useRef)(null);
7587
- const [mediaHover, setMediaHover] = (0, import_react8.useState)(null);
7588
- const [uploadingRects, setUploadingRects] = (0, import_react8.useState)({});
7589
- const hoveredGapRef = (0, import_react8.useRef)(null);
7590
- const imageUnhoverTimerRef = (0, import_react8.useRef)(null);
7591
- const imageShowTimerRef = (0, import_react8.useRef)(null);
7592
- const editStylesRef = (0, import_react8.useRef)(null);
7593
- const activateRef = (0, import_react8.useRef)(() => {
7744
+ const toolbarElRef = (0, import_react9.useRef)(null);
7745
+ const glowElRef = (0, import_react9.useRef)(null);
7746
+ const hoveredImageRef = (0, import_react9.useRef)(null);
7747
+ const hoveredImageHasTextOverlapRef = (0, import_react9.useRef)(false);
7748
+ const dragOverElRef = (0, import_react9.useRef)(null);
7749
+ const [mediaHover, setMediaHover] = (0, import_react9.useState)(null);
7750
+ const [carouselHover, setCarouselHover] = (0, import_react9.useState)(null);
7751
+ const [uploadingRects, setUploadingRects] = (0, import_react9.useState)({});
7752
+ const hoveredGapRef = (0, import_react9.useRef)(null);
7753
+ const imageUnhoverTimerRef = (0, import_react9.useRef)(null);
7754
+ const imageShowTimerRef = (0, import_react9.useRef)(null);
7755
+ const editStylesRef = (0, import_react9.useRef)(null);
7756
+ const activateRef = (0, import_react9.useRef)(() => {
7594
7757
  });
7595
- const deactivateRef = (0, import_react8.useRef)(() => {
7758
+ const deactivateRef = (0, import_react9.useRef)(() => {
7596
7759
  });
7597
- const selectRef = (0, import_react8.useRef)(() => {
7760
+ const selectRef = (0, import_react9.useRef)(() => {
7598
7761
  });
7599
- const selectFrameRef = (0, import_react8.useRef)(() => {
7762
+ const selectFrameRef = (0, import_react9.useRef)(() => {
7600
7763
  });
7601
- const deselectRef = (0, import_react8.useRef)(() => {
7764
+ const deselectRef = (0, import_react9.useRef)(() => {
7602
7765
  });
7603
- const reselectNavigationItemRef = (0, import_react8.useRef)(() => {
7766
+ const reselectNavigationItemRef = (0, import_react9.useRef)(() => {
7604
7767
  });
7605
- const commitNavigationTextEditRef = (0, import_react8.useRef)(() => {
7768
+ const commitNavigationTextEditRef = (0, import_react9.useRef)(() => {
7606
7769
  });
7607
- const refreshActiveCommandsRef = (0, import_react8.useRef)(() => {
7770
+ const refreshActiveCommandsRef = (0, import_react9.useRef)(() => {
7608
7771
  });
7609
- const postToParentRef = (0, import_react8.useRef)(postToParent2);
7772
+ const postToParentRef = (0, import_react9.useRef)(postToParent2);
7610
7773
  postToParentRef.current = postToParent2;
7611
- const sectionsLoadedRef = (0, import_react8.useRef)(false);
7612
- const pendingScheduleConfigRequests = (0, import_react8.useRef)([]);
7613
- const [toolbarRect, setToolbarRect] = (0, import_react8.useState)(null);
7614
- const [toolbarVariant, setToolbarVariant] = (0, import_react8.useState)("none");
7615
- const toolbarVariantRef = (0, import_react8.useRef)("none");
7774
+ const sectionsLoadedRef = (0, import_react9.useRef)(false);
7775
+ const pendingScheduleConfigRequests = (0, import_react9.useRef)([]);
7776
+ const [toolbarRect, setToolbarRect] = (0, import_react9.useState)(null);
7777
+ const [toolbarVariant, setToolbarVariant] = (0, import_react9.useState)("none");
7778
+ const toolbarVariantRef = (0, import_react9.useRef)("none");
7616
7779
  toolbarVariantRef.current = toolbarVariant;
7617
- const [reorderHrefKey, setReorderHrefKey] = (0, import_react8.useState)(null);
7618
- const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react8.useState)(false);
7619
- const [toggleState, setToggleState] = (0, import_react8.useState)(null);
7620
- const [maxBadge, setMaxBadge] = (0, import_react8.useState)(null);
7621
- const [activeCommands, setActiveCommands] = (0, import_react8.useState)(/* @__PURE__ */ new Set());
7622
- const [sectionGap, setSectionGap] = (0, import_react8.useState)(null);
7623
- const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react8.useState)(false);
7624
- const hoveredNavContainerRef = (0, import_react8.useRef)(null);
7625
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react8.useState)(null);
7626
- const hoveredItemElRef = (0, import_react8.useRef)(null);
7627
- const [hoveredItemRect, setHoveredItemRect] = (0, import_react8.useState)(null);
7628
- const siblingHintElRef = (0, import_react8.useRef)(null);
7629
- const [siblingHintRect, setSiblingHintRect] = (0, import_react8.useState)(null);
7630
- const [isItemDragging, setIsItemDragging] = (0, import_react8.useState)(false);
7631
- const [linkPopover, setLinkPopover] = (0, import_react8.useState)(null);
7632
- const linkPopoverSessionRef = (0, import_react8.useRef)(null);
7633
- const addNavAfterAnchorRef = (0, import_react8.useRef)(null);
7634
- const editContentRef = (0, import_react8.useRef)({});
7635
- const [sitePages, setSitePages] = (0, import_react8.useState)([]);
7636
- const [sectionsByPath, setSectionsByPath] = (0, import_react8.useState)({});
7637
- const sectionsPrefetchGenRef = (0, import_react8.useRef)(0);
7638
- const setLinkPopoverRef = (0, import_react8.useRef)(setLinkPopover);
7639
- const linkPopoverPanelRef = (0, import_react8.useRef)(null);
7640
- const linkPopoverOpenRef = (0, import_react8.useRef)(false);
7641
- const linkPopoverGraceUntilRef = (0, import_react8.useRef)(0);
7780
+ const [reorderHrefKey, setReorderHrefKey] = (0, import_react9.useState)(null);
7781
+ const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react9.useState)(false);
7782
+ const [toggleState, setToggleState] = (0, import_react9.useState)(null);
7783
+ const [maxBadge, setMaxBadge] = (0, import_react9.useState)(null);
7784
+ const [activeCommands, setActiveCommands] = (0, import_react9.useState)(/* @__PURE__ */ new Set());
7785
+ const [sectionGap, setSectionGap] = (0, import_react9.useState)(null);
7786
+ const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react9.useState)(false);
7787
+ const hoveredNavContainerRef = (0, import_react9.useRef)(null);
7788
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react9.useState)(null);
7789
+ const hoveredItemElRef = (0, import_react9.useRef)(null);
7790
+ const [hoveredItemRect, setHoveredItemRect] = (0, import_react9.useState)(null);
7791
+ const siblingHintElRef = (0, import_react9.useRef)(null);
7792
+ const [siblingHintRect, setSiblingHintRect] = (0, import_react9.useState)(null);
7793
+ const [isItemDragging, setIsItemDragging] = (0, import_react9.useState)(false);
7794
+ const [linkPopover, setLinkPopover] = (0, import_react9.useState)(null);
7795
+ const linkPopoverSessionRef = (0, import_react9.useRef)(null);
7796
+ const addNavAfterAnchorRef = (0, import_react9.useRef)(null);
7797
+ const editContentRef = (0, import_react9.useRef)({});
7798
+ const [sitePages, setSitePages] = (0, import_react9.useState)([]);
7799
+ const [sectionsByPath, setSectionsByPath] = (0, import_react9.useState)({});
7800
+ const sectionsPrefetchGenRef = (0, import_react9.useRef)(0);
7801
+ const setLinkPopoverRef = (0, import_react9.useRef)(setLinkPopover);
7802
+ const linkPopoverPanelRef = (0, import_react9.useRef)(null);
7803
+ const linkPopoverOpenRef = (0, import_react9.useRef)(false);
7804
+ const linkPopoverGraceUntilRef = (0, import_react9.useRef)(0);
7642
7805
  setLinkPopoverRef.current = setLinkPopover;
7643
7806
  linkPopoverSessionRef.current = linkPopover;
7644
7807
  const bumpLinkPopoverGrace = () => {
7645
7808
  linkPopoverGraceUntilRef.current = Date.now() + 350;
7646
7809
  };
7647
- const runSectionsPrefetch = (0, import_react8.useCallback)((pages) => {
7810
+ const runSectionsPrefetch = (0, import_react9.useCallback)((pages) => {
7648
7811
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
7649
7812
  const gen = ++sectionsPrefetchGenRef.current;
7650
7813
  const paths = pages.map((p) => p.path);
@@ -7663,9 +7826,9 @@ function OhhwellsBridge() {
7663
7826
  );
7664
7827
  });
7665
7828
  }, [isEditMode, pathname]);
7666
- const runSectionsPrefetchRef = (0, import_react8.useRef)(runSectionsPrefetch);
7829
+ const runSectionsPrefetchRef = (0, import_react9.useRef)(runSectionsPrefetch);
7667
7830
  runSectionsPrefetchRef.current = runSectionsPrefetch;
7668
- (0, import_react8.useEffect)(() => {
7831
+ (0, import_react9.useEffect)(() => {
7669
7832
  if (!linkPopover) return;
7670
7833
  if (hoveredImageRef.current) {
7671
7834
  hoveredImageRef.current = null;
@@ -7675,7 +7838,7 @@ function OhhwellsBridge() {
7675
7838
  setSectionGap(null);
7676
7839
  postToParent2({ type: "ow:image-unhover" });
7677
7840
  }, [linkPopover, postToParent2]);
7678
- (0, import_react8.useEffect)(() => {
7841
+ (0, import_react9.useEffect)(() => {
7679
7842
  if (!isEditMode) return;
7680
7843
  const useFixtures = shouldUseDevFixtures();
7681
7844
  if (useFixtures) {
@@ -7699,14 +7862,14 @@ function OhhwellsBridge() {
7699
7862
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
7700
7863
  return () => window.removeEventListener("message", onSitePages);
7701
7864
  }, [isEditMode, postToParent2]);
7702
- (0, import_react8.useEffect)(() => {
7865
+ (0, import_react9.useEffect)(() => {
7703
7866
  if (!isEditMode || shouldUseDevFixtures()) return;
7704
7867
  void loadAllSectionsManifest().then((manifest) => {
7705
7868
  if (Object.keys(manifest).length === 0) return;
7706
7869
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
7707
7870
  });
7708
7871
  }, [isEditMode]);
7709
- (0, import_react8.useEffect)(() => {
7872
+ (0, import_react9.useEffect)(() => {
7710
7873
  const update = () => {
7711
7874
  const el = activeElRef.current ?? selectedElRef.current;
7712
7875
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -7730,10 +7893,10 @@ function OhhwellsBridge() {
7730
7893
  vvp.removeEventListener("resize", update);
7731
7894
  };
7732
7895
  }, []);
7733
- const refreshStateRules = (0, import_react8.useCallback)(() => {
7896
+ const refreshStateRules = (0, import_react9.useCallback)(() => {
7734
7897
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
7735
7898
  }, []);
7736
- const processConfigRequest = (0, import_react8.useCallback)((insertAfterVal) => {
7899
+ const processConfigRequest = (0, import_react9.useCallback)((insertAfterVal) => {
7737
7900
  const tracker = getSectionsTracker();
7738
7901
  let entries = [];
7739
7902
  try {
@@ -7756,7 +7919,7 @@ function OhhwellsBridge() {
7756
7919
  }
7757
7920
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
7758
7921
  }, [isEditMode]);
7759
- const deactivate = (0, import_react8.useCallback)(() => {
7922
+ const deactivate = (0, import_react9.useCallback)(() => {
7760
7923
  const el = activeElRef.current;
7761
7924
  if (!el) return;
7762
7925
  const key = el.dataset.ohwKey;
@@ -7787,7 +7950,7 @@ function OhhwellsBridge() {
7787
7950
  setToolbarShowEditLink(false);
7788
7951
  postToParent2({ type: "ow:exit-edit" });
7789
7952
  }, [postToParent2]);
7790
- const deselect = (0, import_react8.useCallback)(() => {
7953
+ const deselect = (0, import_react9.useCallback)(() => {
7791
7954
  selectedElRef.current = null;
7792
7955
  setReorderHrefKey(null);
7793
7956
  setReorderDragDisabled(false);
@@ -7801,7 +7964,7 @@ function OhhwellsBridge() {
7801
7964
  setToolbarVariant("none");
7802
7965
  }
7803
7966
  }, []);
7804
- const reselectNavigationItem = (0, import_react8.useCallback)((navAnchor) => {
7967
+ const reselectNavigationItem = (0, import_react9.useCallback)((navAnchor) => {
7805
7968
  selectedElRef.current = navAnchor;
7806
7969
  const { key, disabled } = getNavigationItemReorderState(navAnchor);
7807
7970
  setReorderHrefKey(key);
@@ -7811,7 +7974,7 @@ function OhhwellsBridge() {
7811
7974
  setToolbarShowEditLink(false);
7812
7975
  setActiveCommands(/* @__PURE__ */ new Set());
7813
7976
  }, []);
7814
- const commitNavigationTextEdit = (0, import_react8.useCallback)((navAnchor) => {
7977
+ const commitNavigationTextEdit = (0, import_react9.useCallback)((navAnchor) => {
7815
7978
  const el = activeElRef.current;
7816
7979
  if (!el) return;
7817
7980
  const key = el.dataset.ohwKey;
@@ -7837,7 +8000,7 @@ function OhhwellsBridge() {
7837
8000
  postToParent2({ type: "ow:exit-edit" });
7838
8001
  reselectNavigationItem(navAnchor);
7839
8002
  }, [postToParent2, reselectNavigationItem]);
7840
- const handleAddTopLevelNavItem = (0, import_react8.useCallback)(() => {
8003
+ const handleAddTopLevelNavItem = (0, import_react9.useCallback)(() => {
7841
8004
  const items = listNavbarItems();
7842
8005
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
7843
8006
  deselectRef.current();
@@ -7849,17 +8012,17 @@ function OhhwellsBridge() {
7849
8012
  intent: "add-nav"
7850
8013
  });
7851
8014
  }, []);
7852
- const handleItemDragStart = (0, import_react8.useCallback)(() => {
8015
+ const handleItemDragStart = (0, import_react9.useCallback)(() => {
7853
8016
  siblingHintElRef.current = null;
7854
8017
  setSiblingHintRect(null);
7855
8018
  setIsItemDragging(true);
7856
8019
  }, []);
7857
- const handleItemDragEnd = (0, import_react8.useCallback)(() => {
8020
+ const handleItemDragEnd = (0, import_react9.useCallback)(() => {
7858
8021
  setIsItemDragging(false);
7859
8022
  }, []);
7860
8023
  reselectNavigationItemRef.current = reselectNavigationItem;
7861
8024
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
7862
- const select = (0, import_react8.useCallback)((anchor) => {
8025
+ const select = (0, import_react9.useCallback)((anchor) => {
7863
8026
  if (!isNavigationItem(anchor)) return;
7864
8027
  if (activeElRef.current) deactivate();
7865
8028
  selectedElRef.current = anchor;
@@ -7879,7 +8042,7 @@ function OhhwellsBridge() {
7879
8042
  setToolbarShowEditLink(false);
7880
8043
  setActiveCommands(/* @__PURE__ */ new Set());
7881
8044
  }, [deactivate]);
7882
- const selectFrame = (0, import_react8.useCallback)((el) => {
8045
+ const selectFrame = (0, import_react9.useCallback)((el) => {
7883
8046
  if (!isNavigationContainer(el)) return;
7884
8047
  if (activeElRef.current) deactivate();
7885
8048
  selectedElRef.current = el;
@@ -7898,7 +8061,7 @@ function OhhwellsBridge() {
7898
8061
  setToolbarShowEditLink(false);
7899
8062
  setActiveCommands(/* @__PURE__ */ new Set());
7900
8063
  }, [deactivate]);
7901
- const activate = (0, import_react8.useCallback)((el, options) => {
8064
+ const activate = (0, import_react9.useCallback)((el, options) => {
7902
8065
  if (activeElRef.current === el) return;
7903
8066
  selectedElRef.current = null;
7904
8067
  deactivate();
@@ -7938,7 +8101,7 @@ function OhhwellsBridge() {
7938
8101
  selectRef.current = select;
7939
8102
  selectFrameRef.current = selectFrame;
7940
8103
  deselectRef.current = deselect;
7941
- (0, import_react8.useLayoutEffect)(() => {
8104
+ (0, import_react9.useLayoutEffect)(() => {
7942
8105
  if (!subdomain || isEditMode) {
7943
8106
  setFetchState("done");
7944
8107
  return;
@@ -7948,6 +8111,7 @@ function OhhwellsBridge() {
7948
8111
  for (const [key, val] of Object.entries(content)) {
7949
8112
  if (key === "__ohw_sections") continue;
7950
8113
  if (applyVideoSettingNode(key, val)) continue;
8114
+ if (applyCarouselNode(key, val)) continue;
7951
8115
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
7952
8116
  if (el.dataset.ohwEditable === "image") {
7953
8117
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -8007,7 +8171,7 @@ function OhhwellsBridge() {
8007
8171
  cancelled = true;
8008
8172
  };
8009
8173
  }, [subdomain, isEditMode]);
8010
- (0, import_react8.useEffect)(() => {
8174
+ (0, import_react9.useEffect)(() => {
8011
8175
  if (!subdomain || isEditMode) return;
8012
8176
  let debounceTimer = null;
8013
8177
  let observer = null;
@@ -8020,6 +8184,7 @@ function OhhwellsBridge() {
8020
8184
  for (const [key, val] of Object.entries(content)) {
8021
8185
  if (key === "__ohw_sections") continue;
8022
8186
  if (applyVideoSettingNode(key, val)) continue;
8187
+ if (applyCarouselNode(key, val)) continue;
8023
8188
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
8024
8189
  if (el.dataset.ohwEditable === "image") {
8025
8190
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -8056,16 +8221,16 @@ function OhhwellsBridge() {
8056
8221
  if (debounceTimer) clearTimeout(debounceTimer);
8057
8222
  };
8058
8223
  }, [subdomain, isEditMode, pathname]);
8059
- (0, import_react8.useLayoutEffect)(() => {
8224
+ (0, import_react9.useLayoutEffect)(() => {
8060
8225
  const el = document.getElementById("ohw-loader");
8061
8226
  if (!el) return;
8062
8227
  const visible = Boolean(subdomain) && fetchState !== "done";
8063
8228
  el.style.display = visible ? "flex" : "none";
8064
8229
  }, [subdomain, fetchState]);
8065
- (0, import_react8.useEffect)(() => {
8230
+ (0, import_react9.useEffect)(() => {
8066
8231
  postToParent2({ type: "ow:navigation", path: pathname });
8067
8232
  }, [pathname, postToParent2]);
8068
- (0, import_react8.useEffect)(() => {
8233
+ (0, import_react9.useEffect)(() => {
8069
8234
  if (!isEditMode) return;
8070
8235
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
8071
8236
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -8073,7 +8238,7 @@ function OhhwellsBridge() {
8073
8238
  deselectRef.current();
8074
8239
  deactivateRef.current();
8075
8240
  }, [pathname, isEditMode]);
8076
- (0, import_react8.useEffect)(() => {
8241
+ (0, import_react9.useEffect)(() => {
8077
8242
  const contentForNav = () => {
8078
8243
  if (isEditMode) return editContentRef.current;
8079
8244
  if (!subdomain) return {};
@@ -8089,7 +8254,7 @@ function OhhwellsBridge() {
8089
8254
  observer.observe(nav, { childList: true, subtree: true });
8090
8255
  return () => observer.disconnect();
8091
8256
  }, [isEditMode, pathname, subdomain, fetchState]);
8092
- (0, import_react8.useEffect)(() => {
8257
+ (0, import_react9.useEffect)(() => {
8093
8258
  if (!isEditMode) return;
8094
8259
  const measure = () => {
8095
8260
  const h = document.body.scrollHeight;
@@ -8113,7 +8278,7 @@ function OhhwellsBridge() {
8113
8278
  window.removeEventListener("resize", handleResize);
8114
8279
  };
8115
8280
  }, [pathname, isEditMode, postToParent2]);
8116
- (0, import_react8.useEffect)(() => {
8281
+ (0, import_react9.useEffect)(() => {
8117
8282
  if (!subdomainFromQuery || isEditMode) return;
8118
8283
  const handleClick = (e) => {
8119
8284
  const anchor = e.target.closest("a");
@@ -8129,7 +8294,7 @@ function OhhwellsBridge() {
8129
8294
  document.addEventListener("click", handleClick, true);
8130
8295
  return () => document.removeEventListener("click", handleClick, true);
8131
8296
  }, [subdomainFromQuery, isEditMode, router]);
8132
- (0, import_react8.useEffect)(() => {
8297
+ (0, import_react9.useEffect)(() => {
8133
8298
  if (!isEditMode) {
8134
8299
  editStylesRef.current?.base.remove();
8135
8300
  editStylesRef.current?.forceHover.remove();
@@ -8958,6 +9123,7 @@ function OhhwellsBridge() {
8958
9123
  continue;
8959
9124
  }
8960
9125
  if (applyVideoSettingNode(key, val)) continue;
9126
+ if (applyCarouselNode(key, val)) continue;
8961
9127
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
8962
9128
  if (el.dataset.ohwEditable === "image") {
8963
9129
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -8998,6 +9164,13 @@ function OhhwellsBridge() {
8998
9164
  deactivateRef.current();
8999
9165
  };
9000
9166
  window.addEventListener("message", handleDeactivate);
9167
+ const handleUiEscape = (e) => {
9168
+ if (e.data?.type !== "ui:escape") return;
9169
+ if (linkPopoverOpenRef.current) {
9170
+ setLinkPopoverRef.current(null);
9171
+ }
9172
+ };
9173
+ window.addEventListener("message", handleUiEscape);
9001
9174
  const handleKeyDown = (e) => {
9002
9175
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
9003
9176
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
@@ -9222,6 +9395,48 @@ function OhhwellsBridge() {
9222
9395
  if (e.data?.type !== "ow:canvas-height" || typeof e.data.height !== "number") return;
9223
9396
  document.documentElement.style.setProperty("--ohw-canvas-h", `${e.data.height}px`);
9224
9397
  };
9398
+ const handleCarouselChange = (e) => {
9399
+ if (e.data?.type !== "ow:carousel-change") return;
9400
+ const { key, images } = e.data;
9401
+ if (!key || !Array.isArray(images)) return;
9402
+ const text = JSON.stringify(images);
9403
+ applyCarouselValue(key, images);
9404
+ editContentRef.current = { ...editContentRef.current, [key]: text };
9405
+ postToParentRef.current({ type: "ow:change", nodes: [{ key, text }] });
9406
+ setCarouselHover(null);
9407
+ };
9408
+ const findCarouselAtPoint = (clientX, clientY) => {
9409
+ const containers = Array.from(document.querySelectorAll(`[${CAROUSEL_ATTR}]`));
9410
+ for (let i = containers.length - 1; i >= 0; i--) {
9411
+ const r2 = containers[i].getBoundingClientRect();
9412
+ if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) {
9413
+ return containers[i];
9414
+ }
9415
+ }
9416
+ return null;
9417
+ };
9418
+ const isPointOverEditable = (scope, clientX, clientY) => {
9419
+ const editables = scope.querySelectorAll("[data-ohw-editable], [data-ohw-href-key]");
9420
+ for (const el of editables) {
9421
+ const r2 = el.getBoundingClientRect();
9422
+ if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) return true;
9423
+ }
9424
+ return false;
9425
+ };
9426
+ const handleCarouselHover = (e) => {
9427
+ const container = findCarouselAtPoint(e.clientX, e.clientY);
9428
+ const scope = container?.closest("[data-ohw-section]") ?? container?.parentElement ?? null;
9429
+ if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY)) {
9430
+ setCarouselHover((prev) => prev ? null : prev);
9431
+ return;
9432
+ }
9433
+ const key = container.getAttribute("data-ohw-key") ?? "";
9434
+ if (!key) return;
9435
+ const r2 = getVisibleRect(container);
9436
+ setCarouselHover(
9437
+ (prev) => prev && prev.key === key && prev.rect.top === r2.top && prev.rect.left === r2.left && prev.rect.width === r2.width && prev.rect.height === r2.height ? prev : { key, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } }
9438
+ );
9439
+ };
9225
9440
  const applyToolbarPos = (rect) => {
9226
9441
  const ps = parentScrollRef.current;
9227
9442
  const approxW = 330;
@@ -9330,6 +9545,7 @@ function OhhwellsBridge() {
9330
9545
  window.addEventListener("message", handleRemoveSchedulingSection);
9331
9546
  window.addEventListener("message", handleImageUrl);
9332
9547
  window.addEventListener("message", handleImageUploading);
9548
+ window.addEventListener("message", handleCarouselChange);
9333
9549
  window.addEventListener("message", handleCanvasHeight);
9334
9550
  window.addEventListener("message", handleParentScroll);
9335
9551
  window.addEventListener("message", handlePointerSync);
@@ -9347,6 +9563,7 @@ function OhhwellsBridge() {
9347
9563
  document.addEventListener("mouseover", handleMouseOver, true);
9348
9564
  document.addEventListener("mouseout", handleMouseOut, true);
9349
9565
  document.addEventListener("mousemove", handleMouseMove, true);
9566
+ document.addEventListener("mousemove", handleCarouselHover, true);
9350
9567
  document.addEventListener("mouseleave", handleDocMouseLeave);
9351
9568
  document.addEventListener("dragover", handleDragOver, true);
9352
9569
  document.addEventListener("dragleave", handleDragLeave, true);
@@ -9362,6 +9579,7 @@ function OhhwellsBridge() {
9362
9579
  document.removeEventListener("mouseover", handleMouseOver, true);
9363
9580
  document.removeEventListener("mouseout", handleMouseOut, true);
9364
9581
  document.removeEventListener("mousemove", handleMouseMove, true);
9582
+ document.removeEventListener("mousemove", handleCarouselHover, true);
9365
9583
  document.removeEventListener("mouseleave", handleDocMouseLeave);
9366
9584
  document.removeEventListener("dragover", handleDragOver, true);
9367
9585
  document.removeEventListener("dragleave", handleDragLeave, true);
@@ -9377,6 +9595,7 @@ function OhhwellsBridge() {
9377
9595
  window.removeEventListener("message", handleRemoveSchedulingSection);
9378
9596
  window.removeEventListener("message", handleImageUrl);
9379
9597
  window.removeEventListener("message", handleImageUploading);
9598
+ window.removeEventListener("message", handleCarouselChange);
9380
9599
  window.removeEventListener("message", handleCanvasHeight);
9381
9600
  window.removeEventListener("message", handleParentScroll);
9382
9601
  window.removeEventListener("resize", handleViewportResize);
@@ -9384,13 +9603,14 @@ function OhhwellsBridge() {
9384
9603
  window.removeEventListener("message", handleClickAt);
9385
9604
  window.removeEventListener("message", handleHydrate);
9386
9605
  window.removeEventListener("message", handleDeactivate);
9606
+ window.removeEventListener("message", handleUiEscape);
9387
9607
  autoSaveTimers.current.forEach(clearTimeout);
9388
9608
  autoSaveTimers.current.clear();
9389
9609
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
9390
9610
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
9391
9611
  };
9392
9612
  }, [isEditMode, refreshStateRules]);
9393
- (0, import_react8.useEffect)(() => {
9613
+ (0, import_react9.useEffect)(() => {
9394
9614
  const handler = (e) => {
9395
9615
  if (e.data?.type !== "ow:request-schedule-config") return;
9396
9616
  const insertAfterVal = e.data.insertAfter;
@@ -9406,7 +9626,7 @@ function OhhwellsBridge() {
9406
9626
  window.addEventListener("message", handler);
9407
9627
  return () => window.removeEventListener("message", handler);
9408
9628
  }, [processConfigRequest]);
9409
- (0, import_react8.useEffect)(() => {
9629
+ (0, import_react9.useEffect)(() => {
9410
9630
  if (!isEditMode) return;
9411
9631
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
9412
9632
  el.removeAttribute("data-ohw-active-state");
@@ -9435,19 +9655,19 @@ function OhhwellsBridge() {
9435
9655
  clearTimeout(timer);
9436
9656
  };
9437
9657
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
9438
- (0, import_react8.useEffect)(() => {
9658
+ (0, import_react9.useEffect)(() => {
9439
9659
  scrollToHashSectionWhenReady();
9440
9660
  const onHashChange = () => scrollToHashSectionWhenReady();
9441
9661
  window.addEventListener("hashchange", onHashChange);
9442
9662
  return () => window.removeEventListener("hashchange", onHashChange);
9443
9663
  }, [pathname]);
9444
- const handleCommand = (0, import_react8.useCallback)((cmd) => {
9664
+ const handleCommand = (0, import_react9.useCallback)((cmd) => {
9445
9665
  document.execCommand(cmd, false);
9446
9666
  activeElRef.current?.focus();
9447
9667
  if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
9448
9668
  refreshActiveCommandsRef.current();
9449
9669
  }, []);
9450
- const handleStateChange = (0, import_react8.useCallback)((state) => {
9670
+ const handleStateChange = (0, import_react9.useCallback)((state) => {
9451
9671
  if (!activeStateElRef.current) return;
9452
9672
  const el = activeStateElRef.current;
9453
9673
  if (state === "Default") {
@@ -9460,11 +9680,11 @@ function OhhwellsBridge() {
9460
9680
  }
9461
9681
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
9462
9682
  }, [deactivate]);
9463
- const closeLinkPopover = (0, import_react8.useCallback)(() => {
9683
+ const closeLinkPopover = (0, import_react9.useCallback)(() => {
9464
9684
  addNavAfterAnchorRef.current = null;
9465
9685
  setLinkPopover(null);
9466
9686
  }, []);
9467
- const openLinkPopoverForActive = (0, import_react8.useCallback)(() => {
9687
+ const openLinkPopoverForActive = (0, import_react9.useCallback)(() => {
9468
9688
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
9469
9689
  if (!hrefCtx) return;
9470
9690
  bumpLinkPopoverGrace();
@@ -9475,7 +9695,7 @@ function OhhwellsBridge() {
9475
9695
  });
9476
9696
  deactivate();
9477
9697
  }, [deactivate]);
9478
- const openLinkPopoverForSelected = (0, import_react8.useCallback)(() => {
9698
+ const openLinkPopoverForSelected = (0, import_react9.useCallback)(() => {
9479
9699
  const anchor = selectedElRef.current;
9480
9700
  if (!anchor) return;
9481
9701
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -9488,7 +9708,7 @@ function OhhwellsBridge() {
9488
9708
  });
9489
9709
  deselect();
9490
9710
  }, [deselect]);
9491
- const handleLinkPopoverSubmit = (0, import_react8.useCallback)(
9711
+ const handleLinkPopoverSubmit = (0, import_react9.useCallback)(
9492
9712
  (target) => {
9493
9713
  const session = linkPopoverSessionRef.current;
9494
9714
  if (!session) return;
@@ -9547,13 +9767,19 @@ function OhhwellsBridge() {
9547
9767
  const showEditLink = toolbarShowEditLink;
9548
9768
  const currentSections = sectionsByPath[pathname] ?? [];
9549
9769
  linkPopoverOpenRef.current = linkPopover !== null;
9550
- const handleMediaReplace = (0, import_react8.useCallback)(
9770
+ const handleMediaReplace = (0, import_react9.useCallback)(
9551
9771
  (key) => {
9552
9772
  postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
9553
9773
  },
9554
9774
  [postToParent2, mediaHover?.elementType]
9555
9775
  );
9556
- const handleMediaFadeOutComplete = (0, import_react8.useCallback)((key) => {
9776
+ const handleEditCarousel = (0, import_react9.useCallback)(
9777
+ (key) => {
9778
+ postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
9779
+ },
9780
+ [postToParent2]
9781
+ );
9782
+ const handleMediaFadeOutComplete = (0, import_react9.useCallback)((key) => {
9557
9783
  setUploadingRects((prev) => {
9558
9784
  if (!(key in prev)) return prev;
9559
9785
  const next = { ...prev };
@@ -9561,7 +9787,7 @@ function OhhwellsBridge() {
9561
9787
  return next;
9562
9788
  });
9563
9789
  }, []);
9564
- const handleVideoSettingsChange = (0, import_react8.useCallback)(
9790
+ const handleVideoSettingsChange = (0, import_react9.useCallback)(
9565
9791
  (key, settings) => {
9566
9792
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
9567
9793
  const video = getVideoEl(el);
@@ -9584,9 +9810,9 @@ function OhhwellsBridge() {
9584
9810
  [postToParent2]
9585
9811
  );
9586
9812
  return bridgeRoot ? (0, import_react_dom3.createPortal)(
9587
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
9588
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
9589
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9813
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
9814
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
9815
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9590
9816
  MediaOverlay,
9591
9817
  {
9592
9818
  hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
@@ -9597,7 +9823,7 @@ function OhhwellsBridge() {
9597
9823
  },
9598
9824
  `uploading-${key}`
9599
9825
  )),
9600
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9826
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9601
9827
  MediaOverlay,
9602
9828
  {
9603
9829
  hover: mediaHover,
@@ -9606,17 +9832,18 @@ function OhhwellsBridge() {
9606
9832
  onVideoSettingsChange: handleVideoSettingsChange
9607
9833
  }
9608
9834
  ),
9609
- siblingHintRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
9610
- hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && !siblingHintRect && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
9611
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9835
+ carouselHover && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
9836
+ siblingHintRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
9837
+ hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && !siblingHintRect && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
9838
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9612
9839
  NavbarContainerChrome,
9613
9840
  {
9614
9841
  rect: toolbarRect,
9615
9842
  onAdd: handleAddTopLevelNavItem
9616
9843
  }
9617
9844
  ),
9618
- hoveredItemRect && !hoveredNavContainerRect && !siblingHintRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
9619
- toolbarRect && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9845
+ hoveredItemRect && !hoveredNavContainerRect && !siblingHintRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
9846
+ toolbarRect && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9620
9847
  ItemInteractionLayer,
9621
9848
  {
9622
9849
  rect: toolbarRect,
@@ -9627,7 +9854,7 @@ function OhhwellsBridge() {
9627
9854
  dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
9628
9855
  onDragHandleDragStart: handleItemDragStart,
9629
9856
  onDragHandleDragEnd: handleItemDragEnd,
9630
- toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9857
+ toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9631
9858
  ItemActionToolbar,
9632
9859
  {
9633
9860
  onEditLink: openLinkPopoverForSelected,
@@ -9638,8 +9865,8 @@ function OhhwellsBridge() {
9638
9865
  ) : void 0
9639
9866
  }
9640
9867
  ),
9641
- toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
9642
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9868
+ toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
9869
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9643
9870
  EditGlowChrome,
9644
9871
  {
9645
9872
  rect: toolbarRect,
@@ -9648,7 +9875,7 @@ function OhhwellsBridge() {
9648
9875
  dragDisabled: reorderDragDisabled
9649
9876
  }
9650
9877
  ),
9651
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9878
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9652
9879
  FloatingToolbar,
9653
9880
  {
9654
9881
  rect: toolbarRect,
@@ -9661,7 +9888,7 @@ function OhhwellsBridge() {
9661
9888
  }
9662
9889
  )
9663
9890
  ] }),
9664
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9891
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9665
9892
  "div",
9666
9893
  {
9667
9894
  "data-ohw-max-badge": "",
@@ -9687,7 +9914,7 @@ function OhhwellsBridge() {
9687
9914
  ]
9688
9915
  }
9689
9916
  ),
9690
- toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9917
+ toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9691
9918
  StateToggle,
9692
9919
  {
9693
9920
  rect: toggleState.rect,
@@ -9696,15 +9923,15 @@ function OhhwellsBridge() {
9696
9923
  onStateChange: handleStateChange
9697
9924
  }
9698
9925
  ),
9699
- sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9926
+ sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9700
9927
  "div",
9701
9928
  {
9702
9929
  "data-ohw-section-insert-line": "",
9703
9930
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
9704
9931
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
9705
9932
  children: [
9706
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
9707
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9933
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
9934
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9708
9935
  Badge,
9709
9936
  {
9710
9937
  className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
@@ -9717,11 +9944,11 @@ function OhhwellsBridge() {
9717
9944
  children: "Add Section"
9718
9945
  }
9719
9946
  ),
9720
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
9947
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
9721
9948
  ]
9722
9949
  }
9723
9950
  ),
9724
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9951
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9725
9952
  LinkPopover,
9726
9953
  {
9727
9954
  panelRef: linkPopoverPanelRef,
@@ -9738,15 +9965,15 @@ function OhhwellsBridge() {
9738
9965
  },
9739
9966
  linkPopover.key
9740
9967
  ) : null,
9741
- sectionGap && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
9968
+ sectionGap && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9742
9969
  "div",
9743
9970
  {
9744
9971
  "data-ohw-section-insert-line": "",
9745
9972
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
9746
9973
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
9747
9974
  children: [
9748
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
9749
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9975
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
9976
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9750
9977
  Badge,
9751
9978
  {
9752
9979
  className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
@@ -9759,7 +9986,7 @@ function OhhwellsBridge() {
9759
9986
  children: "Add Section"
9760
9987
  }
9761
9988
  ),
9762
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
9989
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
9763
9990
  ]
9764
9991
  }
9765
9992
  )
@@ -9770,7 +9997,7 @@ function OhhwellsBridge() {
9770
9997
 
9771
9998
  // src/ui/drop-indicator.tsx
9772
9999
  var React10 = __toESM(require("react"), 1);
9773
- var import_jsx_runtime24 = require("react/jsx-runtime");
10000
+ var import_jsx_runtime25 = require("react/jsx-runtime");
9774
10001
  var dropIndicatorVariants = cva(
9775
10002
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
9776
10003
  {
@@ -9794,7 +10021,7 @@ var dropIndicatorVariants = cva(
9794
10021
  );
9795
10022
  var DropIndicator = React10.forwardRef(
9796
10023
  ({ className, direction, state, ...props }, ref) => {
9797
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
10024
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
9798
10025
  "div",
9799
10026
  {
9800
10027
  ref,
@@ -9837,6 +10064,7 @@ DropIndicator.displayName = "DropIndicator";
9837
10064
  isValidUrl,
9838
10065
  parseTarget,
9839
10066
  toggleVariants,
10067
+ useOhwCarousel,
9840
10068
  validateUrlInput
9841
10069
  });
9842
10070
  //# sourceMappingURL=index.cjs.map