@tightknitai/block-kitchen 0.10.24 → 0.10.26

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
@@ -1817,6 +1817,35 @@ function labelForBlockType(type) {
1817
1817
  return "Data Table";
1818
1818
  }
1819
1819
  }
1820
+ function historyShortcutOf(event) {
1821
+ if (!(event.metaKey || event.ctrlKey) || event.altKey) {
1822
+ return null;
1823
+ }
1824
+ const key = event.key.toLowerCase();
1825
+ if (key === "z") {
1826
+ return event.shiftKey ? "redo" : "undo";
1827
+ }
1828
+ return key === "y" ? "redo" : null;
1829
+ }
1830
+ function isTextEditingTarget(target) {
1831
+ if (!(target instanceof HTMLElement)) {
1832
+ return false;
1833
+ }
1834
+ return target.isContentEditable || // jsdom has no `isContentEditable`, so check the attribute too.
1835
+ target.closest('[contenteditable=""], [contenteditable="true"], [contenteditable="plaintext-only"]') !== null || ["INPUT", "TEXTAREA", "SELECT"].includes(target.tagName);
1836
+ }
1837
+ function isApplePlatform() {
1838
+ if (typeof navigator === "undefined") {
1839
+ return false;
1840
+ }
1841
+ const { userAgentData } = navigator;
1842
+ return /mac|iphone|ipad|ipod/i.test(userAgentData?.platform ?? navigator.platform ?? "");
1843
+ }
1844
+ var subscribeToNothing = () => () => {
1845
+ };
1846
+ function useIsApplePlatform() {
1847
+ return React.useSyncExternalStore(subscribeToNothing, isApplePlatform, () => false);
1848
+ }
1820
1849
  var Sheet = DialogPrimitive__namespace.Root;
1821
1850
  var SheetOverlay = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1822
1851
  DialogPrimitive__namespace.Overlay,
@@ -1898,6 +1927,16 @@ function useIsMobile() {
1898
1927
  }, []);
1899
1928
  return isMobile;
1900
1929
  }
1930
+ var BlockEditorsContext = React.createContext([]);
1931
+ function BlockEditorsProvider({
1932
+ blockEditors,
1933
+ children
1934
+ }) {
1935
+ return /* @__PURE__ */ jsxRuntime.jsx(BlockEditorsContext.Provider, { value: blockEditors ?? [], children });
1936
+ }
1937
+ function useCustomBlockEditor(block) {
1938
+ return React.useContext(BlockEditorsContext).find((editor) => editor.match(block));
1939
+ }
1901
1940
  var EMPTY = {
1902
1941
  customEmojis: [],
1903
1942
  byName: /* @__PURE__ */ new Map()
@@ -4239,6 +4278,7 @@ function Palette({
4239
4278
  mode = "advanced",
4240
4279
  defaultAdvanced = false,
4241
4280
  onAdvancedChange,
4281
+ onLockedPicked,
4242
4282
  variant = "aside"
4243
4283
  }) {
4244
4284
  const [query, setQuery] = React.useState("");
@@ -4332,7 +4372,16 @@ function Palette({
4332
4372
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col", isSheet ? "px-2 pb-6" : "p-3"), children: !advanced ? (
4333
4373
  // Simple mode: a flat list, no section headings — with this few
4334
4374
  // rows the headings would outnumber the blocks under them.
4335
- basics.map((v) => /* @__PURE__ */ jsxRuntime.jsx(PaletteItem, { variant: v, onAdd: () => onAddBlock(v.factory()), mode: variant }, v.id))
4375
+ basics.map((v) => /* @__PURE__ */ jsxRuntime.jsx(
4376
+ PaletteItem,
4377
+ {
4378
+ variant: v,
4379
+ onAdd: () => onAddBlock(v.factory()),
4380
+ onLockedPicked,
4381
+ mode: variant
4382
+ },
4383
+ v.id
4384
+ ))
4336
4385
  ) : visibleSections.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-1 py-2 text-xs text-muted-foreground", children: "No blocks match." }) : visibleSections.map((section) => /* @__PURE__ */ jsxRuntime.jsx(
4337
4386
  PaletteSection,
4338
4387
  {
@@ -4340,6 +4389,7 @@ function Palette({
4340
4389
  defaultOpen: isDefaultOpen(section.name, defaultOpenSections),
4341
4390
  forceOpen: queryActive,
4342
4391
  onAddBlock,
4392
+ onLockedPicked,
4343
4393
  variant
4344
4394
  },
4345
4395
  section.name
@@ -4371,6 +4421,7 @@ function PaletteSection({
4371
4421
  defaultOpen,
4372
4422
  forceOpen,
4373
4423
  onAddBlock,
4424
+ onLockedPicked,
4374
4425
  variant = "aside"
4375
4426
  }) {
4376
4427
  const [open, setOpen] = React.useState(defaultOpen);
@@ -4402,18 +4453,32 @@ function PaletteSection({
4402
4453
  ]
4403
4454
  }
4404
4455
  ),
4405
- isOpen ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 flex flex-col", children: section.variants.map((v) => /* @__PURE__ */ jsxRuntime.jsx(PaletteItem, { variant: v, onAdd: () => onAddBlock(v.factory()), mode: variant }, v.id)) }) : null
4456
+ isOpen ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 flex flex-col", children: section.variants.map((v) => /* @__PURE__ */ jsxRuntime.jsx(
4457
+ PaletteItem,
4458
+ {
4459
+ variant: v,
4460
+ onAdd: () => onAddBlock(v.factory()),
4461
+ onLockedPicked,
4462
+ mode: variant
4463
+ },
4464
+ v.id
4465
+ )) }) : null
4406
4466
  ] });
