@tightknitai/block-kitchen 0.6.1-alpha.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,18 +1,18 @@
1
- import { useSensors, useSensor, PointerSensor, pointerWithin, closestCenter, DndContext, DragOverlay, useDroppable, useDraggable } from '@dnd-kit/core';
2
- import { X, Circle, Sparkles, FileText, AlignLeft, MousePointerClick, TextCursorInput, LayoutTemplate, Pilcrow, Image, GalleryHorizontal, Table, GripVertical, Sun, Moon, MessageSquare, AppWindow, Home, ChevronDown, Check, BookOpen, ExternalLink, AlertTriangle, Trash2, Code2, Send, Search, CheckCircle2, ChevronRight, LayoutGrid, Pencil, Copy, Plus, Type, Bold, Italic, Strikethrough, Code, List, ListOrdered, Quote, Undo2, Redo2, Link as Link$1 } from 'lucide-react';
3
- import * as React2 from 'react';
1
+ import { useSensors, useSensor, PointerSensor, TouchSensor, KeyboardSensor, pointerWithin, closestCenter, DndContext, DragOverlay, useDroppable, useDraggable } from '@dnd-kit/core';
2
+ import { sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable';
3
+ import { X, Circle, Sparkles, FileText, AlignLeft, MousePointerClick, TextCursorInput, LayoutTemplate, Bell, Pilcrow, Image, Video, GalleryHorizontal, Table, GripVertical, Sun, Moon, MessageSquare, AppWindow, Home, Plus, ChevronDown, BookOpen, ExternalLink, AlertTriangle, Trash2, Code2, MoreHorizontal, Send, Search, CheckCircle2, Check, ChevronRight, LayoutGrid, ArrowUp, ArrowDown, Pencil, Copy, Type, Bold, Italic, Strikethrough, Code, List, ListOrdered, Quote, Undo2, Redo2, Link as Link$1 } from 'lucide-react';
4
+ import * as React from 'react';
4
5
  import { useMemo, useState, useCallback, useRef, useEffect, useId } from 'react';
5
- import * as TooltipPrimitive from '@radix-ui/react-tooltip';
6
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
6
7
  import { clsx } from 'clsx';
7
8
  import { twMerge } from 'tailwind-merge';
8
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
9
11
  import { validateBlockKit, CARD_ACTIONS_MAX } from '@tightknitai/slack-block-kit-validator';
10
12
  import { nanoid } from 'nanoid';
11
- import * as DialogPrimitive from '@radix-ui/react-dialog';
12
13
  import { Slot } from '@radix-ui/react-slot';
13
14
  import { cva } from 'class-variance-authority';
14
15
  import * as LabelPrimitive from '@radix-ui/react-label';
15
- import { SortableContext, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable';
16
16
  import { CSS } from '@dnd-kit/utilities';
17
17
  import * as PopoverPrimitive from '@radix-ui/react-popover';
18
18
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
@@ -75,6 +75,66 @@ var defaultPalette = [
75
75
  }
76
76
  ]
77
77
  })
78
+ },
79
+ {
80
+ id: "agents_plan",
81
+ label: "Plan",
82
+ factory: () => ({
83
+ type: "plan",
84
+ title: "Investigating the issue",
85
+ tasks: [
86
+ {
87
+ type: "task_card",
88
+ task_id: "task_1",
89
+ title: "Read the bug report",
90
+ status: "complete"
91
+ },
92
+ {
93
+ type: "task_card",
94
+ task_id: "task_2",
95
+ title: "Reproduce the error locally",
96
+ status: "in_progress"
97
+ },
98
+ {
99
+ type: "task_card",
100
+ task_id: "task_3",
101
+ title: "Identify the root cause",
102
+ status: "pending"
103
+ }
104
+ ]
105
+ })
106
+ },
107
+ {
108
+ id: "agents_task_card",
109
+ label: "Task card",
110
+ factory: () => ({
111
+ type: "task_card",
112
+ task_id: "task_1",
113
+ title: "Summarize the latest release notes",
114
+ status: "in_progress"
115
+ })
116
+ },
117
+ {
118
+ id: "agents_task_card_with_sources",
119
+ label: "Task card with sources",
120
+ factory: () => ({
121
+ type: "task_card",
122
+ task_id: "task_2",
123
+ title: "Cite supporting docs",
124
+ status: "complete",
125
+ sources: [
126
+ {
127
+ type: "url",
128
+ url: "https://example.com/runbook",
129
+ text: "Runbook"
130
+ },
131
+ {
132
+ type: "url",
133
+ url: "https://example.com/changelog",
134
+ text: "Changelog"
135
+ }
136
+ ]
137
+ })
78
138
  }
79
139
  ]
80
140
  },
@@ -630,6 +690,71 @@ var defaultPalette = [
630
690
  }
631
691
  ]
632
692
  },
693
+ {
694
+ name: "Alert",
695
+ icon: Bell,
696
+ variants: [
697
+ {
698
+ id: "alert_default",
699
+ label: "Default",
700
+ factory: () => ({
701
+ type: "alert",
702
+ text: {
703
+ type: "mrkdwn",
704
+ text: "A neutral alert message."
705
+ }
706
+ })
707
+ },
708
+ {
709
+ id: "alert_info",
710
+ label: "Info",
711
+ factory: () => ({
712
+ type: "alert",
713
+ level: "info",
714
+ text: {
715
+ type: "mrkdwn",
716
+ text: "FYI: the build finished in 42 seconds."
717
+ }
718
+ })
719
+ },
720
+ {
721
+ id: "alert_warning",
722
+ label: "Warning",
723
+ factory: () => ({
724
+ type: "alert",
725
+ level: "warning",
726
+ text: {
727
+ type: "mrkdwn",
728
+ text: "Heads up: this action cannot be undone."
729
+ }
730
+ })
731
+ },
732
+ {
733
+ id: "alert_error",
734
+ label: "Error",
735
+ factory: () => ({
736
+ type: "alert",
737
+ level: "error",
738
+ text: {
739
+ type: "mrkdwn",
740
+ text: "Something went wrong. Please try again."
741
+ }
742
+ })
743
+ },
744
+ {
745
+ id: "alert_success",
746
+ label: "Success",
747
+ factory: () => ({
748
+ type: "alert",
749
+ level: "success",
750
+ text: {
751
+ type: "mrkdwn",
752
+ text: "Your changes have been saved."
753
+ }
754
+ })
755
+ }
756
+ ]
757
+ },
633
758
  {
634
759
  name: "Rich Text",
635
760
  icon: Pilcrow,
@@ -680,6 +805,43 @@ var defaultPalette = [
680
805
  }
681
806
  ]
682
807
  },
808
+ {
809
+ name: "Video",
810
+ icon: Video,
811
+ variants: [
812
+ {
813
+ id: "video_basic",
814
+ label: "Basic",
815
+ factory: () => ({
816
+ type: "video",
817
+ alt_text: "A short demo video",
818
+ title: { type: "plain_text", text: "Product demo", emoji: true },
819
+ thumbnail_url: "https://placehold.co/600x340?text=Video",
820
+ video_url: "https://www.youtube.com/embed/dQw4w9WgXcQ"
821
+ })
822
+ },
823
+ {
824
+ id: "video_with_metadata",
825
+ label: "With metadata",
826
+ factory: () => ({
827
+ type: "video",
828
+ alt_text: "A short demo video",
829
+ title: { type: "plain_text", text: "Product demo", emoji: true },
830
+ title_url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
831
+ thumbnail_url: "https://placehold.co/600x340?text=Video",
832
+ video_url: "https://www.youtube.com/embed/dQw4w9WgXcQ",
833
+ author_name: "Acme",
834
+ description: {
835
+ type: "plain_text",
836
+ text: "A short walkthrough of the new release.",
837
+ emoji: true
838
+ },
839
+ provider_name: "YouTube",
840
+ provider_icon_url: "https://placehold.co/16x16?text=YT"
841
+ })
842
+ }
843
+ ]
844
+ },
683
845
  {
684
846
  name: "Card and Carousel",
685
847
  icon: GalleryHorizontal,
@@ -1265,15 +1427,69 @@ function labelForBlockType(type) {
1265
1427
  return "Context Actions";
1266
1428
  case "input":
1267
1429
  return "Input";
1430
+ case "video":
1431
+ return "Video";
1432
+ case "plan":
1433
+ return "Plan";
1434
+ case "task_card":
1435
+ return "Task Card";
1268
1436
  }
1269
1437
  }
1270
1438
  function cn(...inputs) {
1271
1439
  return twMerge(clsx(inputs));
1272
1440
  }