4407
4467
  }
4408
4468
  function PaletteItem({
4409
4469
  variant,
4410
4470
  onAdd,
4471
+ onLockedPicked,
4411
4472
  mode = "aside"
4412
4473
  }) {
4413
4474
  const { attributes, listeners, setNodeRef, setActivatorNodeRef, isDragging } = core.useDraggable({
4414
- id: `${PALETTE_DRAG_PREFIX}${variant.id}`
4475
+ id: `${PALETTE_DRAG_PREFIX}${variant.id}`,
4476
+ disabled: variant.locked
4415
4477
  });
4416
4478
  const isSheet = mode === "sheet";
4479
+ if (variant.locked) {
4480
+ return /* @__PURE__ */ jsxRuntime.jsx(LockedPaletteItem, { variant, isSheet, onPicked: onLockedPicked });
4481
+ }
4417
4482
  if (isSheet) {
4418
4483
  return /* @__PURE__ */ jsxRuntime.jsxs(
4419
4484
  "button",
@@ -4428,6 +4493,7 @@ function PaletteItem({
4428
4493
  ),
4429
4494
  children: [
4430
4495
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: variant.label }),
4496
+ variant.badge ? /* @__PURE__ */ jsxRuntime.jsx(VariantBadge, { badge: variant.badge }) : null,
4431
4497
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground transition-colors group-hover:bg-primary/10 group-hover:text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" }) })
4432
4498
  ]
4433
4499
  }
@@ -4438,7 +4504,7 @@ function PaletteItem({
4438
4504
  {
4439
4505
  ref: setNodeRef,
4440
4506
  className: cn(
4441
- "group flex items-center gap-2 rounded px-2 py-1 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-foreground has-[:focus-visible]:bg-accent has-[:focus-visible]:text-foreground",
4507
+ "group flex items-start gap-2 rounded px-2 py-1 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-foreground has-[:focus-visible]:bg-accent has-[:focus-visible]:text-foreground",
4442
4508
  isDragging && "opacity-50"
4443
4509
  ),
4444
4510
  children: [
@@ -4446,12 +4512,12 @@ function PaletteItem({
4446
4512
  "div",
4447
4513
  {
4448
4514
  ref: setActivatorNodeRef,
4449
- className: "-my-1 flex min-w-0 flex-1 cursor-grab items-center gap-2 rounded py-1 active:cursor-grabbing focus-visible:outline-none",
4515
+ className: "-my-1 flex min-w-0 flex-1 cursor-grab items-start gap-2 rounded py-1 active:cursor-grabbing focus-visible:outline-none",
4450
4516
  ...attributes,
4451
4517
  ...listeners,
4452
4518
  children: [
4453
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GripVertical, { className: "h-3.5 w-3.5 shrink-0" }),
4454
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: variant.label })
4519
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GripVertical, { className: "mt-[3px] h-3.5 w-3.5 shrink-0" }),
4520
+ /* @__PURE__ */ jsxRuntime.jsx(RailLabel, { variant })
4455
4521
  ]
4456
4522
  }
4457
4523
  ),
@@ -4469,6 +4535,69 @@ function PaletteItem({
4469
4535
  }
4470
4536
  );
4471
4537
  }
4538
+ function LockedPaletteItem({
4539
+ variant,
4540
+ isSheet,
4541
+ onPicked
4542
+ }) {
4543
+ const select = variant.onLockedSelect;
4544
+ const className = cn(
4545
+ "flex w-full text-left text-muted-foreground",
4546
+ isSheet ? "min-h-11 items-center gap-3 rounded-md px-3 py-2 text-sm font-medium" : "items-start gap-2 rounded px-2 py-1 text-sm"
4547
+ );
4548
+ const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4549
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { "aria-hidden": true, className: cn("shrink-0", isSheet ? "h-4 w-4" : "mt-[3px] h-3.5 w-3.5") }),
4550
+ isSheet ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4551
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: variant.label }),
4552
+ variant.badge ? /* @__PURE__ */ jsxRuntime.jsx(VariantBadge, { badge: variant.badge }) : null
4553
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(RailLabel, { variant })
4554
+ ] });
4555
+ if (!select) {
4556
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-disabled": "true", className, children: content });
4557
+ }
4558
+ return /* @__PURE__ */ jsxRuntime.jsx(
4559
+ "button",
4560
+ {
4561
+ type: "button",
4562
+ "aria-label": `${variant.label} (locked${variant.badge ? `, ${variant.badge.label}` : ""})`,
4563
+ onClick: () => {
4564
+ onPicked?.();
4565
+ select();
4566
+ },
4567
+ className: cn(
4568
+ className,
4569
+ "cursor-pointer appearance-none border-0 bg-transparent transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
4570
+ ),
4571
+ children: content
4572
+ }
4573
+ );
4574
+ }
4575
+ function RailLabel({ variant }) {
4576
+ if (!variant.badge) {
4577
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: variant.label });
4578
+ }
4579
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col items-start gap-0.5", children: [
4580
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate", children: variant.label }),
4581
+ " ",
4582
+ /* @__PURE__ */ jsxRuntime.jsx(VariantBadge, { badge: variant.badge })
4583
+ ] });
4584
+ }
4585
+ function VariantBadge({ badge }) {
4586
+ const Icon = badge.icon;
4587
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4588
+ "span",
4589
+ {
4590
+ className: cn(
4591
+ "inline-flex shrink-0 items-center gap-1 rounded-full border bg-background px-1.5 text-[10px] font-medium leading-4 text-muted-foreground",
4592
+ badge.className
4593
+ ),
4594
+ children: [
4595
+ Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { "aria-hidden": true, className: "h-2.5 w-2.5 shrink-0" }) : null,
4596
+ badge.label
4597
+ ]
4598
+ }
4599
+ );
4600
+ }
4472
4601
  function SendDialog({
4473
4602
  open,
4474
4603
  onOpenChange,
@@ -6288,7 +6417,7 @@ function MentionPicker({
6288
6417
  const listRef = React.useRef(null);
6289
6418
  const listboxId = React.useId();
6290
6419
  const activeOptionId = items[activeIndex] ? `${listboxId}-${activeIndex}` : void 0;
6291
- React.useEffect(() => {
6420
+ React.useLayoutEffect(() => {
6292
6421
  const root = editor.view.dom;
6293
6422
  root.setAttribute("role", "combobox");
6294
6423
  root.setAttribute("aria-autocomplete", "list");
@@ -6307,7 +6436,7 @@ function MentionPicker({
6307
6436
  root.removeAttribute("aria-activedescendant");
6308
6437
  };
6309
6438
  }, [activeOptionId, editor, listboxId]);
6310
- React.useEffect(() => {
6439
+ React.useLayoutEffect(() => {
6311
6440
  keyHandlerRef.current = (event) => {
6312
6441
  if (event.key === "ArrowDown" || event.key === "ArrowUp") {
6313
6442
  if (items.length > 0) {
@@ -10397,13 +10526,15 @@ function BlockEditor({
10397
10526
  onChange,
10398
10527
  onDone
10399
10528
  }) {
10529
+ const custom = useCustomBlockEditor(block);
10530
+ const CustomForm = custom?.component;
10400
10531
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
10401
10532
  /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "text-sm font-semibold text-foreground", children: [
10402
10533
  "Edit ",
10403
- labelForBlockType(block.type)
10534
+ custom ? custom.label : labelForBlockType(block.type)
10404
10535
  ] }) }),
10405
10536
  errors && errors.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-0.5 rounded-md border border-destructive/30 bg-destructive/5 p-2 text-xs text-destructive", children: errors.map((err, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: err }, i)) }) : null,
10406
- dispatch(block, onChange),
10537
+ CustomForm ? /* @__PURE__ */ jsxRuntime.jsx(CustomForm, { block, onChange }) : dispatch(block, onChange),
10407
10538
  /* @__PURE__ */ jsxRuntime.jsx(
10408
10539
  AdvancedIdField,
10409
10540
  {
@@ -10574,6 +10705,122 @@ function BlockRow({
10574
10705
  ) })
10575
10706
  ] });
10576
10707
  const adornment = position && renderBlockAdornment?.(position);
10708
+ const hoverChrome = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
10709
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "-translate-x-1/2 pointer-events-none absolute bottom-full left-1/2 z-10 hidden bg-background px-1.5 text-[11px] text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100 md:block", children: BLOCK_TYPE_LABELS[builderBlock.block.type] }),
10710
+ /* @__PURE__ */ jsxRuntime.jsxs(
10711
+ "div",
10712
+ {
10713
+ className: cn(
10714
+ // Hidden on mobile in favor of the inline row below; on desktop
10715
+ // reveal on hover, on keyboard focus inside the row (so Tab-stops on
10716
+ // the floating buttons themselves keep them visible), and when there
10717
+ // are validation errors worth surfacing immediately.
10718
+ // :focus-visible, not :focus-within — a drag leaves pointer focus on
10719
+ // the block, which would otherwise pin the toolbar open until a click.
10720
+ "absolute -top-3 right-2 z-10 hidden items-center gap-0.5 rounded-md border bg-background p-0.5 shadow-sm transition-opacity md:flex",
10721
+ hasErrors ? "opacity-100" : "opacity-0 group-hover:opacity-100 group-has-[:focus-visible]:opacity-100"
10722
+ ),
10723
+ children: [
10724
+ hasErrors ? /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
10725
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
10726
+ "button",
10727
+ {
10728
+ type: "button",
10729
+ "aria-label": `Show ${errors.length} validation ${errors.length === 1 ? "issue" : "issues"}`,
10730
+ onClick: () => onOpenChange?.(true),
10731
+ className: "flex h-6 w-6 items-center justify-center rounded text-destructive hover:bg-destructive/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
10732
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3.5 w-3.5" })
10733
+ }
10734
+ ) }),
10735
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", align: "end", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "flex flex-col gap-0.5", children: [
10736
+ errors.slice(0, 4).map((err, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: err }, i)),
10737
+ errors.length > 4 ? /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "text-muted-foreground", children: [
10738
+ "and ",
10739
+ errors.length - 4,
10740
+ " more"
10741
+ ] }) : null
10742
+ ] }) })
10743
+ ] }) : null,
10744
+ onReorder && typeof index === "number" && typeof total === "number" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
10745
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
10746
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
10747
+ "button",
10748
+ {
10749
+ type: "button",
10750
+ "aria-label": "Move block up",
10751
+ disabled: index === 0,
10752
+ onClick: () => onReorder(builderBlock.id, index - 1),
10753
+ className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent disabled:hover:text-muted-foreground",
10754
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-3.5 w-3.5" })
10755
+ }
10756
+ ) }),
10757
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Move up" })
10758
+ ] }),
10759
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
10760
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
10761
+ "button",
10762
+ {
10763
+ type: "button",
10764
+ "aria-label": "Move block down",
10765
+ disabled: index >= total - 1,
10766
+ onClick: () => onReorder(builderBlock.id, index + 1),
10767
+ className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent disabled:hover:text-muted-foreground",
10768
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "h-3.5 w-3.5" })
10769
+ }
10770
+ ) }),
10771
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Move down" })
10772
+ ] })
10773
+ ] }) : null,
10774
+ /* @__PURE__ */ jsxRuntime.jsx(BlockActionButtons, { actions: blockActions, position, variant: "toolbar" }),
10775
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
10776
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
10777
+ "button",
10778
+ {
10779
+ type: "button",
10780
+ "aria-label": "Edit block",
10781
+ onClick: () => {
10782
+ if (isRichText) {
10783
+ setInlineEditing(true);
10784
+ } else {
10785
+ onOpenChange?.(true);
10786
+ }
10787
+ },
10788
+ className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
10789
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-3.5 w-3.5" })
10790
+ }
10791
+ ) }),
10792
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Edit" })
10793
+ ] }),
10794
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
10795
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
10796
+ "button",
10797
+ {
10798
+ type: "button",
10799
+ "aria-label": "Duplicate block",
10800
+ onClick: () => onDuplicate(builderBlock.id),
10801
+ className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
10802
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-3.5 w-3.5" })
10803
+ }
10804
+ ) }),
10805
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Duplicate" })
10806
+ ] }),
10807
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
10808
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
10809
+ "button",
10810
+ {
10811
+ type: "button",
10812
+ "aria-label": "Delete block",
10813
+ onClick: () => onDelete(builderBlock.id),
10814
+ className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
10815
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" })
10816
+ }
10817
+ ) }),
10818
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Delete" })
10819
+ ] })
10820
+ ]
10821
+ }
10822
+ )
10823
+ ] });
10577
10824
  return /* @__PURE__ */ jsxRuntime.jsxs(
10578
10825
  "div",
10579
10826
  {
@@ -10591,126 +10838,16 @@ function BlockRow({
10591
10838
  children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "-left-1 -top-[3px] absolute h-2 w-2 rounded-full bg-primary shadow-[0_0_0_2px_var(--color-background)]" })
10592
10839
  }
10593
10840
  ) : null,