1441
+ var Sheet = DialogPrimitive.Root;
1442
+ var SheetOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1443
+ DialogPrimitive.Overlay,
1444
+ {
1445
+ ref,
1446
+ className: cn(
1447
+ "bk-portal-content fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1448
+ className
1449
+ ),
1450
+ ...props
1451
+ }
1452
+ ));
1453
+ SheetOverlay.displayName = DialogPrimitive.Overlay.displayName;
1454
+ var SHEET_SIDE_CLASSES = {
1455
+ right: "inset-y-0 right-0 h-full w-full max-w-md border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right",
1456
+ left: "inset-y-0 left-0 h-full w-full max-w-md border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left",
1457
+ top: "inset-x-0 top-0 w-full border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
1458
+ bottom: "inset-x-0 bottom-0 w-full rounded-t-xl border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom"
1459
+ };
1460
+ var SheetContent = React.forwardRef(
1461
+ ({ className, children, side = "right", hideClose = false, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
1462
+ /* @__PURE__ */ jsx(SheetOverlay, {}),
1463
+ /* @__PURE__ */ jsxs(
1464
+ DialogPrimitive.Content,
1465
+ {
1466
+ ref,
1467
+ className: cn(
1468
+ "bk-portal-content fixed z-50 flex flex-col gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out",
1469
+ SHEET_SIDE_CLASSES[side],
1470
+ className
1471
+ ),
1472
+ ...props,
1473
+ children: [
1474
+ children,
1475
+ hideClose ? null : /* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none", children: [
1476
+ /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
1477
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
1478
+ ] })
1479
+ ]
1480
+ }
1481
+ )
1482
+ ] })
1483
+ );
1484
+ SheetContent.displayName = DialogPrimitive.Content.displayName;
1485
+ var SheetTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Title, { ref, className: cn("text-lg font-semibold text-foreground", className), ...props }));
1486
+ SheetTitle.displayName = DialogPrimitive.Title.displayName;
1487
+ var SheetDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
1488
+ SheetDescription.displayName = DialogPrimitive.Description.displayName;
1273
1489
  var TooltipProvider = TooltipPrimitive.Provider;
1274
1490
  var Tooltip = TooltipPrimitive.Root;
1275
1491
  var TooltipTrigger = TooltipPrimitive.Trigger;
1276
- var TooltipContent = React2.forwardRef(({ className, sideOffset = 6, ...props }, ref) => /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(
1492
+ var TooltipContent = React.forwardRef(({ className, sideOffset = 6, ...props }, ref) => /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(
1277
1493
  TooltipPrimitive.Content,
1278
1494
  {
1279
1495
  ref,
@@ -1287,6 +1503,22 @@ var TooltipContent = React2.forwardRef(({ className, sideOffset = 6, ...props },
1287
1503
  }
1288
1504
  ) }));
1289
1505
  TooltipContent.displayName = TooltipPrimitive.Content.displayName;
1506
+ var MOBILE_BREAKPOINT_PX = 768;
1507
+ function useIsMobile() {
1508
+ const [isMobile, setIsMobile] = useState(() => {
1509
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
1510
+ return window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT_PX - 1}px)`).matches;
1511
+ });
1512
+ useEffect(() => {
1513
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1514
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT_PX - 1}px)`);
1515
+ const onChange = (e) => setIsMobile(e.matches);
1516
+ setIsMobile(mql.matches);
1517
+ mql.addEventListener("change", onChange);
1518
+ return () => mql.removeEventListener("change", onChange);
1519
+ }, []);
1520
+ return isMobile;
1521
+ }
1290
1522
 
1291
1523
  // src/lib/error-grouping.ts
1292
1524
  function toValidatorSurface(surface) {
@@ -1870,45 +2102,6 @@ function BrandThemeScope({ theme, children }) {
1870
2102
  /* @__PURE__ */ jsx("div", { "data-bk-scope": scopeId, style: { display: "contents" }, children })
1871
2103
  ] });
1872
2104
  }
1873
- var Sheet = DialogPrimitive.Root;
1874
- var SheetOverlay = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1875
- DialogPrimitive.Overlay,
1876
- {
1877
- ref,
1878
- className: cn(
1879
- "bk-portal-content fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1880
- className
1881
- ),
1882
- ...props
1883
- }
1884
- ));
1885
- SheetOverlay.displayName = DialogPrimitive.Overlay.displayName;
1886
- var SheetContent = React2.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
1887
- /* @__PURE__ */ jsx(SheetOverlay, {}),
1888
- /* @__PURE__ */ jsxs(
1889
- DialogPrimitive.Content,
1890
- {
1891
- ref,
1892
- className: cn(
1893
- "bk-portal-content fixed inset-y-0 right-0 z-50 flex h-full w-full max-w-md flex-col gap-4 border-l bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right",
1894
- className
1895
- ),
1896
- ...props,
1897
- children: [
1898
- children,
1899
- /* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none", children: [
1900
- /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
1901
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
1902
- ] })
1903
- ]
1904
- }
1905
- )
1906
- ] }));
1907
- SheetContent.displayName = DialogPrimitive.Content.displayName;
1908
- var SheetTitle = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Title, { ref, className: cn("text-lg font-semibold text-foreground", className), ...props }));
1909
- SheetTitle.displayName = DialogPrimitive.Title.displayName;
1910
- var SheetDescription = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
1911
- SheetDescription.displayName = DialogPrimitive.Description.displayName;
1912
2105
  function IssuesSheet({
1913
2106
  open,
1914
2107
  onOpenChange,
@@ -1923,7 +2116,7 @@ function IssuesSheet({
1923
2116
  }
1924
2117
  return { block, idx, errors };
1925
2118
  }).filter(Boolean);
1926
- return /* @__PURE__ */ jsx(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs(SheetContent, { className: "flex flex-col gap-3 sm:max-w-md", children: [
2119
+ return /* @__PURE__ */ jsx(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs(SheetContent, { className: "flex w-full max-w-full flex-col gap-3 sm:max-w-md", children: [
1927
2120
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
1928
2121
  /* @__PURE__ */ jsxs(SheetTitle, { className: "flex items-center gap-2", children: [
1929
2122
  validation.total === 0 ? /* @__PURE__ */ jsx(CheckCircle2, { className: "h-4 w-4 text-emerald-600" }) : /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 text-destructive" }),
@@ -2029,8 +2222,8 @@ function JsonDrawer({
2029
2222
  }
2030
2223
  return n;
2031
2224
  }, [value]);
2032
- return /* @__PURE__ */ jsx(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs(SheetContent, { className: "flex flex-col gap-3 sm:max-w-xl", children: [
2033
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
2225
+ return /* @__PURE__ */ jsx(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs(SheetContent, { className: "flex w-full max-w-full flex-col gap-3 sm:max-w-xl", children: [
2226
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 pr-8", children: [
2034
2227
  /* @__PURE__ */ jsx(SheetTitle, { children: "Block Kit JSON" }),
2035
2228
  /* @__PURE__ */ jsx(SheetDescription, { children: "Edits update the preview as you type. Parse errors show below." })
2036
2229
  ] }),
@@ -2048,6 +2241,7 @@ function JsonDrawer({
2048
2241
  "textarea",
2049
2242
  {
2050
2243
  ref: textareaRef,
2244
+ "aria-label": "Block Kit JSON",
2051
2245
  value,
2052
2246
  onChange: (e) => handleChange(e.target.value),
2053
2247
  onScroll: (e) => {
@@ -2073,7 +2267,7 @@ function JsonDrawer({
2073
2267
  ] })
2074
2268
  ] }) });
2075
2269
  }
2076
- var Input = React2.forwardRef(
2270
+ var Input = React.forwardRef(
2077
2271
  ({ className, type, ...props }, ref) => /* @__PURE__ */ jsx(
2078
2272
  "input",
2079
2273
  {
@@ -2120,7 +2314,8 @@ function Palette({
2120
2314
  sections,
2121
2315
  defaultOpenSections = true,
2122
2316
  showSearch = true,
2123
- searchPlaceholder = "Search blocks\u2026"
2317
+ searchPlaceholder = "Search blocks\u2026",
2318
+ variant = "aside"
2124
2319
  }) {
2125
2320
  const [query, setQuery] = useState("");
2126
2321
  const visibleSections = useMemo(
@@ -2128,43 +2323,73 @@ function Palette({
2128
2323
  [sections, query, showSearch]
2129
2324
  );
2130
2325
  const queryActive = showSearch && query.trim().length > 0;
2131
- return /* @__PURE__ */ jsxs("aside", { className: "flex min-h-0 w-72 shrink-0 flex-col overflow-x-hidden overflow-y-auto border-r bg-muted/20", children: [
2132
- showSearch ? /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-10 border-b bg-muted/20 px-3 pt-3 pb-2 backdrop-blur", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
2133
- /* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
2134
- /* @__PURE__ */ jsx(
2135
- Input,
2136
- {
2137
- type: "search",
2138
- value: query,
2139
- onChange: (e) => setQuery(e.target.value),
2140
- placeholder: searchPlaceholder,
2141
- "aria-label": searchPlaceholder,
2142
- className: "h-8 pl-7 text-sm"
2143
- }
2144
- )
2145
- ] }) }) : null,
2146
- /* @__PURE__ */ jsx("div", { className: "flex flex-col p-3", children: visibleSections.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-1 py-2 text-xs text-muted-foreground", children: "No blocks match." }) : visibleSections.map((section) => /* @__PURE__ */ jsx(
2147
- PaletteSection,
2148
- {
2149
- section,
2150
- defaultOpen: isDefaultOpen(section.name, defaultOpenSections),
2151
- forceOpen: queryActive,
2152
- onAddBlock
2153
- },
2154
- section.name
2155
- )) })
2156
- ] });
2326
+ const isSheet = variant === "sheet";
2327
+ return /* @__PURE__ */ jsxs(
2328
+ "aside",
2329
+ {
2330
+ className: cn(
2331
+ "flex min-h-0 flex-col overflow-x-hidden overflow-y-auto",
2332
+ isSheet ? "w-full flex-1 bg-background" : "w-72 shrink-0 border-r bg-muted/20"
2333
+ ),
2334
+ children: [
2335
+ showSearch ? /* @__PURE__ */ jsx(
2336
+ "div",
2337
+ {
2338
+ className: cn(
2339
+ "sticky top-0 z-10 border-b px-3 pt-3 pb-2 backdrop-blur",
2340
+ isSheet ? "bg-background" : "bg-muted/20"
2341
+ ),
2342
+ children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
2343
+ /* @__PURE__ */ jsx(
2344
+ Search,
2345
+ {
2346
+ className: cn(
2347
+ "pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground",
2348
+ isSheet ? "h-4 w-4" : "h-3.5 w-3.5"
2349
+ )
2350
+ }
2351
+ ),
2352
+ /* @__PURE__ */ jsx(
2353
+ Input,
2354
+ {
2355
+ type: "search",
2356
+ value: query,
2357
+ onChange: (e) => setQuery(e.target.value),
2358
+ placeholder: searchPlaceholder,
2359
+ "aria-label": searchPlaceholder,
2360
+ className: cn(isSheet ? "h-10 pl-8 text-base" : "h-8 pl-7 text-sm")
2361
+ }
2362
+ )
2363
+ ] })
2364
+ }
2365
+ ) : null,
2366
+ /* @__PURE__ */ jsx("div", { className: cn("flex flex-col", isSheet ? "px-2 pb-6" : "p-3"), children: visibleSections.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-1 py-2 text-xs text-muted-foreground", children: "No blocks match." }) : visibleSections.map((section) => /* @__PURE__ */ jsx(
2367
+ PaletteSection,
2368
+ {
2369
+ section,
2370
+ defaultOpen: isDefaultOpen(section.name, defaultOpenSections),
2371
+ forceOpen: queryActive,
2372
+ onAddBlock,
2373
+ variant
2374
+ },
2375
+ section.name
2376
+ )) })
2377
+ ]
2378
+ }
2379
+ );
2157
2380
  }
2158
2381
  function PaletteSection({
2159
2382
  section,
2160
2383
  defaultOpen,
2161
2384
  forceOpen,
2162
- onAddBlock
2385
+ onAddBlock,
2386
+ variant = "aside"
2163
2387
  }) {
2164
2388
  const [open, setOpen] = useState(defaultOpen);
2165
2389
  const Icon = section.icon;
2166
2390
  const isOpen = open || forceOpen;
2167
2391
  const Caret = isOpen ? ChevronDown : ChevronRight;
2392
+ const isSheet = variant === "sheet";
2168
2393
  return /* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-col first:mt-0", children: [
2169
2394
  /* @__PURE__ */ jsxs(
2170
2395
  "button",
@@ -2172,21 +2397,54 @@ function PaletteSection({
2172
2397
  type: "button",
2173
2398
  "aria-expanded": isOpen,
2174
2399
  onClick: () => setOpen((v) => !v),
2175
- className: "flex cursor-pointer appearance-none items-center gap-1.5 rounded border-0 bg-transparent px-1 py-1 text-left transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
2400
+ className: cn(
2401
+ "flex cursor-pointer appearance-none items-center gap-1.5 rounded border-0 bg-transparent text-left transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
2402
+ isSheet ? "px-2 py-2 min-h-10" : "px-1 py-1"
2403
+ ),
2176
2404
  children: [
2177
- /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
2178
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-[13px] font-semibold text-foreground", children: section.name }),
2179
- /* @__PURE__ */ jsx(Caret, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" })
2405
+ /* @__PURE__ */ jsx(Icon, { className: cn("shrink-0 text-muted-foreground", isSheet ? "h-5 w-5" : "h-4 w-4") }),
2406
+ /* @__PURE__ */ jsx(
2407
+ "span",
2408
+ {
2409
+ className: cn("min-w-0 flex-1 truncate font-semibold text-foreground", isSheet ? "text-sm" : "text-[13px]"),
2410
+ children: section.name
2411
+ }
2412
+ ),
2413
+ /* @__PURE__ */ jsx(Caret, { className: cn("shrink-0 text-muted-foreground", isSheet ? "h-4 w-4" : "h-3.5 w-3.5") })
2180
2414
  ]
2181
2415
  }
2182
2416
  ),
2183
- isOpen ? /* @__PURE__ */ jsx("div", { className: "mt-0.5 flex flex-col", children: section.variants.map((variant) => /* @__PURE__ */ jsx(PaletteItem, { variant, onAdd: () => onAddBlock(variant.factory()) }, variant.id)) }) : null
2417
+ isOpen ? /* @__PURE__ */ jsx("div", { className: "mt-0.5 flex flex-col", children: section.variants.map((v) => /* @__PURE__ */ jsx(PaletteItem, { variant: v, onAdd: () => onAddBlock(v.factory()), mode: variant }, v.id)) }) : null
2184
2418
  ] });
2185
2419
  }
2186
- function PaletteItem({ variant, onAdd }) {
2420
+ function PaletteItem({
2421
+ variant,
2422
+ onAdd,
2423
+ mode = "aside"
2424
+ }) {
2187
2425
  const { attributes, listeners, setNodeRef, setActivatorNodeRef, isDragging } = useDraggable({
2188
2426
  id: `${PALETTE_DRAG_PREFIX}${variant.id}`
2189
2427
  });
2428
+ const isSheet = mode === "sheet";
2429
+ if (isSheet) {
2430
+ return /* @__PURE__ */ jsxs(
2431
+ "button",
2432
+ {
2433
+ ref: setNodeRef,
2434
+ type: "button",
2435
+ "aria-label": `Add ${variant.label}`,
2436
+ onClick: onAdd,
2437
+ className: cn(
2438
+ "group flex w-full min-h-11 cursor-pointer items-center gap-3 rounded-md border border-transparent bg-background px-3 py-2 text-left text-sm font-medium text-foreground transition-colors hover:border-border hover:bg-accent active:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
2439
+ isDragging && "opacity-50"
2440
+ ),
2441
+ children: [
2442
+ /* @__PURE__ */ 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__ */ jsx(ChevronRight, { className: "h-4 w-4" }) }),
2443
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: variant.label })
2444
+ ]
2445
+ }
2446
+ );
2447
+ }
2190
2448
  return /* @__PURE__ */ jsxs(
2191
2449
  "div",
2192
2450
  {
@@ -2248,7 +2506,7 @@ var buttonVariants = cva(
2248
2506
  }
2249
2507
  }
2250
2508
  );
2251
- var Button = React2.forwardRef(
2509
+ var Button = React.forwardRef(
2252
2510
  ({ className, variant, size, asChild = false, ...props }, ref) => {
2253
2511
  const Comp = asChild ? Slot : "button";
2254
2512
  return /* @__PURE__ */ jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref, ...props });
@@ -2257,7 +2515,7 @@ var Button = React2.forwardRef(
2257
2515
  Button.displayName = "Button";
2258
2516
  var Dialog = DialogPrimitive.Root;
2259
2517
  var DialogPortal = DialogPrimitive.Portal;
2260
- var DialogOverlay = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2518
+ var DialogOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2261
2519
  DialogPrimitive.Overlay,
2262
2520
  {
2263
2521
  ref,
@@ -2269,7 +2527,7 @@ var DialogOverlay = React2.forwardRef(({ className, ...props }, ref) => /* @__PU
2269
2527
  }
2270
2528
  ));
2271
2529
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
2272
- var DialogContent = React2.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
2530
+ var DialogContent = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
2273
2531
  /* @__PURE__ */ jsx(DialogOverlay, {}),
2274
2532
  /* @__PURE__ */ jsxs(
2275
2533
  DialogPrimitive.Content,
@@ -2297,7 +2555,7 @@ function DialogHeader({ className, ...props }) {
2297
2555
  function DialogFooter({ className, ...props }) {
2298
2556
  return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className), ...props });
2299
2557
  }
2300
- var DialogTitle = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2558
+ var DialogTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2301
2559
  DialogPrimitive.Title,
2302
2560
  {
2303
2561
  ref,
@@ -2306,9 +2564,9 @@ var DialogTitle = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE
2306
2564
  }
2307
2565
  ));
2308
2566
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
2309
- var DialogDescription = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
2567
+ var DialogDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
2310
2568
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
2311
- var Label = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2569
+ var Label = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2312
2570
  LabelPrimitive.Root,
2313
2571
  {
2314
2572
  ref,
@@ -2407,7 +2665,7 @@ function SendDialog({
2407
2665
  });
2408
2666
  }
2409
2667
  };
2410
- return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { children: [
2668
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "w-[calc(100vw-1.5rem)] max-w-lg rounded-lg", children: [
2411
2669
  /* @__PURE__ */ jsxs(DialogHeader, { children: [
2412
2670
  /* @__PURE__ */ jsx(DialogTitle, { children: "Send to Slack" }),
2413
2671
  /* @__PURE__ */ jsx(DialogDescription, { children: "Pick a channel and choose who to post as." })
@@ -2505,7 +2763,7 @@ function SendDialog({
2505
2763
  }
2506
2764
  var Popover = PopoverPrimitive.Root;
2507
2765
  var PopoverTrigger = PopoverPrimitive.Trigger;
2508
- var PopoverContent = React2.forwardRef(({ className, align = "start", sideOffset = 8, collisionPadding = 16, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
2766
+ var PopoverContent = React.forwardRef(({ className, align = "start", sideOffset = 8, collisionPadding = 16, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
2509
2767
  PopoverPrimitive.Content,
2510
2768
  {
2511
2769
  ref,
@@ -2521,9 +2779,9 @@ var PopoverContent = React2.forwardRef(({ className, align = "start", sideOffset
2521
2779
  }
2522
2780
  ) }));
2523
2781
  PopoverContent.displayName = PopoverPrimitive.Content.displayName;
2524
- var RadioGroup = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(RadioGroupPrimitive.Root, { className: cn("grid gap-2", className), ...props, ref }));
2782
+ var RadioGroup = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(RadioGroupPrimitive.Root, { className: cn("grid gap-2", className), ...props, ref }));
2525
2783
  RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
2526
- var RadioGroupItem = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2784
+ var RadioGroupItem = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2527
2785
  RadioGroupPrimitive.Item,
2528
2786
  {
2529
2787
  ref,
@@ -2655,7 +2913,7 @@ function ActionsEditor({ block, onChange }) {
2655
2913
  ] })
2656
2914
  ] });
2657
2915
  }
2658
- var Textarea = React2.forwardRef(
2916
+ var Textarea = React.forwardRef(
2659
2917
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2660
2918
  "textarea",
2661
2919
  {
@@ -3685,7 +3943,14 @@ function PlainTextInputEditor({
3685
3943
  }) {
3686
3944
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3687
3945
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
3688
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
3946
+ /* @__PURE__ */ jsx(
3947
+ PlaceholderField,
3948
+ {
3949
+ element,
3950
+ onChange,
3951
+ example: element.multiline ? "e.g. Enter a longer description" : "e.g. Enter some text"
3952
+ }
3953
+ ),
3689
3954
  /* @__PURE__ */ jsx(
3690
3955
  EditorField,
3691
3956
  {
@@ -3747,7 +4012,7 @@ function PlainTextInputEditor({
3747
4012
  function EmailInputEditor({ element, onChange }) {
3748
4013
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3749
4014
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
3750
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4015
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. name@example.com" }),
3751
4016
  /* @__PURE__ */ jsx(EditorField, { label: "Initial value", help: "Pre-filled email address.", htmlFor: "email-initial", children: /* @__PURE__ */ jsx(
3752
4017
  Input,
3753
4018
  {
@@ -3762,7 +4027,7 @@ function EmailInputEditor({ element, onChange }) {
3762
4027
  function URLInputEditor({ element, onChange }) {
3763
4028
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3764
4029
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
3765
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4030
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. https://example.com" }),
3766
4031
  /* @__PURE__ */ jsx(EditorField, { label: "Initial value", help: "Pre-filled URL.", htmlFor: "url-initial", children: /* @__PURE__ */ jsx(
3767
4032
  Input,
3768
4033
  {
@@ -3777,7 +4042,7 @@ function URLInputEditor({ element, onChange }) {
3777
4042
  function NumberInputEditor({ element, onChange }) {
3778
4043
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3779
4044
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
3780
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4045
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. 0" }),
3781
4046
  /* @__PURE__ */ jsx(
3782
4047
  CheckboxField,
3783
4048
  {
@@ -3830,7 +4095,7 @@ function NumberInputEditor({ element, onChange }) {
3830
4095
  function DatepickerEditor({ element, onChange }) {
3831
4096
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3832
4097
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
3833
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4098
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. Select a date" }),
3834
4099
  /* @__PURE__ */ jsx(EditorField, { label: "Initial date", help: "YYYY-MM-DD. Pre-selected on load.", htmlFor: "date-initial", children: /* @__PURE__ */ jsx(
3835
4100
  Input,
3836
4101
  {
@@ -3845,7 +4110,7 @@ function DatepickerEditor({ element, onChange }) {
3845
4110
  function TimepickerEditor({ element, onChange }) {
3846
4111
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3847
4112
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
3848
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4113
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. Select a time" }),
3849
4114
  /* @__PURE__ */ jsx(EditorField, { label: "Initial time", help: "HH:mm in 24-hour clock.", htmlFor: "time-initial", children: /* @__PURE__ */ jsx(
3850
4115
  Input,
3851
4116
  {
@@ -3898,7 +4163,7 @@ function DateTimepickerEditor({
3898
4163
  function StaticSelectEditor({ element, onChange }) {
3899
4164
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3900
4165
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
3901
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4166
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. Choose one" }),
3902
4167
  /* @__PURE__ */ jsx(
3903
4168
  PlainTextOptionsField,
3904
4169
  {
@@ -3914,7 +4179,7 @@ function MultiStaticSelectEditor({
3914
4179
  }) {
3915
4180
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3916
4181
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
3917
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4182
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. Choose one or more" }),
3918
4183
  /* @__PURE__ */ jsx(
3919
4184
  PlainTextOptionsField,
3920
4185
  {
@@ -3928,7 +4193,7 @@ function MultiStaticSelectEditor({
3928
4193
  function UsersSelectEditor({ element, onChange }) {
3929
4194
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3930
4195
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
3931
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4196
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. Select a user" }),
3932
4197
  /* @__PURE__ */ jsx(EditorField, { label: "Initial user ID", help: "Optional. Pre-selects this Slack user.", htmlFor: "users-initial", children: /* @__PURE__ */ jsx(
3933
4198
  Input,
3934
4199
  {
@@ -3946,7 +4211,7 @@ function MultiUsersSelectEditor({
3946
4211
  }) {
3947
4212
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3948
4213
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
3949
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4214
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. Select users" }),
3950
4215
  /* @__PURE__ */ jsx(MaxSelectedField, { element, onChange })
3951
4216
  ] });
3952
4217
  }
@@ -3956,7 +4221,7 @@ function ChannelsSelectEditor({
3956
4221
  }) {
3957
4222
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3958
4223
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
3959
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4224
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. Select a channel" }),
3960
4225
  /* @__PURE__ */ jsx(EditorField, { label: "Initial channel ID", help: "Optional. Pre-selects this channel.", htmlFor: "channels-initial", children: /* @__PURE__ */ jsx(
3961
4226
  Input,
3962
4227
  {
@@ -3977,7 +4242,7 @@ function MultiChannelsSelectEditor({
3977
4242
  }) {
3978
4243
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3979
4244
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
3980
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4245
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. Select channels" }),
3981
4246
  /* @__PURE__ */ jsx(MaxSelectedField, { element, onChange })
3982
4247
  ] });
3983
4248
  }
@@ -3987,7 +4252,7 @@ function ConversationsSelectEditor({
3987
4252
  }) {
3988
4253
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3989
4254
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
3990
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4255
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. Select a conversation" }),
3991
4256
  /* @__PURE__ */ jsx(
3992
4257
  EditorField,
3993
4258
  {
@@ -4029,7 +4294,7 @@ function MultiConversationsSelectEditor({
4029
4294
  }) {
4030
4295
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4031
4296
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
4032
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4297
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. Select conversations" }),
4033
4298
  /* @__PURE__ */ jsx(MaxSelectedField, { element, onChange }),
4034
4299
  /* @__PURE__ */ jsx(
4035
4300
  CheckboxField,
@@ -4052,7 +4317,7 @@ function ExternalSelectEditor({
4052
4317
  }) {
4053
4318
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4054
4319
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
4055
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4320
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. Choose one" }),
4056
4321
  /* @__PURE__ */ jsx(
4057
4322
  EditorField,
4058
4323
  {
@@ -4082,7 +4347,7 @@ function MultiExternalSelectEditor({
4082
4347
  }) {
4083
4348
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4084
4349
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
4085
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4350
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. Choose one or more" }),
4086
4351
  /* @__PURE__ */ jsx(
4087
4352
  EditorField,
4088
4353
  {
@@ -4137,7 +4402,7 @@ function RichTextInputEditor({
4137
4402
  }) {
4138
4403
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4139
4404
  /* @__PURE__ */ jsx(ActionIdField, { element, onChange }),
4140
- /* @__PURE__ */ jsx(PlaceholderField, { element, onChange }),
4405
+ /* @__PURE__ */ jsx(PlaceholderField, { element, onChange, example: "e.g. Type something" }),
4141
4406
  /* @__PURE__ */ jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "Edit the initial rich-text value via the View JSON drawer." })
4142
4407
  ] });
4143
4408
  }
@@ -4206,13 +4471,14 @@ function ActionIdField({
4206
4471
  }
4207
4472
  );
4208
4473
  }
4209
- function PlaceholderField({ element, onChange }) {
4474
+ function PlaceholderField({ element, onChange, example = "e.g. Type a hint" }) {
4210
4475
  return /* @__PURE__ */ jsx(EditorField, { label: "Placeholder", help: "Greyed-out hint shown when the input is empty.", htmlFor: "placeholder", children: /* @__PURE__ */ jsx(
4211
4476
  Input,
4212
4477
  {
4213
4478
  id: "placeholder",
4214
4479
  value: element.placeholder?.text ?? "",
4215
4480
  maxLength: 150,
4481
+ placeholder: example,
4216
4482
  onChange: (e) => onChange({
4217
4483
  ...element,
4218
4484
  placeholder: e.target.value ? { type: "plain_text", text: e.target.value, emoji: true } : void 0
@@ -4360,6 +4626,96 @@ function MarkdownEditor({ block, onChange }) {
4360
4626
  }
4361
4627
  );
4362
4628
  }
4629
+ var STATUSES = ["pending", "in_progress", "complete", "error"];
4630
+ function PlanEditor({ block, onChange }) {
4631
+ const titleText = typeof block.title === "string" ? block.title : block.title?.text ?? "";
4632
+ const tasks = block.tasks ?? [];
4633
+ const updateTask = (idx, change) => {
4634
+ onChange({
4635
+ ...block,
4636
+ tasks: tasks.map((t, i) => i === idx ? { ...t, ...change } : t)
4637
+ });
4638
+ };
4639
+ const removeTask = (idx) => {
4640
+ const next = tasks.filter((_, i) => i !== idx);
4641
+ onChange({ ...block, tasks: next.length > 0 ? next : void 0 });
4642
+ };
4643
+ const addTask = () => {
4644
+ onChange({
4645
+ ...block,
4646
+ tasks: [
4647
+ ...tasks,
4648
+ {
4649
+ type: "task_card",
4650
+ task_id: `task_${nanoid(6)}`,
4651
+ title: "New step",
4652
+ status: "pending"
4653
+ }
4654
+ ]
4655
+ });
4656
+ };
4657
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
4658
+ /* @__PURE__ */ jsx(EditorField, { label: "Title", help: "Heading shown above the task list.", htmlFor: "plan-title", children: /* @__PURE__ */ jsx(
4659
+ Input,
4660
+ {
4661
+ id: "plan-title",
4662
+ value: titleText,
4663
+ placeholder: "e.g. Investigating the issue",
4664
+ onChange: (e) => onChange({ ...block, title: e.target.value })
4665
+ }
4666
+ ) }),
4667
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 rounded-md border bg-muted/20 p-3", children: [
4668
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground", children: "Tasks" }),
4669
+ tasks.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "No tasks. Add one to render a checklist beneath the title." }) : null,
4670
+ tasks.map((task, idx) => {
4671
+ const status = task.status ?? "pending";
4672
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 rounded border bg-background p-2", children: [
4673
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
4674
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-foreground", children: [
4675
+ "Task ",
4676
+ idx + 1
4677
+ ] }),
4678
+ /* @__PURE__ */ jsx(
4679
+ "button",
4680
+ {
4681
+ type: "button",
4682
+ "aria-label": "Remove task",
4683
+ onClick: () => removeTask(idx),
4684
+ className: "rounded p-1 text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
4685
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
4686
+ }
4687
+ )
4688
+ ] }),
4689
+ /* @__PURE__ */ jsx(EditorField, { label: "Title", htmlFor: `plan-task-title-${idx}`, children: /* @__PURE__ */ jsx(
4690
+ Input,
4691
+ {
4692
+ id: `plan-task-title-${idx}`,
4693
+ value: task.title,
4694
+ placeholder: "e.g. Reproduce the error locally",
4695
+ onChange: (e) => updateTask(idx, { title: e.target.value })
4696
+ }
4697
+ ) }),
4698
+ /* @__PURE__ */ jsx(EditorField, { label: "Status", children: /* @__PURE__ */ jsx(
4699
+ RadioGroup,
4700
+ {
4701
+ value: status,
4702
+ onValueChange: (v) => updateTask(idx, { status: v }),
4703
+ className: "flex flex-row flex-wrap gap-3",
4704
+ children: STATUSES.map((s) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
4705
+ /* @__PURE__ */ jsx(RadioGroupItem, { value: s, id: `plan-task-status-${idx}-${s}` }),
4706
+ /* @__PURE__ */ jsx(Label, { htmlFor: `plan-task-status-${idx}-${s}`, className: "text-xs capitalize", children: s.replace("_", " ") })
4707
+ ] }, s))
4708
+ }
4709
+ ) })
4710
+ ] }, idx);
4711
+ }),
4712
+ /* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: addTask, className: "self-start", children: [
4713
+ /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
4714
+ " Add task"
4715
+ ] })
4716
+ ] })
4717
+ ] });
4718
+ }
4363
4719
 
4364
4720
  // src/lib/rich-text-tiptap.ts
4365
4721
  var SUPPORTED_BLOCK_KINDS = /* @__PURE__ */ new Set([
@@ -5850,24 +6206,263 @@ function TableEditor({ block, onChange }) {
5850
6206
  ] })
5851
6207
  ] });
5852
6208
  }
5853
- function BlockEditor({
5854
- block,
5855
- errors,
5856
- onChange
5857
- }) {
5858
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
5859
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("h3", { className: "text-sm font-semibold text-foreground", children: [
5860
- "Edit ",
5861
- labelForBlockType(block.type)
5862
- ] }) }),
5863
- errors && errors.length > 0 ? /* @__PURE__ */ 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__ */ jsx("li", { children: err }, i)) }) : null,
5864
- dispatch(block, onChange)
5865
- ] });
5866
- }
5867
- function dispatch(block, onChange) {
5868
- switch (block.type) {
5869
- case "section":
5870
- return /* @__PURE__ */ jsx(SectionEditor, { block, onChange: (next) => onChange(next) });
6209
+ var STATUSES2 = ["pending", "in_progress", "complete", "error"];
6210
+ function TaskCardEditor({ block, onChange }) {
6211
+ const status = block.status ?? "pending";
6212
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
6213
+ /* @__PURE__ */ jsx(EditorField, { label: "Title", help: "Short label shown at the top of the card.", htmlFor: "task-card-title", children: /* @__PURE__ */ jsx(
6214
+ Input,
6215
+ {
6216
+ id: "task-card-title",
6217
+ value: block.title,
6218
+ placeholder: "e.g. Reproduce the bug locally",
6219
+ onChange: (e) => onChange({ ...block, title: e.target.value })
6220
+ }
6221
+ ) }),
6222
+ /* @__PURE__ */ jsx(
6223
+ EditorField,
6224
+ {
6225
+ label: "Task ID",
6226
+ help: "Stable identifier you can reference from interaction payloads.",
6227
+ htmlFor: "task-card-id",
6228
+ children: /* @__PURE__ */ jsx(
6229
+ Input,
6230
+ {
6231
+ id: "task-card-id",
6232
+ value: block.task_id,
6233
+ placeholder: "e.g. task_1",
6234
+ onChange: (e) => onChange({ ...block, task_id: e.target.value })
6235
+ }
6236
+ )
6237
+ }
6238
+ ),
6239
+ /* @__PURE__ */ jsx(EditorField, { label: "Status", help: "Slack renders a matching status chip on the card.", children: /* @__PURE__ */ jsx(
6240
+ RadioGroup,
6241
+ {
6242
+ value: status,
6243
+ onValueChange: (v) => onChange({ ...block, status: v }),
6244
+ className: "flex flex-row flex-wrap gap-3",
6245
+ children: STATUSES2.map((s) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
6246
+ /* @__PURE__ */ jsx(RadioGroupItem, { value: s, id: `task-card-status-${s}` }),
6247
+ /* @__PURE__ */ jsx(Label, { htmlFor: `task-card-status-${s}`, className: "text-xs capitalize", children: s.replace("_", " ") })
6248
+ ] }, s))
6249
+ }
6250
+ ) }),
6251
+ /* @__PURE__ */ jsx(
6252
+ SourcesField,
6253
+ {
6254
+ sources: block.sources ?? [],
6255
+ onChange: (next) => onChange({ ...block, sources: next.length > 0 ? next : void 0 })
6256
+ }
6257
+ )
6258
+ ] });
6259
+ }
6260
+ function SourcesField({
6261
+ sources,
6262
+ onChange
6263
+ }) {
6264
+ const update = (idx, change) => {
6265
+ onChange(sources.map((s, i) => i === idx ? { ...s, ...change } : s));
6266
+ };
6267
+ const removeAt = (idx) => onChange(sources.filter((_, i) => i !== idx));
6268
+ const addSource = () => {
6269
+ onChange([...sources, { type: "url", url: "", text: "" }]);
6270
+ };
6271
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 rounded-md border bg-muted/20 p-3", children: [
6272
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground", children: "Sources" }),
6273
+ sources.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "No sources. Add one to cite a document or link beneath the card." }) : null,
6274
+ sources.map((src, idx) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 rounded border bg-background p-2", children: [
6275
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
6276
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-foreground", children: [
6277
+ "Source ",
6278
+ idx + 1
6279
+ ] }),
6280
+ /* @__PURE__ */ jsx(
6281
+ "button",
6282
+ {
6283
+ type: "button",
6284
+ "aria-label": "Remove source",
6285
+ onClick: () => removeAt(idx),
6286
+ className: "rounded p-1 text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
6287
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
6288
+ }
6289
+ )
6290
+ ] }),
6291
+ /* @__PURE__ */ jsx(EditorField, { label: "Label", htmlFor: `task-card-source-text-${idx}`, children: /* @__PURE__ */ jsx(
6292
+ Input,
6293
+ {
6294
+ id: `task-card-source-text-${idx}`,
6295
+ value: src.text,
6296
+ placeholder: "e.g. Runbook",
6297
+ onChange: (e) => update(idx, { text: e.target.value })
6298
+ }
6299
+ ) }),
6300
+ /* @__PURE__ */ jsx(EditorField, { label: "URL", htmlFor: `task-card-source-url-${idx}`, children: /* @__PURE__ */ jsx(
6301
+ Input,
6302
+ {
6303
+ id: `task-card-source-url-${idx}`,
6304
+ type: "url",
6305
+ value: src.url,
6306
+ placeholder: "e.g. https://example.com/runbook",
6307
+ onChange: (e) => update(idx, { url: e.target.value })
6308
+ }
6309
+ ) })
6310
+ ] }, idx)),
6311
+ /* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: addSource, className: "self-start", children: [
6312
+ /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
6313
+ " Add source"
6314
+ ] })
6315
+ ] });
6316
+ }
6317
+ function VideoEditor({ block, onChange }) {
6318
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
6319
+ /* @__PURE__ */ jsx(EditorField, { label: "Title", help: "Up to 199 characters. Shown above the embedded player.", htmlFor: "video-title", children: /* @__PURE__ */ jsx(
6320
+ Input,
6321
+ {
6322
+ id: "video-title",
6323
+ value: block.title?.text ?? "",
6324
+ maxLength: 199,
6325
+ placeholder: "e.g. Product demo",
6326
+ onChange: (e) => onChange({
6327
+ ...block,
6328
+ title: { type: "plain_text", text: e.target.value, emoji: true }
6329
+ })
6330
+ }
6331
+ ) }),
6332
+ /* @__PURE__ */ jsx(EditorField, { label: "Alt text", help: "Tooltip for the video. Required for accessibility.", htmlFor: "video-alt", children: /* @__PURE__ */ jsx(
6333
+ Input,
6334
+ {
6335
+ id: "video-alt",
6336
+ value: block.alt_text ?? "",
6337
+ placeholder: "e.g. A short walkthrough of the new release",
6338
+ onChange: (e) => onChange({ ...block, alt_text: e.target.value })
6339
+ }
6340
+ ) }),
6341
+ /* @__PURE__ */ jsx(
6342
+ EditorField,
6343
+ {
6344
+ label: "Video URL",
6345
+ help: "HTTPS embed URL. Must match an unfurl domain on your Slack app.",
6346
+ htmlFor: "video-url",
6347
+ children: /* @__PURE__ */ jsx(
6348
+ Input,
6349
+ {
6350
+ id: "video-url",
6351
+ type: "url",
6352
+ value: block.video_url ?? "",
6353
+ placeholder: "e.g. https://www.youtube.com/embed/dQw4w9WgXcQ",
6354
+ onChange: (e) => onChange({ ...block, video_url: e.target.value })
6355
+ }
6356
+ )
6357
+ }
6358
+ ),
6359
+ /* @__PURE__ */ jsx(EditorField, { label: "Thumbnail URL", help: "Preview image shown before the video loads.", htmlFor: "video-thumbnail", children: /* @__PURE__ */ jsx(
6360
+ Input,
6361
+ {
6362
+ id: "video-thumbnail",
6363
+ type: "url",
6364
+ value: block.thumbnail_url ?? "",
6365
+ placeholder: "e.g. https://example.com/thumb.png",
6366
+ onChange: (e) => onChange({ ...block, thumbnail_url: e.target.value })
6367
+ }
6368
+ ) }),
6369
+ /* @__PURE__ */ jsx(
6370
+ EditorField,
6371
+ {
6372
+ label: "Title link URL",
6373
+ help: "Optional. HTTPS link the title text opens (the non-embed page).",
6374
+ htmlFor: "video-title-url",
6375
+ children: /* @__PURE__ */ jsx(
6376
+ Input,
6377
+ {
6378
+ id: "video-title-url",
6379
+ type: "url",
6380
+ value: block.title_url ?? "",
6381
+ placeholder: "e.g. https://www.youtube.com/watch?v=dQw4w9WgXcQ",
6382
+ onChange: (e) => onChange({ ...block, title_url: e.target.value || void 0 })
6383
+ }
6384
+ )
6385
+ }
6386
+ ),
6387
+ /* @__PURE__ */ jsx(EditorField, { label: "Description", help: "Optional. Up to 199 characters.", htmlFor: "video-description", children: /* @__PURE__ */ jsx(
6388
+ Textarea,
6389
+ {
6390
+ id: "video-description",
6391
+ value: block.description?.text ?? "",
6392
+ maxLength: 199,
6393
+ rows: 2,
6394
+ placeholder: "e.g. A short walkthrough of the new release.",
6395
+ onChange: (e) => onChange({
6396
+ ...block,
6397
+ description: e.target.value ? { type: "plain_text", text: e.target.value, emoji: true } : void 0
6398
+ })
6399
+ }
6400
+ ) }),
6401
+ /* @__PURE__ */ jsx(EditorField, { label: "Author name", help: "Optional. Up to 49 characters.", htmlFor: "video-author", children: /* @__PURE__ */ jsx(
6402
+ Input,
6403
+ {
6404
+ id: "video-author",
6405
+ value: block.author_name ?? "",
6406
+ maxLength: 49,
6407
+ placeholder: "e.g. Acme",
6408
+ onChange: (e) => onChange({ ...block, author_name: e.target.value || void 0 })
6409
+ }
6410
+ ) }),
6411
+ /* @__PURE__ */ jsx(
6412
+ EditorField,
6413
+ {
6414
+ label: "Provider name",
6415
+ help: "Optional. Originating service (e.g. YouTube, Vimeo).",
6416
+ htmlFor: "video-provider-name",
6417
+ children: /* @__PURE__ */ jsx(
6418
+ Input,
6419
+ {
6420
+ id: "video-provider-name",
6421
+ value: block.provider_name ?? "",
6422
+ placeholder: "e.g. YouTube",
6423
+ onChange: (e) => onChange({ ...block, provider_name: e.target.value || void 0 })
6424
+ }
6425
+ )
6426
+ }
6427
+ ),
6428
+ /* @__PURE__ */ jsx(
6429
+ EditorField,
6430
+ {
6431
+ label: "Provider icon URL",
6432
+ help: "Optional. Small icon shown next to the provider name.",
6433
+ htmlFor: "video-provider-icon",
6434
+ children: /* @__PURE__ */ jsx(
6435
+ Input,
6436
+ {
6437
+ id: "video-provider-icon",
6438
+ type: "url",
6439
+ value: block.provider_icon_url ?? "",
6440
+ placeholder: "e.g. https://example.com/youtube-favicon.png",
6441
+ onChange: (e) => onChange({ ...block, provider_icon_url: e.target.value || void 0 })
6442
+ }
6443
+ )
6444
+ }
6445
+ )
6446
+ ] });
6447
+ }
6448
+ function BlockEditor({
6449
+ block,
6450
+ errors,
6451
+ onChange
6452
+ }) {
6453
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
6454
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("h3", { className: "text-sm font-semibold text-foreground", children: [
6455
+ "Edit ",
6456
+ labelForBlockType(block.type)
6457
+ ] }) }),
6458
+ errors && errors.length > 0 ? /* @__PURE__ */ 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__ */ jsx("li", { children: err }, i)) }) : null,
6459
+ dispatch(block, onChange)
6460
+ ] });
6461
+ }
6462
+ function dispatch(block, onChange) {
6463
+ switch (block.type) {
6464
+ case "section":
6465
+ return /* @__PURE__ */ jsx(SectionEditor, { block, onChange: (next) => onChange(next) });
5871
6466
  case "header":
5872
6467
  return /* @__PURE__ */ jsx(HeaderEditor, { block, onChange: (next) => onChange(next) });
5873
6468
  case "divider":
@@ -5894,6 +6489,12 @@ function dispatch(block, onChange) {
5894
6489
  return /* @__PURE__ */ jsx(ContextActionsEditor, { block, onChange: (next) => onChange(next) });
5895
6490
  case "input":
5896
6491
  return /* @__PURE__ */ jsx(InputEditor, { block, onChange: (next) => onChange(next) });
6492
+ case "video":
6493
+ return /* @__PURE__ */ jsx(VideoEditor, { block, onChange: (next) => onChange(next) });
6494
+ case "plan":
6495
+ return /* @__PURE__ */ jsx(PlanEditor, { block, onChange: (next) => onChange(next) });
6496
+ case "task_card":
6497
+ return /* @__PURE__ */ jsx(TaskCardEditor, { block, onChange: (next) => onChange(next) });
5897
6498
  default:
5898
6499
  return null;
5899
6500
  }
@@ -5966,7 +6567,10 @@ var BLOCK_TYPE_LABELS = {
5966
6567
  card: "Card",
5967
6568
  carousel: "Carousel",
5968
6569
  context_actions: "Context Actions",
5969
- input: "Input"
6570
+ input: "Input",
6571
+ video: "Video",
6572
+ plan: "Plan",
6573
+ task_card: "Task Card"
5970
6574
  };
5971
6575
  function BlockRow({
5972
6576
  builderBlock,
@@ -5978,6 +6582,9 @@ function BlockRow({
5978
6582
  onUpdate,
5979
6583
  onDuplicate,
5980
6584
  onDelete,
6585
+ index,
6586
+ total,
6587
+ onReorder,
5981
6588
  isPaletteDrag = false
5982
6589
  }) {
5983
6590
  const { attributes, listeners, setNodeRef, transform, transition, isDragging, isOver } = useSortable({
@@ -5993,144 +6600,243 @@ function BlockRow({
5993
6600
  const [inlineEditing, setInlineEditing] = useState(false);
5994
6601
  const showDropIndicator = isPaletteDrag && isOver;
5995
6602
  const preview = /* @__PURE__ */ jsx(SlackBlockPreview, { block: builderBlock.block, hooks: previewHooks, theme: previewTheme });
5996
- return /* @__PURE__ */ jsxs("div", { ref: setNodeRef, style, className: cn("group relative hover:z-10", isDragging && "opacity-40"), children: [
5997
- showDropIndicator ? /* @__PURE__ */ jsx(
5998
- "div",
5999
- {
6000
- "aria-hidden": "true",
6001
- className: "-top-1 pointer-events-none absolute right-0 left-0 z-20 h-0.5 rounded-full bg-primary",
6002
- children: /* @__PURE__ */ jsx("span", { className: "-left-1 -top-[3px] absolute h-2 w-2 rounded-full bg-primary shadow-[0_0_0_2px_var(--color-background)]" })
6003
- }
6004
- ) : null,
6005
- /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
6006
- isRichText && inlineEditing ? /* @__PURE__ */ jsx(
6007
- RichTextInlineEditor,
6008
- {
6009
- block: builderBlock.block,
6010
- onSave: (next) => {
6011
- onUpdate(builderBlock.id, next);
6012
- setInlineEditing(false);
6013
- },
6014
- onCancel: () => setInlineEditing(false)
6015
- }
6016
- ) : isRichText ? /* @__PURE__ */ jsx(
6017
- "button",
6018
- {
6019
- type: "button",
6020
- "aria-label": "Edit block",
6021
- onClick: () => setInlineEditing(true),
6022
- ...attributes,
6023
- ...listeners,
6024
- className: cn(
6025
- "block w-full cursor-grab rounded-sm border-0 bg-transparent p-0 text-left transition-shadow hover:shadow-md focus-visible:ring-1 focus-visible:ring-ring active:cursor-grabbing",
6026
- hasErrors ? "ring-1 ring-destructive/60 hover:ring-destructive" : "hover:ring-1 hover:ring-border"
6027
- ),
6028
- children: preview
6029
- }
6030
- ) : /* @__PURE__ */ jsxs(Popover, { open: isOpen, onOpenChange, children: [
6031
- /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6603
+ return /* @__PURE__ */ jsxs(
6604
+ "div",
6605
+ {
6606
+ ref: setNodeRef,
6607
+ style,
6608
+ className: cn("group relative mb-2 last:mb-0 hover:z-10 md:mb-0", isDragging && "opacity-40"),
6609
+ children: [
6610
+ showDropIndicator ? /* @__PURE__ */ jsx(
6032
6611
  "div",
6033
6612
  {
6034
- role: "button",
6035
- tabIndex: 0,
6036
- "aria-label": "Edit block",
6037
- ...sortableA11yAttrs,
6038
- ...listeners,
6039
- className: cn(
6040
- "block w-full cursor-grab rounded-sm transition-shadow hover:shadow-md focus-visible:ring-1 focus-visible:ring-ring active:cursor-grabbing",
6041
- hasErrors ? "ring-1 ring-destructive/60 hover:ring-destructive" : "hover:ring-1 hover:ring-border"
6042
- ),
6043
- children: preview
6613
+ "aria-hidden": "true",
6614
+ className: "-top-1 pointer-events-none absolute right-0 left-0 z-20 h-0.5 rounded-full bg-primary",
6615
+ children: /* @__PURE__ */ jsx("span", { className: "-left-1 -top-[3px] absolute h-2 w-2 rounded-full bg-primary shadow-[0_0_0_2px_var(--color-background)]" })
6044
6616
  }
6045
- ) }),
6046
- /* @__PURE__ */ jsx(PopoverContent, { className: "w-[32rem]", align: "start", children: /* @__PURE__ */ jsx(
6047
- BlockEditor,
6048
- {
6049
- block: builderBlock.block,
6050
- errors,
6051
- onChange: (next) => onUpdate(builderBlock.id, next)
6052
- }
6053
- ) })
6054
- ] }),
6055
- /* @__PURE__ */ jsx("span", { className: "-translate-x-1/2 pointer-events-none absolute bottom-full left-1/2 z-10 bg-background px-1.5 text-[11px] text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100", children: BLOCK_TYPE_LABELS[builderBlock.block.type] }),
6056
- /* @__PURE__ */ jsxs(
6057
- "div",
6058
- {
6059
- className: cn(
6060
- "absolute -top-3 right-2 z-10 flex items-center gap-0.5 rounded-md border bg-background p-0.5 shadow-sm transition-opacity",
6061
- hasErrors ? "opacity-100" : "opacity-0 group-hover:opacity-100"
6062
- ),
6063
- children: [
6064
- hasErrors ? /* @__PURE__ */ jsxs(Tooltip, { children: [
6065
- /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6066
- "button",
6067
- {
6068
- type: "button",
6069
- "aria-label": `Show ${errors.length} validation ${errors.length === 1 ? "issue" : "issues"}`,
6070
- onClick: () => onOpenChange?.(true),
6071
- className: "flex h-6 w-6 items-center justify-center rounded text-destructive hover:bg-destructive/10",
6072
- children: /* @__PURE__ */ jsx(AlertTriangle, { className: "h-3.5 w-3.5" })
6073
- }
6074
- ) }),
6075
- /* @__PURE__ */ jsx(TooltipContent, { side: "top", align: "end", children: /* @__PURE__ */ jsxs("ul", { className: "flex flex-col gap-0.5", children: [
6076
- errors.slice(0, 4).map((err, i) => /* @__PURE__ */ jsx("li", { children: err }, i)),
6077
- errors.length > 4 ? /* @__PURE__ */ jsxs("li", { className: "text-muted-foreground", children: [
6078
- "and ",
6079
- errors.length - 4,
6080
- " more"
6081
- ] }) : null
6082
- ] }) })
6083
- ] }) : null,
6084
- /* @__PURE__ */ jsxs(Tooltip, { children: [
6085
- /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6086
- "button",
6087
- {
6088
- type: "button",
6089
- "aria-label": "Edit block",
6090
- onClick: () => {
6091
- if (isRichText) {
6092
- setInlineEditing(true);
6093
- } else {
6094
- onOpenChange?.(true);
6617
+ ) : null,
6618
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
6619
+ isRichText && inlineEditing ? /* @__PURE__ */ jsx(
6620
+ RichTextInlineEditor,
6621
+ {
6622
+ block: builderBlock.block,
6623
+ onSave: (next) => {
6624
+ onUpdate(builderBlock.id, next);
6625
+ setInlineEditing(false);
6626
+ },
6627
+ onCancel: () => setInlineEditing(false)
6628
+ }
6629
+ ) : isRichText ? /* @__PURE__ */ jsx(
6630
+ "button",
6631
+ {
6632
+ type: "button",
6633
+ "aria-label": "Edit block",
6634
+ onClick: () => setInlineEditing(true),
6635
+ ...attributes,
6636
+ ...listeners,
6637
+ className: cn(
6638
+ "block w-full cursor-grab rounded-sm border-0 bg-transparent p-0 text-left transition-shadow hover:shadow-md focus-visible:ring-1 focus-visible:ring-ring active:cursor-grabbing",
6639
+ hasErrors ? "ring-1 ring-destructive/60 hover:ring-destructive" : "hover:ring-1 hover:ring-border"
6640
+ ),
6641
+ children: preview
6642
+ }
6643
+ ) : /* @__PURE__ */ jsxs(Popover, { open: isOpen, onOpenChange, children: [
6644
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6645
+ "div",
6646
+ {
6647
+ role: "button",
6648
+ tabIndex: 0,
6649
+ "aria-label": "Edit block",
6650
+ ...sortableA11yAttrs,
6651
+ ...listeners,
6652
+ onKeyDown: (e) => {
6653
+ if (e.key === "Enter" || e.key === " ") {
6654
+ e.preventDefault();
6655
+ onOpenChange?.(!isOpen);
6656
+ }
6657
+ },
6658
+ className: cn(
6659
+ "block w-full cursor-grab rounded-sm transition-shadow hover:shadow-md focus-visible:ring-1 focus-visible:ring-ring active:cursor-grabbing",
6660
+ hasErrors ? "ring-1 ring-destructive/60 hover:ring-destructive" : "hover:ring-1 hover:ring-border"
6661
+ ),
6662
+ children: preview
6663
+ }
6664
+ ) }),
6665
+ /* @__PURE__ */ jsx(PopoverContent, { className: "w-[min(32rem,calc(100vw-1.5rem))] sm:w-[32rem]", align: "start", children: /* @__PURE__ */ jsx(
6666
+ BlockEditor,
6667
+ {
6668
+ block: builderBlock.block,
6669
+ errors,
6670
+ onChange: (next) => onUpdate(builderBlock.id, next)
6671
+ }
6672
+ ) })
6673
+ ] }),
6674
+ /* @__PURE__ */ 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] }),
6675
+ /* @__PURE__ */ jsxs(
6676
+ "div",
6677
+ {
6678
+ className: cn(
6679
+ // Hidden on mobile in favor of the inline row below; on desktop
6680
+ // reveal on hover, on focus inside the row (so Tab-stops on the
6681
+ // floating buttons themselves keep them visible), and when there
6682
+ // are validation errors worth surfacing immediately.
6683
+ "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",
6684
+ hasErrors ? "opacity-100" : "opacity-0 group-hover:opacity-100 group-focus-within:opacity-100"
6685
+ ),
6686
+ children: [
6687
+ hasErrors ? /* @__PURE__ */ jsxs(Tooltip, { children: [
6688
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6689
+ "button",
6690
+ {
6691
+ type: "button",
6692
+ "aria-label": `Show ${errors.length} validation ${errors.length === 1 ? "issue" : "issues"}`,
6693
+ onClick: () => onOpenChange?.(true),
6694
+ 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",
6695
+ children: /* @__PURE__ */ jsx(AlertTriangle, { className: "h-3.5 w-3.5" })
6095
6696
  }
6096
- },
6097
- className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground",
6098
- children: /* @__PURE__ */ jsx(Pencil, { className: "h-3.5 w-3.5" })
6099
- }
6100
- ) }),
6101
- /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: "Edit" })
6102
- ] }),
6103
- /* @__PURE__ */ jsxs(Tooltip, { children: [
6104
- /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6105
- "button",
6106
- {
6107
- type: "button",
6108
- "aria-label": "Duplicate block",
6109
- onClick: () => onDuplicate(builderBlock.id),
6110
- className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground",
6111
- children: /* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5" })
6112
- }
6113
- ) }),
6114
- /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: "Duplicate" })
6115
- ] }),
6116
- /* @__PURE__ */ jsxs(Tooltip, { children: [
6117
- /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6118
- "button",
6119
- {
6120
- type: "button",
6121
- "aria-label": "Delete block",
6122
- onClick: () => onDelete(builderBlock.id),
6123
- className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
6124
- children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
6125
- }
6126
- ) }),
6127
- /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: "Delete" })
6128
- ] })
6129
- ]
6130
- }
6131
- )
6132
- ] })
6133
- ] });
6697
+ ) }),
6698
+ /* @__PURE__ */ jsx(TooltipContent, { side: "top", align: "end", children: /* @__PURE__ */ jsxs("ul", { className: "flex flex-col gap-0.5", children: [
6699
+ errors.slice(0, 4).map((err, i) => /* @__PURE__ */ jsx("li", { children: err }, i)),
6700
+ errors.length > 4 ? /* @__PURE__ */ jsxs("li", { className: "text-muted-foreground", children: [
6701
+ "and ",
6702
+ errors.length - 4,
6703
+ " more"
6704
+ ] }) : null
6705
+ ] }) })
6706
+ ] }) : null,
6707
+ onReorder && typeof index === "number" && typeof total === "number" ? /* @__PURE__ */ jsxs(Fragment, { children: [
6708
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
6709
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6710
+ "button",
6711
+ {
6712
+ type: "button",
6713
+ "aria-label": "Move block up",
6714
+ disabled: index === 0,
6715
+ onClick: () => onReorder(builderBlock.id, index - 1),
6716
+ 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",
6717
+ children: /* @__PURE__ */ jsx(ArrowUp, { className: "h-3.5 w-3.5" })
6718
+ }
6719
+ ) }),
6720
+ /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: "Move up" })
6721
+ ] }),
6722
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
6723
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6724
+ "button",
6725
+ {
6726
+ type: "button",
6727
+ "aria-label": "Move block down",
6728
+ disabled: index >= total - 1,
6729
+ onClick: () => onReorder(builderBlock.id, index + 1),
6730
+ 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",
6731
+ children: /* @__PURE__ */ jsx(ArrowDown, { className: "h-3.5 w-3.5" })
6732
+ }
6733
+ ) }),
6734
+ /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: "Move down" })
6735
+ ] })
6736
+ ] }) : null,
6737
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
6738
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6739
+ "button",
6740
+ {
6741
+ type: "button",
6742
+ "aria-label": "Edit block",
6743
+ onClick: () => {
6744
+ if (isRichText) {
6745
+ setInlineEditing(true);
6746
+ } else {
6747
+ onOpenChange?.(true);
6748
+ }
6749
+ },
6750
+ 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",
6751
+ children: /* @__PURE__ */ jsx(Pencil, { className: "h-3.5 w-3.5" })
6752
+ }
6753
+ ) }),
6754
+ /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: "Edit" })
6755
+ ] }),
6756
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
6757
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6758
+ "button",
6759
+ {
6760
+ type: "button",
6761
+ "aria-label": "Duplicate block",
6762
+ onClick: () => onDuplicate(builderBlock.id),
6763
+ 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",
6764
+ children: /* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5" })
6765
+ }
6766
+ ) }),
6767
+ /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: "Duplicate" })
6768
+ ] }),
6769
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
6770
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6771
+ "button",
6772
+ {
6773
+ type: "button",
6774
+ "aria-label": "Delete block",
6775
+ onClick: () => onDelete(builderBlock.id),
6776
+ 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",
6777
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
6778
+ }
6779
+ ) }),
6780
+ /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: "Delete" })
6781
+ ] })
6782
+ ]
6783
+ }
6784
+ )
6785
+ ] }),
6786
+ /* @__PURE__ */ 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: [
6787
+ /* @__PURE__ */ jsx("span", { className: "truncate text-[11px] font-medium text-muted-foreground", children: BLOCK_TYPE_LABELS[builderBlock.block.type] }),
6788
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
6789
+ hasErrors ? /* @__PURE__ */ jsx(
6790
+ "button",
6791
+ {
6792
+ type: "button",
6793
+ "aria-label": `Show ${errors.length} validation ${errors.length === 1 ? "issue" : "issues"}`,
6794
+ onClick: () => onOpenChange?.(true),
6795
+ className: "flex h-9 w-9 items-center justify-center rounded text-destructive hover:bg-destructive/10",
6796
+ children: /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4" })
6797
+ }
6798
+ ) : null,
6799
+ /* @__PURE__ */ jsx(
6800
+ "button",
6801
+ {
6802
+ type: "button",
6803
+ "aria-label": "Edit block",
6804
+ onClick: () => {
6805
+ if (isRichText) {
6806
+ setInlineEditing(true);
6807
+ } else {
6808
+ onOpenChange?.(true);
6809
+ }
6810
+ },
6811
+ className: "flex h-9 w-9 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground",
6812
+ children: /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" })
6813
+ }
6814
+ ),
6815
+ /* @__PURE__ */ jsx(
6816
+ "button",
6817
+ {
6818
+ type: "button",
6819
+ "aria-label": "Duplicate block",
6820
+ onClick: () => onDuplicate(builderBlock.id),
6821
+ className: "flex h-9 w-9 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground",
6822
+ children: /* @__PURE__ */ jsx(Copy, { className: "h-4 w-4" })
6823
+ }
6824
+ ),
6825
+ /* @__PURE__ */ jsx(
6826
+ "button",
6827
+ {
6828
+ type: "button",
6829
+ "aria-label": "Delete block",
6830
+ onClick: () => onDelete(builderBlock.id),
6831
+ className: "flex h-9 w-9 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
6832
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
6833
+ }
6834
+ )
6835
+ ] })
6836
+ ] })
6837
+ ]
6838
+ }
6839
+ );
6134
6840
  }