10594
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
10595
- renderBlockAdornment ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
10596
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: body }),
10597
- adornment != null && adornment !== false ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: adornment }) : null
10598
- ] }) : body,
10599
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "-translate-x-1/2 pointer-events-none absolute bottom-full left-1/2 z-10 hidden bg-background px-1.5 text-[11px] text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100 md:block", children: BLOCK_TYPE_LABELS[builderBlock.block.type] }),
10600
- /* @__PURE__ */ jsxRuntime.jsxs(
10601
- "div",
10602
- {
10603
- className: cn(
10604
- // Hidden on mobile in favor of the inline row below; on desktop
10605
- // reveal on hover, on keyboard focus inside the row (so Tab-stops on
10606
- // the floating buttons themselves keep them visible), and when there
10607
- // are validation errors worth surfacing immediately.
10608
- // :focus-visible, not :focus-within — a drag leaves pointer focus on
10609
- // the block, which would otherwise pin the toolbar open until a click.
10610
- "absolute -top-3 right-2 z-10 hidden items-center gap-0.5 rounded-md border bg-background p-0.5 shadow-sm transition-opacity md:flex",
10611
- hasErrors ? "opacity-100" : "opacity-0 group-hover:opacity-100 group-has-[:focus-visible]:opacity-100"
10612
- ),
10613
- children: [
10614
- hasErrors ? /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
10615
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
10616
- "button",
10617
- {
10618
- type: "button",
10619
- "aria-label": `Show ${errors.length} validation ${errors.length === 1 ? "issue" : "issues"}`,
10620
- onClick: () => onOpenChange?.(true),
10621
- className: "flex h-6 w-6 items-center justify-center rounded text-destructive hover:bg-destructive/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
10622
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3.5 w-3.5" })
10623
- }
10624
- ) }),
10625
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", align: "end", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "flex flex-col gap-0.5", children: [
10626
- errors.slice(0, 4).map((err, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: err }, i)),
10627
- errors.length > 4 ? /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "text-muted-foreground", children: [
10628
- "and ",
10629
- errors.length - 4,
10630
- " more"
10631
- ] }) : null
10632
- ] }) })
10633
- ] }) : null,
10634
- onReorder && typeof index === "number" && typeof total === "number" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
10635
- /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
10636
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
10637
- "button",
10638
- {
10639
- type: "button",
10640
- "aria-label": "Move block up",
10641
- disabled: index === 0,
10642
- onClick: () => onReorder(builderBlock.id, index - 1),
10643
- className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent disabled:hover:text-muted-foreground",
10644
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-3.5 w-3.5" })
10645
- }
10646
- ) }),
10647
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Move up" })
10648
- ] }),
10649
- /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
10650
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
10651
- "button",
10652
- {
10653
- type: "button",
10654
- "aria-label": "Move block down",
10655
- disabled: index >= total - 1,
10656
- onClick: () => onReorder(builderBlock.id, index + 1),
10657
- className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent disabled:hover:text-muted-foreground",
10658
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "h-3.5 w-3.5" })
10659
- }
10660
- ) }),
10661
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Move down" })
10662
- ] })
10663
- ] }) : null,
10664
- /* @__PURE__ */ jsxRuntime.jsx(BlockActionButtons, { actions: blockActions, position, variant: "toolbar" }),
10665
- /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
10666
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
10667
- "button",
10668
- {
10669
- type: "button",
10670
- "aria-label": "Edit block",
10671
- onClick: () => {
10672
- if (isRichText) {
10673
- setInlineEditing(true);
10674
- } else {
10675
- onOpenChange?.(true);
10676
- }
10677
- },
10678
- className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
10679
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-3.5 w-3.5" })
10680
- }
10681
- ) }),
10682
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Edit" })
10683
- ] }),
10684
- /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
10685
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
10686
- "button",
10687
- {
10688
- type: "button",
10689
- "aria-label": "Duplicate block",
10690
- onClick: () => onDuplicate(builderBlock.id),
10691
- className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
10692
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-3.5 w-3.5" })
10693
- }
10694
- ) }),
10695
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Duplicate" })
10696
- ] }),
10697
- /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
10698
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
10699
- "button",
10700
- {
10701
- type: "button",
10702
- "aria-label": "Delete block",
10703
- onClick: () => onDelete(builderBlock.id),
10704
- className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
10705
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" })
10706
- }
10707
- ) }),
10708
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Delete" })
10709
- ] })
10710
- ]
10711
- }
10712
- )
10713
- ] }),
10841
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full", children: renderBlockAdornment ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
10842
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative min-w-0 flex-1", children: [
10843
+ body,
10844
+ hoverChrome
10845
+ ] }),
10846
+ adornment != null && adornment !== false ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: adornment }) : null
10847
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
10848
+ body,
10849
+ hoverChrome
10850
+ ] }) }),
10714
10851
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex items-center justify-between gap-2 rounded-md border border-dashed bg-muted/40 px-2 py-1 md:hidden", children: [
10715
10852
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[11px] font-medium text-muted-foreground", children: BLOCK_TYPE_LABELS[builderBlock.block.type] }),
10716
10853
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
@@ -10915,6 +11052,45 @@ function ContainerRow({
10915
11052
  ]
10916
11053
  }
10917
11054
  );
11055
+ const toolbar = /* @__PURE__ */ jsxRuntime.jsxs(
11056
+ "div",
11057
+ {
11058
+ className: cn(
11059
+ "absolute -top-3 right-2 z-10 hidden items-center gap-0.5 rounded-md border bg-background p-0.5 shadow-sm transition-opacity md:flex",
11060
+ hasErrors ? "opacity-100" : "opacity-0 group-hover/container:opacity-100 group-has-[:focus-visible]/container:opacity-100"
11061
+ ),
11062
+ children: [
11063
+ hasErrors ? /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
11064
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
11065
+ "button",
11066
+ {
11067
+ type: "button",
11068
+ "aria-label": `Show ${errors.length} validation ${errors.length === 1 ? "issue" : "issues"}`,
11069
+ onClick: () => onOpenBlockChange?.(id),
11070
+ className: "flex h-6 w-6 items-center justify-center rounded text-destructive hover:bg-destructive/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
11071
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3.5 w-3.5" })
11072
+ }
11073
+ ) }),
11074
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", align: "end", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "flex flex-col gap-0.5", children: [
11075
+ errors.slice(0, 4).map((err, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: err }, i)),
11076
+ errors.length > 4 ? /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "text-muted-foreground", children: [
11077
+ "and ",
11078
+ errors.length - 4,
11079
+ " more"
11080
+ ] }) : null
11081
+ ] }) })
11082
+ ] }) : null,
11083
+ onReorder && typeof index === "number" && typeof total === "number" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11084
+ /* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Move up", disabled: index === 0, onClick: () => onReorder(id, index - 1), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-3.5 w-3.5" }) }),
11085
+ /* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Move down", disabled: index >= total - 1, onClick: () => onReorder(id, index + 1), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "h-3.5 w-3.5" }) })
11086
+ ] }) : null,
11087
+ /* @__PURE__ */ jsxRuntime.jsx(BlockActionButtons, { actions: blockActions, position, variant: "toolbar" }),
11088
+ /* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Edit", onClick: () => onOpenBlockChange?.(id), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-3.5 w-3.5" }) }),
11089
+ /* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Duplicate", onClick: () => onDuplicate(id), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-3.5 w-3.5" }) }),
11090
+ /* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Delete", destructive: true, onClick: () => onDelete(id), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" }) })
11091
+ ]
11092
+ }
11093
+ );
10918
11094
  return /* @__PURE__ */ jsxRuntime.jsxs(
10919
11095
  "div",
10920
11096
  {
@@ -10924,48 +11100,15 @@ function ContainerRow({
10924
11100
  className: cn("group/container relative mb-2 last:mb-0 hover:z-10", isDragging && "opacity-40"),
10925
11101
  children: [
10926
11102
  renderBlockAdornment ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
10927
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: card }),
11103
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative min-w-0 flex-1", children: [
11104
+ card,
11105
+ toolbar
11106
+ ] }),
10928
11107
  adornment != null && adornment !== false ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: adornment }) : null