6135
6841
  function RichTextInlineEditor({
6136
6842
  block,
@@ -6171,7 +6877,9 @@ function Surface({
6171
6877
  onUpdate,
6172
6878
  onDuplicate,
6173
6879
  onDelete,
6174
- isPaletteDrag = false
6880
+ onReorder,
6881
+ isPaletteDrag = false,
6882
+ onOpenPalette
6175
6883
  }) {
6176
6884
  const { setNodeRef, isOver } = useDroppable({ id: SURFACE_DROPPABLE_ID });
6177
6885
  const isDark = previewTheme === "dark";
@@ -6181,13 +6889,13 @@ function Surface({
6181
6889
  {
6182
6890
  ref: setNodeRef,
6183
6891
  className: cn(
6184
- "flex min-h-[240px] flex-col px-5 py-2 transition-colors",
6892
+ "flex min-h-[180px] flex-col px-3 py-2 transition-colors sm:min-h-[240px] sm:px-5",
6185
6893
  isDark ? "bg-[#1a1d21]" : "bg-white",
6186
6894
  isPaletteDrag && (isDark ? "bg-[#22262c] outline-2 outline-primary/40 -outline-offset-2 outline-dashed" : "bg-[#f5f8ff] outline-2 outline-primary/40 -outline-offset-2 outline-dashed"),
6187
6895
  isPaletteDrag && isOver && (isDark ? "bg-[#2c3036]" : "bg-[#eaf0ff]")
6188
6896
  ),
6189
- children: blocks.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { isDark, isPaletteDrag, isOver }) : /* @__PURE__ */ jsxs(SortableContext, { items: blocks.map((b) => b.id), strategy: verticalListSortingStrategy, children: [
6190
- blocks.map((block) => /* @__PURE__ */ jsx(
6897
+ children: blocks.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { isDark, isPaletteDrag, isOver, onOpenPalette }) : /* @__PURE__ */ jsxs(SortableContext, { items: blocks.map((b) => b.id), strategy: verticalListSortingStrategy, children: [
6898
+ blocks.map((block, idx) => /* @__PURE__ */ jsx(
6191
6899
  BlockRow,
6192
6900
  {
6193
6901
  builderBlock: block,
@@ -6199,6 +6907,9 @@ function Surface({
6199
6907
  onUpdate,
6200
6908
  onDuplicate,
6201
6909
  onDelete,
6910
+ index: idx,
6911
+ total: blocks.length,
6912
+ onReorder,
6202
6913
  isPaletteDrag
6203
6914
  },
6204
6915
  block.id
@@ -6207,7 +6918,14 @@ function Surface({
6207
6918
  ] })
6208
6919
  }
6209
6920
  );
6210
- return /* @__PURE__ */ jsx("div", { className: cn("flex flex-1 flex-col p-6", isDark ? "bg-[#0e0f12]" : "bg-[#f4f4f4]"), children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-2xl", children: previewSurface === "modal" ? /* @__PURE__ */ jsx(ModalFrame, { isDark, children: blocksList }) : previewSurface === "app_home" ? /* @__PURE__ */ jsx(AppHomeFrame, { workspaceName, isDark, children: blocksList }) : /* @__PURE__ */ jsx(MessageFrame, { workspaceName, isDark, children: blocksList }) }) });
6921
+ return /* @__PURE__ */ jsx(
6922
+ "main",
6923
+ {
6924
+ "aria-label": "Block preview",
6925
+ className: cn("flex min-w-0 flex-1 flex-col overflow-y-auto bg-muted p-3 sm:p-6"),
6926
+ children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-2xl", children: previewSurface === "modal" ? /* @__PURE__ */ jsx(ModalFrame, { isDark, children: blocksList }) : previewSurface === "app_home" ? /* @__PURE__ */ jsx(AppHomeFrame, { workspaceName, isDark, children: blocksList }) : /* @__PURE__ */ jsx(MessageFrame, { workspaceName, isDark, children: blocksList }) })
6927
+ }
6928
+ );
6211
6929
  }
6212
6930
  function MessageFrame({
6213
6931
  workspaceName,
@@ -6277,13 +6995,12 @@ function ModalFrame({ isDark, children }) {
6277
6995
  children: [
6278
6996
  /* @__PURE__ */ jsx("h2", { className: cn("text-base font-bold", isDark ? "text-white" : "text-[#1d1c1d]"), children: "Modal title" }),
6279
6997
  /* @__PURE__ */ jsx(
6280
- "button",
6998
+ "span",
6281
6999
  {
6282
- type: "button",
6283
- "aria-label": "Close",
7000
+ "aria-hidden": "true",
6284
7001
  className: cn(
6285
7002
  "flex h-6 w-6 items-center justify-center rounded",
6286
- isDark ? "text-white/60 hover:bg-white/10 hover:text-white" : "text-[#616061] hover:bg-[#f3f3f3] hover:text-[#1d1c1d]"
7003
+ isDark ? "text-white/60" : "text-[#616061]"
6287
7004
  ),
6288
7005
  children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
6289
7006
  }
@@ -6295,30 +7012,23 @@ function ModalFrame({ isDark, children }) {
6295
7012
  /* @__PURE__ */ jsxs(
6296
7013
  "div",
6297
7014
  {
7015
+ "aria-hidden": "true",
6298
7016
  className: cn(
6299
7017
  "flex items-center justify-end gap-2 border-t px-5 py-3",
6300
7018
  isDark ? "border-[#2c2d30]" : "border-[#e8e8e8]"
6301
7019
  ),
6302
7020
  children: [
6303
7021
  /* @__PURE__ */ jsx(
6304
- "button",
7022
+ "span",
6305
7023
  {
6306
- type: "button",
6307
7024
  className: cn(
6308
- "cursor-pointer rounded-sm border px-3 py-1.5 text-sm font-medium",
6309
- isDark ? "border-white/20 bg-transparent text-white hover:bg-white/5" : "border-[#e8e8e8] bg-white text-[#1d1c1d] hover:bg-[#f3f3f3]"
7025
+ "rounded-sm border px-3 py-1.5 text-sm font-medium",
7026
+ isDark ? "border-white/20 bg-transparent text-white" : "border-[#e8e8e8] bg-white text-[#1d1c1d]"
6310
7027
  ),
6311
7028
  children: "Cancel"
6312
7029
  }
6313
7030
  ),
6314
- /* @__PURE__ */ jsx(
6315
- "button",
6316
- {
6317
- type: "button",
6318
- className: "cursor-pointer rounded-sm bg-[#007a5a] px-3 py-1.5 text-sm font-bold text-white hover:bg-[#148567]",
6319
- children: "Submit"
6320
- }
6321
- )
7031
+ /* @__PURE__ */ jsx("span", { className: "rounded-sm bg-[#007a5a] px-3 py-1.5 text-sm font-bold text-white", children: "Submit" })
6322
7032
  ]
6323
7033
  }
6324
7034
  )
@@ -6387,7 +7097,12 @@ function AppHomeFrame({
6387
7097
  }
6388
7098
  );
6389
7099
  }
6390
- function EmptyState({ isDark, isPaletteDrag, isOver }) {
7100
+ function EmptyState({
7101
+ isDark,
7102
+ isPaletteDrag,
7103
+ isOver,
7104
+ onOpenPalette
7105
+ }) {
6391
7106
  const active = isPaletteDrag && isOver;
6392
7107
  return /* @__PURE__ */ jsxs(
6393
7108
  "div",
@@ -6407,7 +7122,7 @@ function EmptyState({ isDark, isPaletteDrag, isOver }) {
6407
7122
  children: /* @__PURE__ */ jsx(LayoutGrid, { className: "h-6 w-6" })
6408
7123
  }
6409
7124
  ),
6410
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
7125
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
6411
7126
  /* @__PURE__ */ jsx(
6412
7127
  "p",
6413
7128
  {
@@ -6418,8 +7133,23 @@ function EmptyState({ isDark, isPaletteDrag, isOver }) {
6418
7133
  children: active ? "Drop to add block" : "Start adding blocks!"
6419
7134
  }
6420
7135
  ),
6421
- /* @__PURE__ */ jsx("p", { className: "text-xs", children: active ? "Release to insert it here." : "Drag a block from the left, or click one to add it here." })
6422
- ] })
7136
+ /* @__PURE__ */ jsx("p", { className: "text-xs", children: active ? "Release to insert it here." : /* @__PURE__ */ jsxs(Fragment, { children: [
7137
+ /* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: "Drag a block from the left, or click one to add it here." }),
7138
+ /* @__PURE__ */ jsx("span", { className: "md:hidden", children: "Tap \u201CAdd a block\u201D below to get started." })
7139
+ ] }) })
7140
+ ] }),
7141
+ !active && onOpenPalette ? /* @__PURE__ */ jsxs(
7142
+ "button",
7143
+ {
7144
+ type: "button",
7145
+ onClick: onOpenPalette,
7146
+ className: "inline-flex min-h-11 items-center gap-2 rounded-full bg-primary px-4 py-2 text-sm font-semibold text-primary-foreground shadow-sm transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring md:hidden",
7147
+ children: [
7148
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
7149
+ "Add a block"
7150
+ ]
7151
+ }
7152
+ ) : null
6423
7153
  ]
6424
7154
  }
6425
7155
  );
@@ -6443,6 +7173,7 @@ function Toolbar2({
6443
7173
  onOpenJson,
6444
7174
  onOpenIssues,
6445
7175
  onOpenSend,
7176
+ onOpenPalette,
6446
7177
  canSend,
6447
7178
  canClear,
6448
7179
  previewTheme,
@@ -6460,61 +7191,63 @@ function Toolbar2({
6460
7191
  const showSurfaceControl = surfaceOptions.length > 1;
6461
7192
  const docsHref = docsLink === false ? null : docsLink?.href ?? DEFAULT_DOCS_HREF;
6462
7193
  const docsLabel = docsLink === false ? null : docsLink?.label ?? DEFAULT_DOCS_LABEL;
6463
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 border-b bg-background px-3 py-2", children: [
6464
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6465
- showSurfaceControl ? /* @__PURE__ */ jsxs(Popover, { children: [
6466
- /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "ghost", size: "sm", children: [
7194
+ const [surfaceMenuOpen, setSurfaceMenuOpen] = useState(false);
7195
+ const [themeMenuOpen, setThemeMenuOpen] = useState(false);
7196
+ const [moreMenuOpen, setMoreMenuOpen] = useState(false);
7197
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-x-2 gap-y-1 border-b bg-background px-2 py-1.5 sm:px-3 sm:py-2", children: [
7198
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-1 sm:gap-2", children: [
7199
+ onOpenPalette ? /* @__PURE__ */ jsxs(
7200
+ Button,
7201
+ {
7202
+ type: "button",
7203
+ variant: "ghost",
7204
+ size: "sm",
7205
+ onClick: onOpenPalette,
7206
+ className: "md:hidden",
7207
+ "aria-label": "Add a block",
7208
+ children: [
7209
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
7210
+ /* @__PURE__ */ jsx("span", { children: "Blocks" })
7211
+ ]
7212
+ }
7213
+ ) : null,
7214
+ showSurfaceControl ? /* @__PURE__ */ jsxs(Popover, { open: surfaceMenuOpen, onOpenChange: setSurfaceMenuOpen, children: [
7215
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": `Preview surface: ${activeSurface.label}`, children: [
6467
7216
  /* @__PURE__ */ jsx(activeSurface.Icon, { className: "h-3.5 w-3.5" }),
6468
- activeSurface.label,
7217
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: activeSurface.label }),
6469
7218
  /* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5 opacity-60" })
6470
7219
  ] }) }),
6471
- /* @__PURE__ */ jsx(PopoverContent, { align: "start", className: "w-36 p-1", children: surfaceOptions.map(({ value, label, Icon }) => {
6472
- const isActive = value === previewSurface;
6473
- return /* @__PURE__ */ jsxs(
6474
- "button",
6475
- {
6476
- type: "button",
6477
- onClick: () => onPreviewSurfaceChange(value),
6478
- className: cn(
6479
- "flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-left text-sm hover:bg-accent hover:text-foreground",
6480
- isActive ? "text-foreground" : "text-muted-foreground"
6481
- ),
6482
- children: [
6483
- /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" }),
6484
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: label }),
6485
- isActive ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : null
6486
- ]
6487
- },
6488
- value
6489
- );
6490
- }) })
7220
+ /* @__PURE__ */ jsx(PopoverContent, { align: "start", className: "w-36 p-1", children: /* @__PURE__ */ jsx(
7221
+ Menu,
7222
+ {
7223
+ ariaLabel: "Preview surface",
7224
+ options: surfaceOptions,
7225
+ value: previewSurface,
7226
+ onChange: (next) => {
7227
+ onPreviewSurfaceChange(next);
7228
+ setSurfaceMenuOpen(false);
7229
+ }
7230
+ }
7231
+ ) })
6491
7232
  ] }) : null,
6492
- showThemeControl ? /* @__PURE__ */ jsxs(Popover, { children: [
6493
- /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "ghost", size: "sm", children: [
7233
+ showThemeControl ? /* @__PURE__ */ jsxs(Popover, { open: themeMenuOpen, onOpenChange: setThemeMenuOpen, children: [
7234
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": `Preview theme: ${activeTheme.label}`, children: [
6494
7235
  /* @__PURE__ */ jsx(activeTheme.Icon, { className: "h-3.5 w-3.5" }),
6495
- activeTheme.label,
7236
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: activeTheme.label }),
6496
7237
  /* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5 opacity-60" })
6497
7238
  ] }) }),
6498
- /* @__PURE__ */ jsx(PopoverContent, { align: "start", className: "w-32 p-1", children: THEME_OPTIONS.map(({ value, label, Icon }) => {
6499
- const isActive = value === previewTheme;
6500
- return /* @__PURE__ */ jsxs(
6501
- "button",
6502
- {
6503
- type: "button",
6504
- onClick: () => onPreviewThemeChange(value),
6505
- className: cn(
6506
- "flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-left text-sm hover:bg-accent hover:text-foreground",
6507
- isActive ? "text-foreground" : "text-muted-foreground"
6508
- ),
6509
- children: [
6510
- /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" }),
6511
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: label }),
6512
- isActive ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : null
6513
- ]
6514
- },
6515
- value
6516
- );
6517
- }) })
7239
+ /* @__PURE__ */ jsx(PopoverContent, { align: "start", className: "w-32 p-1", children: /* @__PURE__ */ jsx(
7240
+ Menu,
7241
+ {
7242
+ ariaLabel: "Preview theme",
7243
+ options: THEME_OPTIONS,
7244
+ value: previewTheme,
7245
+ onChange: (next) => {
7246
+ onPreviewThemeChange(next);
7247
+ setThemeMenuOpen(false);
7248
+ }
7249
+ }
7250
+ ) })
6518
7251
  ] }) : null,
6519
7252
  docsHref ? /* @__PURE__ */ jsxs(
6520
7253
  "a",
@@ -6522,7 +7255,8 @@ function Toolbar2({
6522
7255
  href: docsHref,
6523
7256
  target: "_blank",
6524
7257
  rel: "noreferrer noopener",
6525
- className: "inline-flex h-8 items-center gap-1.5 rounded-md px-2 py-1 text-sm text-muted-foreground no-underline transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
7258
+ className: "hidden h-8 items-center gap-1.5 rounded-md px-2 py-1 text-sm text-muted-foreground no-underline transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:inline-flex",
7259
+ "aria-label": `${docsLabel} (opens in a new tab)`,
6526
7260
  children: [
6527
7261
  /* @__PURE__ */ jsx(BookOpen, { className: "h-3.5 w-3.5" }),
6528
7262
  docsLabel,
@@ -6531,7 +7265,7 @@ function Toolbar2({
6531
7265
  }
6532
7266
  ) : null
6533
7267
  ] }),
6534
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
7268
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 sm:gap-2", children: [
6535
7269
  errorCount > 0 ? /* @__PURE__ */ jsxs(
6536
7270
  Button,
6537
7271
  {
@@ -6540,11 +7274,14 @@ function Toolbar2({
6540
7274
  size: "sm",
6541
7275
  onClick: onOpenIssues,
6542
7276
  className: "text-destructive hover:text-destructive",
7277
+ "aria-label": `${errorCount} ${errorCount === 1 ? "issue" : "issues"}`,
6543
7278
  children: [
6544
7279
  /* @__PURE__ */ jsx(AlertTriangle, { className: "h-3.5 w-3.5" }),
6545
- errorCount,
6546
- " ",
6547
- errorCount === 1 ? "issue" : "issues"
7280
+ /* @__PURE__ */ jsxs("span", { children: [
7281
+ errorCount,
7282
+ " ",
7283
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: errorCount === 1 ? "issue" : "issues" })
7284
+ ] })
6548
7285
  ]
6549
7286
  }
6550
7287
  ) : null,
@@ -6556,24 +7293,188 @@ function Toolbar2({
6556
7293
  size: "sm",
6557
7294
  onClick: onClear,
6558
7295
  disabled: !canClear,
6559
- className: "hover:bg-destructive/10 hover:text-destructive",
7296
+ className: "hidden hover:bg-destructive/10 hover:text-destructive sm:inline-flex",
7297
+ "aria-label": "Clear all blocks",
6560
7298
  children: [
6561
7299
  /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" }),
6562
7300
  "Clear"
6563
7301
  ]
6564
7302
  }
6565
7303
  ),
6566
- /* @__PURE__ */ jsxs(Button, { type: "button", variant: "ghost", size: "sm", onClick: onOpenJson, children: [
6567
- /* @__PURE__ */ jsx(Code2, { className: "h-3.5 w-3.5" }),
6568
- "View JSON"
7304
+ /* @__PURE__ */ jsxs(
7305
+ Button,
7306
+ {
7307
+ type: "button",
7308
+ variant: "ghost",
7309
+ size: "sm",
7310
+ onClick: onOpenJson,
7311
+ "aria-label": "View JSON",
7312
+ className: "hidden sm:inline-flex",
7313
+ children: [
7314
+ /* @__PURE__ */ jsx(Code2, { className: "h-3.5 w-3.5" }),
7315
+ "View JSON"
7316
+ ]
7317
+ }
7318
+ ),
7319
+ /* @__PURE__ */ jsxs(Popover, { open: moreMenuOpen, onOpenChange: setMoreMenuOpen, children: [
7320
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
7321
+ Button,
7322
+ {
7323
+ type: "button",
7324
+ variant: "ghost",
7325
+ size: "sm",
7326
+ "aria-label": "More actions",
7327
+ "aria-haspopup": "menu",
7328
+ className: "px-2 sm:hidden",
7329
+ children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "h-3.5 w-3.5" })
7330
+ }
7331
+ ) }),
7332
+ /* @__PURE__ */ jsx(PopoverContent, { align: "end", className: "w-44 p-1", children: /* @__PURE__ */ jsxs("div", { role: "menu", "aria-label": "More actions", className: "flex flex-col", children: [
7333
+ /* @__PURE__ */ jsx(
7334
+ ActionMenuItem,
7335
+ {
7336
+ icon: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" }),
7337
+ onSelect: () => {
7338
+ setMoreMenuOpen(false);
7339
+ onClear();
7340
+ },
7341
+ disabled: !canClear,
7342
+ tone: "destructive",
7343
+ children: "Clear"
7344
+ }
7345
+ ),
7346
+ /* @__PURE__ */ jsx(
7347
+ ActionMenuItem,
7348
+ {
7349
+ icon: /* @__PURE__ */ jsx(Code2, { className: "h-3.5 w-3.5" }),
7350
+ onSelect: () => {
7351
+ setMoreMenuOpen(false);
7352
+ onOpenJson();
7353
+ },
7354
+ children: "View JSON"
7355
+ }
7356
+ ),
7357
+ docsHref ? /* @__PURE__ */ jsx(
7358
+ ActionMenuLink,
7359
+ {
7360
+ href: docsHref,
7361
+ icon: /* @__PURE__ */ jsx(BookOpen, { className: "h-3.5 w-3.5" }),
7362
+ trailingIcon: /* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3 opacity-50" }),
7363
+ onSelect: () => setMoreMenuOpen(false),
7364
+ children: docsLabel
7365
+ }
7366
+ ) : null
7367
+ ] }) })
6569
7368
  ] }),
6570
- /* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: onOpenSend, disabled: !canSend, children: [
7369
+ /* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: onOpenSend, disabled: !canSend, "aria-label": "Send", children: [
6571
7370
  /* @__PURE__ */ jsx(Send, { className: "h-3.5 w-3.5" }),
6572
- "Send"
7371
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Send" })
6573
7372
  ] })
6574
7373
  ] })
6575
7374
  ] });
6576
7375
  }
7376
+ function Menu({
7377
+ ariaLabel,
7378
+ options,
7379
+ value,
7380
+ onChange
7381
+ }) {
7382
+ const itemsRef = useRef([]);
7383
+ const moveFocus = (from, delta) => {
7384
+ const len = options.length;
7385
+ if (len === 0) return;
7386
+ const next = (from + delta + len) % len;
7387
+ itemsRef.current[next]?.focus();
7388
+ };
7389
+ const handleKeyDown = (e, idx) => {
7390
+ if (e.key === "ArrowDown") {
7391
+ e.preventDefault();
7392
+ moveFocus(idx, 1);
7393
+ } else if (e.key === "ArrowUp") {
7394
+ e.preventDefault();
7395
+ moveFocus(idx, -1);
7396
+ } else if (e.key === "Home") {
7397
+ e.preventDefault();
7398
+ itemsRef.current[0]?.focus();
7399
+ } else if (e.key === "End") {
7400
+ e.preventDefault();
7401
+ itemsRef.current[options.length - 1]?.focus();
7402
+ }
7403
+ };
7404
+ return /* @__PURE__ */ jsx("div", { role: "menu", "aria-label": ariaLabel, className: "flex flex-col", children: options.map(({ value: optValue, label, Icon }, idx) => {
7405
+ const isActive = optValue === value;
7406
+ return /* @__PURE__ */ jsxs(
7407
+ "button",
7408
+ {
7409
+ ref: (el) => {
7410
+ itemsRef.current[idx] = el;
7411
+ },
7412
+ type: "button",
7413
+ role: "menuitemradio",
7414
+ "aria-checked": isActive,
7415
+ onClick: () => onChange(optValue),
7416
+ onKeyDown: (e) => handleKeyDown(e, idx),
7417
+ className: cn(
7418
+ "flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-left text-sm hover:bg-accent hover:text-foreground focus-visible:bg-accent focus-visible:text-foreground focus-visible:outline-none",
7419
+ isActive ? "text-foreground" : "text-muted-foreground"
7420
+ ),
7421
+ children: [
7422
+ /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" }),
7423
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: label }),
7424
+ isActive ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : null
7425
+ ]
7426
+ },
7427
+ optValue
7428
+ );
7429
+ }) });
7430
+ }
7431
+ var ACTION_ITEM_BASE = "flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-left text-sm text-muted-foreground no-underline transition-colors hover:bg-accent hover:text-foreground focus-visible:bg-accent focus-visible:text-foreground focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50";
7432
+ function ActionMenuItem({
7433
+ icon,
7434
+ children,
7435
+ onSelect,
7436
+ disabled,
7437
+ tone
7438
+ }) {
7439
+ return /* @__PURE__ */ jsxs(
7440
+ "button",
7441
+ {
7442
+ type: "button",
7443
+ role: "menuitem",
7444
+ onClick: onSelect,
7445
+ disabled,
7446
+ className: cn(ACTION_ITEM_BASE, tone === "destructive" && "hover:bg-destructive/10 hover:text-destructive"),
7447
+ children: [
7448
+ icon,
7449
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children })
7450
+ ]
7451
+ }
7452
+ );
7453
+ }
7454
+ function ActionMenuLink({
7455
+ href,
7456
+ icon,
7457
+ trailingIcon,
7458
+ children,
7459
+ onSelect
7460
+ }) {
7461
+ return /* @__PURE__ */ jsxs(
7462
+ "a",
7463
+ {
7464
+ role: "menuitem",
7465
+ href,
7466
+ target: "_blank",
7467
+ rel: "noreferrer noopener",
7468
+ onClick: onSelect,
7469
+ className: ACTION_ITEM_BASE,
7470
+ children: [
7471
+ icon,
7472
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children }),
7473
+ trailingIcon
7474
+ ]
7475
+ }
7476
+ );
7477
+ }
6577
7478
  function BlockKitchen(props) {
6578
7479
  const {
6579
7480
  workspaceName,
@@ -6584,6 +7485,7 @@ function BlockKitchen(props) {
6584
7485
  loadSendAsUserStatus,
6585
7486
  onSend,
6586
7487
  palette,
7488
+ disabledBlockTypes,
6587
7489
  showPaletteSearch,
6588
7490
  paletteSearchPlaceholder,
6589
7491
  defaultOpenSections,
@@ -6593,7 +7495,21 @@ function BlockKitchen(props) {
6593
7495
  defaultPreviewTheme = "light",
6594
7496
  theme
6595
7497
  } = props;
6596
- const paletteSections = palette ?? defaultPalette;
7498
+ const paletteSections = useMemo(() => {
7499
+ const sections = palette ?? defaultPalette;
7500
+ if (!disabledBlockTypes || disabledBlockTypes.length === 0) {
7501
+ return sections;
7502
+ }
7503
+ const blocked = new Set(disabledBlockTypes);
7504
+ const filtered = [];
7505
+ for (const section of sections) {
7506
+ const variants = section.variants.filter((variant) => !blocked.has(variant.factory().type));
7507
+ if (variants.length > 0) {
7508
+ filtered.push({ ...section, variants });
7509
+ }
7510
+ }
7511
+ return filtered;
7512
+ }, [palette, disabledBlockTypes]);
6597
7513
  const variantById = useMemo(() => buildVariantById(paletteSections), [paletteSections]);
6598
7514
  const allowedSurfaces = allowedSurfacesProp && allowedSurfacesProp.length > 0 ? allowedSurfacesProp : ["message"];
6599
7515
  const { blocks, addBlock, updateBlock, removeBlock, duplicateBlock, reorderBlock, replaceAll } = useBlockKitchenState(
@@ -6602,12 +7518,18 @@ function BlockKitchen(props) {
6602
7518
  const [jsonOpen, setJsonOpen] = useState(false);
6603
7519
  const [sendOpen, setSendOpen] = useState(false);
6604
7520
  const [issuesOpen, setIssuesOpen] = useState(false);
7521
+ const [paletteOpen, setPaletteOpen] = useState(false);
6605
7522
  const [openBlockId, setOpenBlockId] = useState(null);
6606
7523
  const [previewTheme, setPreviewTheme] = useState(defaultPreviewTheme);
6607
7524
  const [previewSurface, setPreviewSurface] = useState(allowedSurfaces[0]);
6608
7525
  const [activePaletteVariantId, setActivePaletteVariantId] = useState(null);
7526
+ const isMobile = useIsMobile();
6609
7527
  const validation = useBlockKitValidation(blocks, "message");
6610
- const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 4 } }));
7528
+ const sensors = useSensors(
7529
+ useSensor(PointerSensor, { activationConstraint: { distance: 4 } }),
7530
+ useSensor(TouchSensor, { activationConstraint: { delay: 150, tolerance: 8 } }),
7531
+ useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
7532
+ );
6611
7533
  const collisionDetection = useCallback((args) => {
6612
7534
  const pointerHits = pointerWithin(args);
6613
7535
  if (pointerHits.length > 0) {
@@ -6660,7 +7582,7 @@ function BlockKitchen(props) {
6660
7582
  onDragEnd: handleDragEnd,
6661
7583
  onDragCancel: handleDragCancel,
6662
7584
  children: [
6663
- /* @__PURE__ */ jsxs("div", { className: "bk-root flex h-full w-full flex-col rounded-md border bg-background text-foreground", children: [
7585
+ /* @__PURE__ */ jsxs("div", { className: "bk-root flex h-full w-full flex-col overflow-hidden rounded-md border bg-background text-foreground", children: [
6664
7586
  /* @__PURE__ */ jsx(
6665
7587
  Toolbar2,
6666
7588
  {
@@ -6668,6 +7590,7 @@ function BlockKitchen(props) {
6668
7590
  onOpenJson: () => setJsonOpen(true),
6669
7591
  onOpenIssues: () => setIssuesOpen(true),
6670
7592
  onOpenSend: () => setSendOpen(true),
7593
+ onOpenPalette: () => setPaletteOpen(true),
6671
7594
  canSend: blocks.length > 0,
6672
7595
  canClear: blocks.length > 0,
6673
7596
  errorCount: validation.total,
@@ -6681,7 +7604,7 @@ function BlockKitchen(props) {
6681
7604
  }
6682
7605
  ),
6683
7606
  /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 items-stretch", children: [
6684
- /* @__PURE__ */ jsx(
7607
+ /* @__PURE__ */ jsx("div", { className: "hidden min-h-0 md:flex", children: /* @__PURE__ */ jsx(
6685
7608
  Palette,
6686
7609
  {
6687
7610
  onAddBlock: (block) => addBlock(block),
@@ -6690,7 +7613,7 @@ function BlockKitchen(props) {
6690
7613
  searchPlaceholder: paletteSearchPlaceholder,
6691
7614
  defaultOpenSections
6692
7615
  }
6693
- ),
7616
+ ) }),
6694
7617
  /* @__PURE__ */ jsx(
6695
7618
  Surface,
6696
7619
  {
@@ -6705,7 +7628,9 @@ function BlockKitchen(props) {
6705
7628
  onUpdate: updateBlock,
6706
7629
  onDuplicate: duplicateBlock,
6707
7630
  onDelete: removeBlock,
6708
- isPaletteDrag: activePaletteVariant !== null
7631
+ onReorder: reorderBlock,
7632
+ isPaletteDrag: activePaletteVariant !== null,
7633
+ onOpenPalette: () => setPaletteOpen(true)
6709
7634
  }
6710
7635
  )
6711
7636
  ] })
@@ -6714,6 +7639,33 @@ function BlockKitchen(props) {
6714
7639
  /* @__PURE__ */ jsx(GripVertical, { className: "h-3 w-3 shrink-0" }),
6715
7640
  /* @__PURE__ */ jsx("span", { className: "truncate", children: activePaletteVariant.label })
6716
7641
  ] }) : null }),
7642
+ /* @__PURE__ */ jsx(Sheet, { open: paletteOpen && isMobile, onOpenChange: setPaletteOpen, children: /* @__PURE__ */ jsxs(
7643
+ SheetContent,
7644
+ {
7645
+ side: "bottom",
7646
+ className: "bk-portal-content flex h-[85svh] max-h-[85svh] flex-col gap-3 p-0 sm:max-w-none",
7647
+ children: [
7648
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 px-4 pt-5", children: [
7649
+ /* @__PURE__ */ jsx(SheetTitle, { children: "Add a block" }),
7650
+ /* @__PURE__ */ jsx(SheetDescription, { children: "Tap a block to add it to the bottom of your draft." })
7651
+ ] }),
7652
+ /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ jsx(
7653
+ Palette,
7654
+ {
7655
+ onAddBlock: (block) => {
7656
+ addBlock(block);
7657
+ setPaletteOpen(false);
7658
+ },
7659
+ sections: paletteSections,
7660
+ showSearch: showPaletteSearch,
7661
+ searchPlaceholder: paletteSearchPlaceholder,
7662
+ defaultOpenSections,
7663
+ variant: "sheet"
7664
+ }
7665
+ ) })
7666
+ ]
7667
+ }
7668
+ ) }),
6717
7669
  /* @__PURE__ */ jsx(JsonDrawer, { open: jsonOpen, onOpenChange: setJsonOpen, blocks: blockPayloads, onApply: replaceAll }),
6718
7670
  /* @__PURE__ */ jsx(
6719
7671
  SendDialog,
@@ -6846,11 +7798,11 @@ function TemplatePicker({
6846
7798
  }) {
6847
7799
  const visible = surface ? templates.filter((t) => t.surface === surface) : templates;
6848
7800
  const { grouped, sections } = groupByCategory(visible);
6849
- return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full w-full flex-col gap-8 overflow-y-auto bg-muted/30 p-8", className), children: [
6850
- heading ? /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold tracking-tight text-foreground", children: heading }) : null,
6851
- visible.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground/75", children: emptyLabel }) : sections.map((section) => /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-4", children: [
7801
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full w-full flex-col gap-6 overflow-y-auto bg-muted/30 p-4 sm:gap-8 sm:p-8", className), children: [
7802
+ heading ? /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold tracking-tight text-foreground sm:text-xl", children: heading }) : null,
7803
+ visible.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground/75", children: emptyLabel }) : sections.map((section) => /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-3 sm:gap-4", children: [
6852
7804
  grouped ? /* @__PURE__ */ jsx("h3", { className: "text-xs font-semibold tracking-wider text-foreground/60 uppercase", children: section.category }) : null,
6853
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-[repeat(auto-fill,minmax(280px,1fr))] gap-5", children: section.templates.map((template) => /* @__PURE__ */ jsx(TemplateCard, { template, theme, onSelect }, template.id)) })
7805
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-[repeat(auto-fill,minmax(240px,1fr))] gap-4 sm:grid-cols-[repeat(auto-fill,minmax(280px,1fr))] sm:gap-5", children: section.templates.map((template) => /* @__PURE__ */ jsx(TemplateCard, { template, theme, onSelect }, template.id)) })
6854
7806
  ] }, section.category))
6855
7807
  ] });
6856
7808
  }