10929
- ] }) : card,
10930
- /* @__PURE__ */ jsxRuntime.jsxs(
10931
- "div",
10932
- {
10933
- className: cn(
10934
- "absolute -top-3 right-2 z-10 hidden items-center gap-0.5 rounded-md border bg-background p-0.5 shadow-sm transition-opacity md:flex",
10935
- hasErrors ? "opacity-100" : "opacity-0 group-hover/container:opacity-100 group-has-[:focus-visible]/container:opacity-100"
10936
- ),
10937
- children: [
10938
- hasErrors ? /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
10939
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
10940
- "button",
10941
- {
10942
- type: "button",
10943
- "aria-label": `Show ${errors.length} validation ${errors.length === 1 ? "issue" : "issues"}`,
10944
- onClick: () => onOpenBlockChange?.(id),
10945
- className: "flex h-6 w-6 items-center justify-center rounded text-destructive hover:bg-destructive/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
10946
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3.5 w-3.5" })
10947
- }
10948
- ) }),
10949
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", align: "end", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "flex flex-col gap-0.5", children: [
10950
- errors.slice(0, 4).map((err, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: err }, i)),
10951
- errors.length > 4 ? /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "text-muted-foreground", children: [
10952
- "and ",
10953
- errors.length - 4,
10954
- " more"
10955
- ] }) : null
10956
- ] }) })
10957
- ] }) : null,
10958
- onReorder && typeof index === "number" && typeof total === "number" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
10959
- /* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Move up", disabled: index === 0, onClick: () => onReorder(id, index - 1), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-3.5 w-3.5" }) }),
10960
- /* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Move down", disabled: index >= total - 1, onClick: () => onReorder(id, index + 1), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "h-3.5 w-3.5" }) })
10961
- ] }) : null,
10962
- /* @__PURE__ */ jsxRuntime.jsx(BlockActionButtons, { actions: blockActions, position, variant: "toolbar" }),
10963
- /* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Edit", onClick: () => onOpenBlockChange?.(id), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-3.5 w-3.5" }) }),
10964
- /* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Duplicate", onClick: () => onDuplicate(id), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-3.5 w-3.5" }) }),
10965
- /* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Delete", destructive: true, onClick: () => onDelete(id), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" }) })
10966
- ]
10967
- }
10968
- ),
11108
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11109
+ card,
11110
+ toolbar
11111
+ ] }),
10969
11112
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex items-center justify-between gap-2 rounded-md border border-dashed bg-muted/40 px-2 py-1 md:hidden", children: [
10970
11113
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[11px] font-medium text-muted-foreground", children: "Container" }),
10971
11114
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
@@ -11382,6 +11525,7 @@ function Toolbar2({
11382
11525
  canRedo = false,
11383
11526
  onUndo,
11384
11527
  onRedo,
11528
+ undoRedoShortcuts = true,
11385
11529
  onClear,
11386
11530
  onOpenJson,
11387
11531
  onOpenIssues,
@@ -11415,6 +11559,7 @@ function Toolbar2({
11415
11559
  const showSurfaceControl = surfaceOptions.length > 1;
11416
11560
  const docsHref = docsLink === false ? null : docsLink?.href ?? DEFAULT_DOCS_HREF;
11417
11561
  const docsLabel = docsLink === false ? null : docsLink?.label ?? DEFAULT_DOCS_LABEL;
11562
+ const isApple = useIsApplePlatform();
11418
11563
  const [surfaceMenuOpen, setSurfaceMenuOpen] = React.useState(false);
11419
11564
  const [themeMenuOpen, setThemeMenuOpen] = React.useState(false);
11420
11565
  const [sendMenuOpen, setSendMenuOpen] = React.useState(false);
@@ -11505,7 +11650,8 @@ function Toolbar2({
11505
11650
  onClick: onUndo,
11506
11651
  disabled: !canUndo,
11507
11652
  "aria-label": "Undo",
11508
- title: "Undo (Ctrl+Z)",
11653
+ "aria-keyshortcuts": undoRedoShortcuts ? "Control+Z Meta+Z" : void 0,
11654
+ title: undoRedoShortcuts ? `Undo (${isApple ? "\u2318Z" : "Ctrl+Z"})` : "Undo",
11509
11655
  className: "px-2",
11510
11656
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Undo2, { className: "h-3.5 w-3.5" })
11511
11657
  }
@@ -11519,7 +11665,8 @@ function Toolbar2({
11519
11665
  onClick: onRedo,
11520
11666
  disabled: !canRedo,
11521
11667
  "aria-label": "Redo",
11522
- title: "Redo (Ctrl+Shift+Z)",
11668
+ "aria-keyshortcuts": undoRedoShortcuts ? "Control+Shift+Z Meta+Shift+Z Control+Y" : void 0,
11669
+ title: undoRedoShortcuts ? `Redo (${isApple ? "\u21E7\u2318Z" : "Ctrl+Shift+Z"})` : "Redo",
11523
11670
  className: "px-2",
11524
11671
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Redo2, { className: "h-3.5 w-3.5" })
11525
11672
  }
@@ -11868,6 +12015,7 @@ function BlockKitchen(props) {
11868
12015
  previewHooks,
11869
12016
  blockActions,
11870
12017
  renderBlockAdornment,
12018
+ blockEditors,
11871
12019
  customEmojis,
11872
12020
  mentions,
11873
12021
  loadChannels,
@@ -11893,7 +12041,8 @@ function BlockKitchen(props) {
11893
12041
  previewTheme: controlledPreviewTheme,
11894
12042
  sendButtonLabel,
11895
12043
  confirmSendLabel,
11896
- theme
12044
+ theme,
12045
+ undoRedoShortcuts = true
11897
12046
  // Widen the all-or-nothing union so the branch-specific props
11898
12047
  // destructure as independent optionals: untyped JS consumers can still
11899
12048
  // pass partial wiring (handled by the runtime guards below), and the
@@ -12073,7 +12222,7 @@ function BlockKitchen(props) {
12073
12222
  const variantId = parsePaletteDragId(active.id);
12074
12223
  if (variantId) {
12075
12224
  const variant = variantById.get(variantId);
12076
- if (!variant) {
12225
+ if (!variant || variant.locked) {
12077
12226
  return;
12078
12227
  }
12079
12228
  if (target.kind === "container") {
@@ -12092,30 +12241,47 @@ function BlockKitchen(props) {
12092
12241
  const handleDragCancel = React.useCallback(() => {
12093
12242
  setActivePaletteVariantId(null);
12094
12243
  }, []);
12095
- const handleKeyDown = React.useCallback(
12244
+ const runHistoryShortcut = React.useCallback(
12096
12245
  (event) => {
12097
- if (!(event.metaKey || event.ctrlKey) || event.altKey) {
12098
- return;
12099
- }
12100
- const key = event.key.toLowerCase();
12101
- const isUndo = key === "z" && !event.shiftKey;
12102
- const isRedo = key === "y" || key === "z" && event.shiftKey;
12103
- if (!isUndo && !isRedo) {
12246
+ const action = historyShortcutOf(event);
12247
+ if (!undoRedoShortcuts || !action || event.defaultPrevented || isTextEditingTarget(event.target)) {
12104
12248
  return;
12105
12249
  }
12106
- const target = event.target;
12107
- if (target && (target.isContentEditable || ["INPUT", "TEXTAREA", "SELECT"].includes(target.tagName))) {
12250
+ if (action === "undo" ? !canUndo : !canRedo) {
12108
12251
  return;
12109
12252
  }
12110
12253
  event.preventDefault();
12111
- if (isRedo) {
12112
- if (canRedo) redo();
12113
- } else if (canUndo) {
12254
+ if (action === "undo") {
12114
12255
  undo();
12256
+ } else {
12257
+ redo();
12115
12258
  }
12116
12259
  },
12117
- [canRedo, canUndo, redo, undo]
12260
+ [canRedo, canUndo, redo, undo, undoRedoShortcuts]
12118
12261
  );
12262
+ const rootRef = React.useRef(null);
12263
+ const lastClickInBuilderRef = React.useRef(false);
12264
+ React.useEffect(() => {
12265
+ if (!undoRedoShortcuts) {
12266
+ return;
12267
+ }
12268
+ const onPointerDown = () => {
12269
+ lastClickInBuilderRef.current = false;
12270
+ };
12271
+ const onKeyDown = (event) => {
12272
+ const root = rootRef.current;
12273
+ const focusAroundBuilder = event.target instanceof Node && root !== null && event.target.contains(root);
12274
+ if (focusAroundBuilder && lastClickInBuilderRef.current) {
12275
+ runHistoryShortcut(event);
12276
+ }
12277
+ };
12278
+ window.addEventListener("pointerdown", onPointerDown, true);
12279
+ window.addEventListener("keydown", onKeyDown);
12280
+ return () => {
12281
+ window.removeEventListener("pointerdown", onPointerDown, true);
12282
+ window.removeEventListener("keydown", onKeyDown);
12283
+ };
12284
+ }, [runHistoryShortcut, undoRedoShortcuts]);
12119
12285
  const activePaletteVariant = activePaletteVariantId ? variantById.get(activePaletteVariantId) : null;
12120
12286
  const blockPayloads = blocks.map((b) => b.block);
12121
12287
  return /* @__PURE__ */ jsxRuntime.jsx(BrandThemeScope, { theme, children: /* @__PURE__ */ jsxRuntime.jsx(CustomEmojiProvider, { customEmojis, children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxRuntime.jsxs(
@@ -12130,8 +12296,12 @@ function BlockKitchen(props) {
12130
12296
  /* @__PURE__ */ jsxRuntime.jsxs(
12131
12297
  "div",
12132
12298
  {
12299
+ ref: rootRef,
12133
12300
  className: "bk-root flex h-full max-h-[var(--bk-max-height,100svh)] w-full flex-col overflow-hidden rounded-md border bg-background text-foreground",
12134
- onKeyDown: handleKeyDown,
12301
+ onKeyDown: runHistoryShortcut,
12302
+ onPointerDownCapture: () => {
12303
+ lastClickInBuilderRef.current = true;
12304
+ },
12135
12305
  children: [
12136
12306
  /* @__PURE__ */ jsxRuntime.jsx(
12137
12307
  Toolbar2,
@@ -12140,6 +12310,7 @@ function BlockKitchen(props) {
12140
12310
  canRedo,
12141
12311
  onUndo: undo,
12142
12312
  onRedo: redo,
12313
+ undoRedoShortcuts,
12143
12314
  onClear: () => replaceAll([]),
12144
12315
  onOpenJson: () => setJsonOpen(true),
12145
12316
  onOpenIssues: () => setIssuesOpen(true),
@@ -12230,7 +12401,7 @@ function BlockKitchen(props) {
12230
12401
  }
12231
12402
  )
12232
12403
  ] }),
12233
- /* @__PURE__ */ jsxRuntime.jsx(MentionsProvider, { mentions, children: /* @__PURE__ */ jsxRuntime.jsx(
12404
+ /* @__PURE__ */ jsxRuntime.jsx(MentionsProvider, { mentions, children: /* @__PURE__ */ jsxRuntime.jsx(BlockEditorsProvider, { blockEditors, children: /* @__PURE__ */ jsxRuntime.jsx(
12234
12405
  Surface,
12235
12406
  {
12236
12407
  blocks,
@@ -12252,7 +12423,7 @@ function BlockKitchen(props) {
12252
12423
  blockActions,
12253
12424
  renderBlockAdornment
12254
12425
  }
12255
- ) })
12426
+ ) }) })
12256
12427
  ] })
12257
12428
  ]
12258
12429
  }
@@ -12283,6 +12454,7 @@ function BlockKitchen(props) {
12283
12454
  addBlock(block);
12284
12455
  setPaletteOpen(false);
12285
12456
  },
12457
+ onLockedPicked: () => setPaletteOpen(false),
12286
12458
  sections: paletteSections,
12287
12459
  mode: paletteMode,
12288
12460
  showSearch: showPaletteSearch,