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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,19 +1,19 @@
1
1
  'use strict';
2
2
 
3
3
  var core = require('@dnd-kit/core');
4
+ var sortable = require('@dnd-kit/sortable');
4
5
  var lucideReact = require('lucide-react');
5
- var React2 = require('react');
6
- var TooltipPrimitive = require('@radix-ui/react-tooltip');
6
+ var React = require('react');
7
+ var DialogPrimitive = require('@radix-ui/react-dialog');
7
8
  var clsx = require('clsx');
8
9
  var tailwindMerge = require('tailwind-merge');
9
10
  var jsxRuntime = require('react/jsx-runtime');
11
+ var TooltipPrimitive = require('@radix-ui/react-tooltip');
10
12
  var slackBlockKitValidator = require('@tightknitai/slack-block-kit-validator');
11
13
  var nanoid = require('nanoid');
12
- var DialogPrimitive = require('@radix-ui/react-dialog');
13
14
  var reactSlot = require('@radix-ui/react-slot');
14
15
  var classVarianceAuthority = require('class-variance-authority');
15
16
  var LabelPrimitive = require('@radix-ui/react-label');
16
- var sortable = require('@dnd-kit/sortable');
17
17
  var utilities = require('@dnd-kit/utilities');
18
18
  var PopoverPrimitive = require('@radix-ui/react-popover');
19
19
  var RadioGroupPrimitive = require('@radix-ui/react-radio-group');
@@ -43,9 +43,9 @@ function _interopNamespace(e) {
43
43
  return Object.freeze(n);
44
44
  }
45
45
 
46
- var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
47
- var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
46
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
48
47
  var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
48
+ var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
49
49
  var LabelPrimitive__namespace = /*#__PURE__*/_interopNamespace(LabelPrimitive);
50
50
  var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitive);
51
51
  var RadioGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(RadioGroupPrimitive);
@@ -105,6 +105,66 @@ var defaultPalette = [
105
105
  }
106
106
  ]
107
107
  })
108
+ },
109
+ {
110
+ id: "agents_plan",
111
+ label: "Plan",
112
+ factory: () => ({
113
+ type: "plan",
114
+ title: "Investigating the issue",
115
+ tasks: [
116
+ {
117
+ type: "task_card",
118
+ task_id: "task_1",
119
+ title: "Read the bug report",
120
+ status: "complete"
121
+ },
122
+ {
123
+ type: "task_card",
124
+ task_id: "task_2",
125
+ title: "Reproduce the error locally",
126
+ status: "in_progress"
127
+ },
128
+ {
129
+ type: "task_card",
130
+ task_id: "task_3",
131
+ title: "Identify the root cause",
132
+ status: "pending"
133
+ }
134
+ ]
135
+ })
136
+ },
137
+ {
138
+ id: "agents_task_card",
139
+ label: "Task card",
140
+ factory: () => ({
141
+ type: "task_card",
142
+ task_id: "task_1",
143
+ title: "Summarize the latest release notes",
144
+ status: "in_progress"
145
+ })
146
+ },
147
+ {
148
+ id: "agents_task_card_with_sources",
149
+ label: "Task card with sources",
150
+ factory: () => ({
151
+ type: "task_card",
152
+ task_id: "task_2",
153
+ title: "Cite supporting docs",
154
+ status: "complete",
155
+ sources: [
156
+ {
157
+ type: "url",
158
+ url: "https://example.com/runbook",
159
+ text: "Runbook"
160
+ },
161
+ {
162
+ type: "url",
163
+ url: "https://example.com/changelog",
164
+ text: "Changelog"
165
+ }
166
+ ]
167
+ })
108
168
  }
109
169
  ]
110
170
  },
@@ -660,6 +720,71 @@ var defaultPalette = [
660
720
  }
661
721
  ]
662
722
  },
723
+ {
724
+ name: "Alert",
725
+ icon: lucideReact.Bell,
726
+ variants: [
727
+ {
728
+ id: "alert_default",
729
+ label: "Default",
730
+ factory: () => ({
731
+ type: "alert",
732
+ text: {
733
+ type: "mrkdwn",
734
+ text: "A neutral alert message."
735
+ }
736
+ })
737
+ },
738
+ {
739
+ id: "alert_info",
740
+ label: "Info",
741
+ factory: () => ({
742
+ type: "alert",
743
+ level: "info",
744
+ text: {
745
+ type: "mrkdwn",
746
+ text: "FYI: the build finished in 42 seconds."
747
+ }
748
+ })
749
+ },
750
+ {
751
+ id: "alert_warning",
752
+ label: "Warning",
753
+ factory: () => ({
754
+ type: "alert",
755
+ level: "warning",
756
+ text: {
757
+ type: "mrkdwn",
758
+ text: "Heads up: this action cannot be undone."
759
+ }
760
+ })
761
+ },
762
+ {
763
+ id: "alert_error",
764
+ label: "Error",
765
+ factory: () => ({
766
+ type: "alert",
767
+ level: "error",
768
+ text: {
769
+ type: "mrkdwn",
770
+ text: "Something went wrong. Please try again."
771
+ }
772
+ })
773
+ },
774
+ {
775
+ id: "alert_success",
776
+ label: "Success",
777
+ factory: () => ({
778
+ type: "alert",
779
+ level: "success",
780
+ text: {
781
+ type: "mrkdwn",
782
+ text: "Your changes have been saved."
783
+ }
784
+ })
785
+ }
786
+ ]
787
+ },
663
788
  {
664
789
  name: "Rich Text",
665
790
  icon: lucideReact.Pilcrow,
@@ -710,6 +835,43 @@ var defaultPalette = [
710
835
  }
711
836
  ]
712
837
  },
838
+ {
839
+ name: "Video",
840
+ icon: lucideReact.Video,
841
+ variants: [
842
+ {
843
+ id: "video_basic",
844
+ label: "Basic",
845
+ factory: () => ({
846
+ type: "video",
847
+ alt_text: "A short demo video",
848
+ title: { type: "plain_text", text: "Product demo", emoji: true },
849
+ thumbnail_url: "https://placehold.co/600x340?text=Video",
850
+ video_url: "https://www.youtube.com/embed/dQw4w9WgXcQ"
851
+ })
852
+ },
853
+ {
854
+ id: "video_with_metadata",
855
+ label: "With metadata",
856
+ factory: () => ({
857
+ type: "video",
858
+ alt_text: "A short demo video",
859
+ title: { type: "plain_text", text: "Product demo", emoji: true },
860
+ title_url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
861
+ thumbnail_url: "https://placehold.co/600x340?text=Video",
862
+ video_url: "https://www.youtube.com/embed/dQw4w9WgXcQ",
863
+ author_name: "Acme",
864
+ description: {
865
+ type: "plain_text",
866
+ text: "A short walkthrough of the new release.",
867
+ emoji: true
868
+ },
869
+ provider_name: "YouTube",
870
+ provider_icon_url: "https://placehold.co/16x16?text=YT"
871
+ })
872
+ }
873
+ ]
874
+ },
713
875
  {
714
876
  name: "Card and Carousel",
715
877
  icon: lucideReact.GalleryHorizontal,
@@ -1295,15 +1457,69 @@ function labelForBlockType(type) {
1295
1457
  return "Context Actions";
1296
1458
  case "input":
1297
1459
  return "Input";
1460
+ case "video":
1461
+ return "Video";
1462
+ case "plan":
1463
+ return "Plan";
1464
+ case "task_card":
1465
+ return "Task Card";
1298
1466
  }
1299
1467
  }
1300
1468
  function cn(...inputs) {
1301
1469
  return tailwindMerge.twMerge(clsx.clsx(inputs));
1302
1470
  }
1471
+ var Sheet = DialogPrimitive__namespace.Root;
1472
+ var SheetOverlay = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1473
+ DialogPrimitive__namespace.Overlay,
1474
+ {
1475
+ ref,
1476
+ className: cn(
1477
+ "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",
1478
+ className
1479
+ ),
1480
+ ...props
1481
+ }
1482
+ ));
1483
+ SheetOverlay.displayName = DialogPrimitive__namespace.Overlay.displayName;
1484
+ var SHEET_SIDE_CLASSES = {
1485
+ 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",
1486
+ 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",
1487
+ top: "inset-x-0 top-0 w-full border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
1488
+ 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"
1489
+ };
1490
+ var SheetContent = React__namespace.forwardRef(
1491
+ ({ className, children, side = "right", hideClose = false, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(DialogPrimitive__namespace.Portal, { children: [
1492
+ /* @__PURE__ */ jsxRuntime.jsx(SheetOverlay, {}),
1493
+ /* @__PURE__ */ jsxRuntime.jsxs(
1494
+ DialogPrimitive__namespace.Content,
1495
+ {
1496
+ ref,
1497
+ className: cn(
1498
+ "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",
1499
+ SHEET_SIDE_CLASSES[side],
1500
+ className
1501
+ ),
1502
+ ...props,
1503
+ children: [
1504
+ children,
1505
+ hideClose ? null : /* @__PURE__ */ jsxRuntime.jsxs(DialogPrimitive__namespace.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none", children: [
1506
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }),
1507
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
1508
+ ] })
1509
+ ]
1510
+ }
1511
+ )
1512
+ ] })
1513
+ );
1514
+ SheetContent.displayName = DialogPrimitive__namespace.Content.displayName;
1515
+ var SheetTitle = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Title, { ref, className: cn("text-lg font-semibold text-foreground", className), ...props }));
1516
+ SheetTitle.displayName = DialogPrimitive__namespace.Title.displayName;
1517
+ var SheetDescription = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
1518
+ SheetDescription.displayName = DialogPrimitive__namespace.Description.displayName;
1303
1519
  var TooltipProvider = TooltipPrimitive__namespace.Provider;
1304
1520
  var Tooltip = TooltipPrimitive__namespace.Root;
1305
1521
  var TooltipTrigger = TooltipPrimitive__namespace.Trigger;
1306
- var TooltipContent = React2__namespace.forwardRef(({ className, sideOffset = 6, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(TooltipPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
1522
+ var TooltipContent = React__namespace.forwardRef(({ className, sideOffset = 6, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(TooltipPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
1307
1523
  TooltipPrimitive__namespace.Content,
1308
1524
  {
1309
1525
  ref,
@@ -1317,6 +1533,22 @@ var TooltipContent = React2__namespace.forwardRef(({ className, sideOffset = 6,
1317
1533
  }
1318
1534
  ) }));
1319
1535
  TooltipContent.displayName = TooltipPrimitive__namespace.Content.displayName;
1536
+ var MOBILE_BREAKPOINT_PX = 768;
1537
+ function useIsMobile() {
1538
+ const [isMobile, setIsMobile] = React.useState(() => {
1539
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
1540
+ return window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT_PX - 1}px)`).matches;
1541
+ });
1542
+ React.useEffect(() => {
1543
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1544
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT_PX - 1}px)`);
1545
+ const onChange = (e) => setIsMobile(e.matches);
1546
+ setIsMobile(mql.matches);
1547
+ mql.addEventListener("change", onChange);
1548
+ return () => mql.removeEventListener("change", onChange);
1549
+ }, []);
1550
+ return isMobile;
1551
+ }
1320
1552
 
1321
1553
  // src/lib/error-grouping.ts
1322
1554
  function toValidatorSurface(surface) {
@@ -1497,9 +1729,9 @@ function computeValidation(blocks, surface) {
1497
1729
  };
1498
1730
  }
1499
1731
  function useBlockKitValidation(blocks, surface) {
1500
- const [state, setState] = React2.useState(() => computeValidation(blocks, surface));
1501
- const isFirstRunRef = React2.useRef(true);
1502
- React2.useEffect(() => {
1732
+ const [state, setState] = React.useState(() => computeValidation(blocks, surface));
1733
+ const isFirstRunRef = React.useRef(true);
1734
+ React.useEffect(() => {
1503
1735
  if (isFirstRunRef.current) {
1504
1736
  isFirstRunRef.current = false;
1505
1737
  return;
@@ -1518,20 +1750,20 @@ function useBlockKitchenState({
1518
1750
  initialBlocks,
1519
1751
  onChange
1520
1752
  } = {}) {
1521
- const [blocks, setBlocks] = React2.useState(() => (initialBlocks ?? []).map(wrap));
1522
- const onChangeRef = React2.useRef(onChange);
1523
- React2.useEffect(() => {
1753
+ const [blocks, setBlocks] = React.useState(() => (initialBlocks ?? []).map(wrap));
1754
+ const onChangeRef = React.useRef(onChange);
1755
+ React.useEffect(() => {
1524
1756
  onChangeRef.current = onChange;
1525
1757
  }, [onChange]);
1526
- const isFirstRunRef = React2.useRef(true);
1527
- React2.useEffect(() => {
1758
+ const isFirstRunRef = React.useRef(true);
1759
+ React.useEffect(() => {
1528
1760
  if (isFirstRunRef.current) {
1529
1761
  isFirstRunRef.current = false;
1530
1762
  return;
1531
1763
  }
1532
1764
  onChangeRef.current?.(blocks.map((b) => b.block));
1533
1765
  }, [blocks]);
1534
- const addBlock = React2.useCallback((block, atIndex) => {
1766
+ const addBlock = React.useCallback((block, atIndex) => {
1535
1767
  setBlocks((prev) => {
1536
1768
  const next = [...prev];
1537
1769
  const inserted = wrap(block);
@@ -1540,13 +1772,13 @@ function useBlockKitchenState({
1540
1772
  return next;
1541
1773
  });
1542
1774
  }, []);
1543
- const updateBlock = React2.useCallback((id, block) => {
1775
+ const updateBlock = React.useCallback((id, block) => {
1544
1776
  setBlocks((prev) => prev.map((b) => b.id === id ? { ...b, block } : b));
1545
1777
  }, []);
1546
- const removeBlock = React2.useCallback((id) => {
1778
+ const removeBlock = React.useCallback((id) => {
1547
1779
  setBlocks((prev) => prev.filter((b) => b.id !== id));
1548
1780
  }, []);
1549
- const duplicateBlock = React2.useCallback((id) => {
1781
+ const duplicateBlock = React.useCallback((id) => {
1550
1782
  setBlocks((prev) => {
1551
1783
  const idx = prev.findIndex((b) => b.id === id);
1552
1784
  if (idx === -1) {
@@ -1558,7 +1790,7 @@ function useBlockKitchenState({
1558
1790
  return next;
1559
1791
  });
1560
1792
  }, []);
1561
- const reorderBlock = React2.useCallback((fromId, toIndex) => {
1793
+ const reorderBlock = React.useCallback((fromId, toIndex) => {
1562
1794
  setBlocks((prev) => {
1563
1795
  const fromIndex = prev.findIndex((b) => b.id === fromId);
1564
1796
  if (fromIndex === -1) {
@@ -1571,7 +1803,7 @@ function useBlockKitchenState({
1571
1803
  return next;
1572
1804
  });
1573
1805
  }, []);
1574
- const replaceAll = React2.useCallback((newBlocks) => {
1806
+ const replaceAll = React.useCallback((newBlocks) => {
1575
1807
  setBlocks(newBlocks.map(wrap));
1576
1808
  }, []);
1577
1809
  return {
@@ -1877,9 +2109,9 @@ function toCssDeclarations(vars) {
1877
2109
  return entries.map(([name, value]) => `${name}: ${value};`).join(" ");
1878
2110
  }
1879
2111
  function BrandThemeScope({ theme, children }) {
1880
- const rawId = React2.useId();
1881
- const scopeId = React2.useMemo(() => `bk-${rawId.replace(/[:]/g, "")}`, [rawId]);
1882
- const resolved = React2.useMemo(() => resolveBrandTheme(theme), [theme]);
2112
+ const rawId = React.useId();
2113
+ const scopeId = React.useMemo(() => `bk-${rawId.replace(/[:]/g, "")}`, [rawId]);
2114
+ const resolved = React.useMemo(() => resolveBrandTheme(theme), [theme]);
1883
2115
  const hasLight = Object.keys(resolved.light).length > 0;
1884
2116
  const hasDark = Object.keys(resolved.dark).length > 0;
1885
2117
  if (!hasLight && !hasDark) {
@@ -1900,45 +2132,6 @@ function BrandThemeScope({ theme, children }) {
1900
2132
  /* @__PURE__ */ jsxRuntime.jsx("div", { "data-bk-scope": scopeId, style: { display: "contents" }, children })
1901
2133
  ] });
1902
2134
  }
1903
- var Sheet = DialogPrimitive__namespace.Root;
1904
- var SheetOverlay = React2__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1905
- DialogPrimitive__namespace.Overlay,
1906
- {
1907
- ref,
1908
- className: cn(
1909
- "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",
1910
- className
1911
- ),
1912
- ...props
1913
- }
1914
- ));
1915
- SheetOverlay.displayName = DialogPrimitive__namespace.Overlay.displayName;
1916
- var SheetContent = React2__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(DialogPrimitive__namespace.Portal, { children: [
1917
- /* @__PURE__ */ jsxRuntime.jsx(SheetOverlay, {}),
1918
- /* @__PURE__ */ jsxRuntime.jsxs(
1919
- DialogPrimitive__namespace.Content,
1920
- {
1921
- ref,
1922
- className: cn(
1923
- "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",
1924
- className
1925
- ),
1926
- ...props,
1927
- children: [
1928
- children,
1929
- /* @__PURE__ */ jsxRuntime.jsxs(DialogPrimitive__namespace.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none", children: [
1930
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }),
1931
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
1932
- ] })
1933
- ]
1934
- }
1935
- )
1936
- ] }));
1937
- SheetContent.displayName = DialogPrimitive__namespace.Content.displayName;
1938
- var SheetTitle = React2__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Title, { ref, className: cn("text-lg font-semibold text-foreground", className), ...props }));
1939
- SheetTitle.displayName = DialogPrimitive__namespace.Title.displayName;
1940
- var SheetDescription = React2__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
1941
- SheetDescription.displayName = DialogPrimitive__namespace.Description.displayName;
1942
2135
  function IssuesSheet({
1943
2136
  open,
1944
2137
  onOpenChange,
@@ -1953,7 +2146,7 @@ function IssuesSheet({
1953
2146
  }
1954
2147
  return { block, idx, errors };
1955
2148
  }).filter(Boolean);
1956
- return /* @__PURE__ */ jsxRuntime.jsx(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { className: "flex flex-col gap-3 sm:max-w-md", children: [
2149
+ return /* @__PURE__ */ jsxRuntime.jsx(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { className: "flex w-full max-w-full flex-col gap-3 sm:max-w-md", children: [
1957
2150
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
1958
2151
  /* @__PURE__ */ jsxRuntime.jsxs(SheetTitle, { className: "flex items-center gap-2", children: [
1959
2152
  validation.total === 0 ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-4 w-4 text-emerald-600" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-4 w-4 text-destructive" }),
@@ -2003,16 +2196,16 @@ function JsonDrawer({
2003
2196
  blocks,
2004
2197
  onApply
2005
2198
  }) {
2006
- const [value, setValue] = React2.useState("");
2007
- const [parseError, setParseError] = React2.useState(null);
2008
- const [validationErrors, setValidationErrors] = React2.useState([]);
2009
- const textareaRef = React2.useRef(null);
2010
- const gutterRef = React2.useRef(null);
2011
- const blocksRef = React2.useRef(blocks);
2012
- React2.useEffect(() => {
2199
+ const [value, setValue] = React.useState("");
2200
+ const [parseError, setParseError] = React.useState(null);
2201
+ const [validationErrors, setValidationErrors] = React.useState([]);
2202
+ const textareaRef = React.useRef(null);
2203
+ const gutterRef = React.useRef(null);
2204
+ const blocksRef = React.useRef(blocks);
2205
+ React.useEffect(() => {
2013
2206
  blocksRef.current = blocks;
2014
2207
  });
2015
- React2.useEffect(() => {
2208
+ React.useEffect(() => {
2016
2209
  if (open) {
2017
2210
  setValue(JSON.stringify(blocksRef.current, null, 2));
2018
2211
  setParseError(null);
@@ -2047,7 +2240,7 @@ function JsonDrawer({
2047
2240
  });
2048
2241
  setValidationErrors(result.valid ? [] : result.errors);
2049
2242
  };
2050
- const lineCount = React2.useMemo(() => {
2243
+ const lineCount = React.useMemo(() => {
2051
2244
  if (!value) {
2052
2245
  return 1;
2053
2246
  }
@@ -2059,8 +2252,8 @@ function JsonDrawer({
2059
2252
  }
2060
2253
  return n;
2061
2254
  }, [value]);
2062
- return /* @__PURE__ */ jsxRuntime.jsx(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { className: "flex flex-col gap-3 sm:max-w-xl", children: [
2063
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
2255
+ return /* @__PURE__ */ jsxRuntime.jsx(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { className: "flex w-full max-w-full flex-col gap-3 sm:max-w-xl", children: [
2256
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 pr-8", children: [
2064
2257
  /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { children: "Block Kit JSON" }),
2065
2258
  /* @__PURE__ */ jsxRuntime.jsx(SheetDescription, { children: "Edits update the preview as you type. Parse errors show below." })
2066
2259
  ] }),
@@ -2078,6 +2271,7 @@ function JsonDrawer({
2078
2271
  "textarea",
2079
2272
  {
2080
2273
  ref: textareaRef,
2274
+ "aria-label": "Block Kit JSON",
2081
2275
  value,
2082
2276
  onChange: (e) => handleChange(e.target.value),
2083
2277
  onScroll: (e) => {
@@ -2103,7 +2297,7 @@ function JsonDrawer({
2103
2297
  ] })
2104
2298
  ] }) });
2105
2299
  }
2106
- var Input = React2__namespace.forwardRef(
2300
+ var Input = React__namespace.forwardRef(
2107
2301
  ({ className, type, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2108
2302
  "input",
2109
2303
  {
@@ -2150,51 +2344,82 @@ function Palette({
2150
2344
  sections,
2151
2345
  defaultOpenSections = true,
2152
2346
  showSearch = true,
2153
- searchPlaceholder = "Search blocks\u2026"
2347
+ searchPlaceholder = "Search blocks\u2026",
2348
+ variant = "aside"
2154
2349
  }) {
2155
- const [query, setQuery] = React2.useState("");
2156
- const visibleSections = React2.useMemo(
2350
+ const [query, setQuery] = React.useState("");
2351
+ const visibleSections = React.useMemo(
2157
2352
  () => showSearch ? filterSections(sections, query) : sections,
2158
2353
  [sections, query, showSearch]
2159
2354
  );
2160
2355
  const queryActive = showSearch && query.trim().length > 0;
2161
- return /* @__PURE__ */ jsxRuntime.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: [
2162
- showSearch ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10 border-b bg-muted/20 px-3 pt-3 pb-2 backdrop-blur", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
2163
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "pointer-events-none absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
2164
- /* @__PURE__ */ jsxRuntime.jsx(
2165
- Input,
2166
- {
2167
- type: "search",
2168
- value: query,
2169
- onChange: (e) => setQuery(e.target.value),
2170
- placeholder: searchPlaceholder,
2171
- "aria-label": searchPlaceholder,
2172
- className: "h-8 pl-7 text-sm"
2173
- }
2174
- )
2175
- ] }) }) : null,
2176
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col p-3", children: visibleSections.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-1 py-2 text-xs text-muted-foreground", children: "No blocks match." }) : visibleSections.map((section) => /* @__PURE__ */ jsxRuntime.jsx(
2177
- PaletteSection,
2178
- {
2179
- section,
2180
- defaultOpen: isDefaultOpen(section.name, defaultOpenSections),
2181
- forceOpen: queryActive,
2182
- onAddBlock
2183
- },
2184
- section.name
2185
- )) })
2186
- ] });
2356
+ const isSheet = variant === "sheet";
2357
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2358
+ "aside",
2359
+ {
2360
+ className: cn(
2361
+ "flex min-h-0 flex-col overflow-x-hidden overflow-y-auto",
2362
+ isSheet ? "w-full flex-1 bg-background" : "w-72 shrink-0 border-r bg-muted/20"
2363
+ ),
2364
+ children: [
2365
+ showSearch ? /* @__PURE__ */ jsxRuntime.jsx(
2366
+ "div",
2367
+ {
2368
+ className: cn(
2369
+ "sticky top-0 z-10 border-b px-3 pt-3 pb-2 backdrop-blur",
2370
+ isSheet ? "bg-background" : "bg-muted/20"
2371
+ ),
2372
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
2373
+ /* @__PURE__ */ jsxRuntime.jsx(
2374
+ lucideReact.Search,
2375
+ {
2376
+ className: cn(
2377
+ "pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground",
2378
+ isSheet ? "h-4 w-4" : "h-3.5 w-3.5"
2379
+ )
2380
+ }
2381
+ ),
2382
+ /* @__PURE__ */ jsxRuntime.jsx(
2383
+ Input,
2384
+ {
2385
+ type: "search",
2386
+ value: query,
2387
+ onChange: (e) => setQuery(e.target.value),
2388
+ placeholder: searchPlaceholder,
2389
+ "aria-label": searchPlaceholder,
2390
+ className: cn(isSheet ? "h-10 pl-8 text-base" : "h-8 pl-7 text-sm")
2391
+ }
2392
+ )
2393
+ ] })
2394
+ }
2395
+ ) : null,
2396
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col", isSheet ? "px-2 pb-6" : "p-3"), children: visibleSections.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-1 py-2 text-xs text-muted-foreground", children: "No blocks match." }) : visibleSections.map((section) => /* @__PURE__ */ jsxRuntime.jsx(
2397
+ PaletteSection,
2398
+ {
2399
+ section,
2400
+ defaultOpen: isDefaultOpen(section.name, defaultOpenSections),
2401
+ forceOpen: queryActive,
2402
+ onAddBlock,
2403
+ variant
2404
+ },
2405
+ section.name
2406
+ )) })
2407
+ ]
2408
+ }
2409
+ );
2187
2410
  }
2188
2411
  function PaletteSection({
2189
2412
  section,
2190
2413
  defaultOpen,
2191
2414
  forceOpen,
2192
- onAddBlock
2415
+ onAddBlock,
2416
+ variant = "aside"
2193
2417
  }) {
2194
- const [open, setOpen] = React2.useState(defaultOpen);
2418
+ const [open, setOpen] = React.useState(defaultOpen);
2195
2419
  const Icon = section.icon;
2196
2420
  const isOpen = open || forceOpen;
2197
2421
  const Caret = isOpen ? lucideReact.ChevronDown : lucideReact.ChevronRight;
2422
+ const isSheet = variant === "sheet";
2198
2423
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex flex-col first:mt-0", children: [
2199
2424
  /* @__PURE__ */ jsxRuntime.jsxs(
2200
2425
  "button",
@@ -2202,21 +2427,54 @@ function PaletteSection({
2202
2427
  type: "button",
2203
2428
  "aria-expanded": isOpen,
2204
2429
  onClick: () => setOpen((v) => !v),
2205
- 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",
2430
+ className: cn(
2431
+ "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",
2432
+ isSheet ? "px-2 py-2 min-h-10" : "px-1 py-1"
2433
+ ),
2206
2434
  children: [
2207
- /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
2208
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-[13px] font-semibold text-foreground", children: section.name }),
2209
- /* @__PURE__ */ jsxRuntime.jsx(Caret, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" })
2435
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: cn("shrink-0 text-muted-foreground", isSheet ? "h-5 w-5" : "h-4 w-4") }),
2436
+ /* @__PURE__ */ jsxRuntime.jsx(
2437
+ "span",
2438
+ {
2439
+ className: cn("min-w-0 flex-1 truncate font-semibold text-foreground", isSheet ? "text-sm" : "text-[13px]"),
2440
+ children: section.name
2441
+ }
2442
+ ),
2443
+ /* @__PURE__ */ jsxRuntime.jsx(Caret, { className: cn("shrink-0 text-muted-foreground", isSheet ? "h-4 w-4" : "h-3.5 w-3.5") })
2210
2444
  ]
2211
2445
  }
2212
2446
  ),
2213
- isOpen ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 flex flex-col", children: section.variants.map((variant) => /* @__PURE__ */ jsxRuntime.jsx(PaletteItem, { variant, onAdd: () => onAddBlock(variant.factory()) }, variant.id)) }) : null
2447
+ isOpen ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 flex flex-col", children: section.variants.map((v) => /* @__PURE__ */ jsxRuntime.jsx(PaletteItem, { variant: v, onAdd: () => onAddBlock(v.factory()), mode: variant }, v.id)) }) : null
2214
2448
  ] });
2215
2449
  }
2216
- function PaletteItem({ variant, onAdd }) {
2450
+ function PaletteItem({
2451
+ variant,
2452
+ onAdd,
2453
+ mode = "aside"
2454
+ }) {
2217
2455
  const { attributes, listeners, setNodeRef, setActivatorNodeRef, isDragging } = core.useDraggable({
2218
2456
  id: `${PALETTE_DRAG_PREFIX}${variant.id}`
2219
2457
  });
2458
+ const isSheet = mode === "sheet";
2459
+ if (isSheet) {
2460
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2461
+ "button",
2462
+ {
2463
+ ref: setNodeRef,
2464
+ type: "button",
2465
+ "aria-label": `Add ${variant.label}`,
2466
+ onClick: onAdd,
2467
+ className: cn(
2468
+ "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",
2469
+ isDragging && "opacity-50"
2470
+ ),
2471
+ children: [
2472
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground transition-colors group-hover:bg-primary/10 group-hover:text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" }) }),
2473
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: variant.label })
2474
+ ]
2475
+ }
2476
+ );
2477
+ }
2220
2478
  return /* @__PURE__ */ jsxRuntime.jsxs(
2221
2479
  "div",
2222
2480
  {
@@ -2278,7 +2536,7 @@ var buttonVariants = classVarianceAuthority.cva(
2278
2536
  }
2279
2537
  }
2280
2538
  );
2281
- var Button = React2__namespace.forwardRef(
2539
+ var Button = React__namespace.forwardRef(
2282
2540
  ({ className, variant, size, asChild = false, ...props }, ref) => {
2283
2541
  const Comp = asChild ? reactSlot.Slot : "button";
2284
2542
  return /* @__PURE__ */ jsxRuntime.jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref, ...props });
@@ -2287,7 +2545,7 @@ var Button = React2__namespace.forwardRef(
2287
2545
  Button.displayName = "Button";
2288
2546
  var Dialog = DialogPrimitive__namespace.Root;
2289
2547
  var DialogPortal = DialogPrimitive__namespace.Portal;
2290
- var DialogOverlay = React2__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2548
+ var DialogOverlay = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2291
2549
  DialogPrimitive__namespace.Overlay,
2292
2550
  {
2293
2551
  ref,
@@ -2299,7 +2557,7 @@ var DialogOverlay = React2__namespace.forwardRef(({ className, ...props }, ref)
2299
2557
  }
2300
2558
  ));
2301
2559
  DialogOverlay.displayName = DialogPrimitive__namespace.Overlay.displayName;
2302
- var DialogContent = React2__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { children: [
2560
+ var DialogContent = React__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { children: [
2303
2561
  /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
2304
2562
  /* @__PURE__ */ jsxRuntime.jsxs(
2305
2563
  DialogPrimitive__namespace.Content,
@@ -2327,7 +2585,7 @@ function DialogHeader({ className, ...props }) {
2327
2585
  function DialogFooter({ className, ...props }) {
2328
2586
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className), ...props });
2329
2587
  }
2330
- var DialogTitle = React2__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2588
+ var DialogTitle = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2331
2589
  DialogPrimitive__namespace.Title,
2332
2590
  {
2333
2591
  ref,
@@ -2336,9 +2594,9 @@ var DialogTitle = React2__namespace.forwardRef(({ className, ...props }, ref) =>
2336
2594
  }
2337
2595
  ));
2338
2596
  DialogTitle.displayName = DialogPrimitive__namespace.Title.displayName;
2339
- var DialogDescription = React2__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
2597
+ var DialogDescription = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
2340
2598
  DialogDescription.displayName = DialogPrimitive__namespace.Description.displayName;
2341
- var Label = React2__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2599
+ var Label = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2342
2600
  LabelPrimitive__namespace.Root,
2343
2601
  {
2344
2602
  ref,
@@ -2357,22 +2615,22 @@ function SendDialog({
2357
2615
  errorCount,
2358
2616
  onShowIssues
2359
2617
  }) {
2360
- const [channels, setChannels] = React2.useState(null);
2361
- const [channelsError, setChannelsError] = React2.useState(null);
2362
- const [channelId, setChannelId] = React2.useState("");
2363
- const [userStatus, setUserStatus] = React2.useState(null);
2364
- const [sendAs, setSendAs] = React2.useState("bot");
2365
- const [status, setStatus] = React2.useState({ kind: "idle" });
2366
- const loadChannelsRef = React2.useRef(loadChannels);
2367
- const loadSendAsUserStatusRef = React2.useRef(loadSendAsUserStatus);
2368
- React2.useEffect(() => {
2618
+ const [channels, setChannels] = React.useState(null);
2619
+ const [channelsError, setChannelsError] = React.useState(null);
2620
+ const [channelId, setChannelId] = React.useState("");
2621
+ const [userStatus, setUserStatus] = React.useState(null);
2622
+ const [sendAs, setSendAs] = React.useState("bot");
2623
+ const [status, setStatus] = React.useState({ kind: "idle" });
2624
+ const loadChannelsRef = React.useRef(loadChannels);
2625
+ const loadSendAsUserStatusRef = React.useRef(loadSendAsUserStatus);
2626
+ React.useEffect(() => {
2369
2627
  loadChannelsRef.current = loadChannels;
2370
2628
  loadSendAsUserStatusRef.current = loadSendAsUserStatus;
2371
2629
  });
2372
- const refreshSendAsUser = React2.useCallback(() => {
2630
+ const refreshSendAsUser = React.useCallback(() => {
2373
2631
  loadSendAsUserStatusRef.current().then(setUserStatus).catch(() => setUserStatus({ canSendAsUser: false }));
2374
2632
  }, []);
2375
- React2.useEffect(() => {
2633
+ React.useEffect(() => {
2376
2634
  if (!open) {
2377
2635
  return;
2378
2636
  }
@@ -2400,7 +2658,7 @@ function SendDialog({
2400
2658
  cancelled = true;
2401
2659
  };
2402
2660
  }, [open, refreshSendAsUser]);
2403
- React2.useEffect(() => {
2661
+ React.useEffect(() => {
2404
2662
  if (!open) {
2405
2663
  return;
2406
2664
  }
@@ -2437,7 +2695,7 @@ function SendDialog({
2437
2695
  });
2438
2696
  }
2439
2697
  };
2440
- return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { children: [
2698
+ return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "w-[calc(100vw-1.5rem)] max-w-lg rounded-lg", children: [
2441
2699
  /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
2442
2700
  /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Send to Slack" }),
2443
2701
  /* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: "Pick a channel and choose who to post as." })
@@ -2535,7 +2793,7 @@ function SendDialog({
2535
2793
  }
2536
2794
  var Popover = PopoverPrimitive__namespace.Root;
2537
2795
  var PopoverTrigger = PopoverPrimitive__namespace.Trigger;
2538
- var PopoverContent = React2__namespace.forwardRef(({ className, align = "start", sideOffset = 8, collisionPadding = 16, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
2796
+ var PopoverContent = React__namespace.forwardRef(({ className, align = "start", sideOffset = 8, collisionPadding = 16, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
2539
2797
  PopoverPrimitive__namespace.Content,
2540
2798
  {
2541
2799
  ref,
@@ -2551,9 +2809,9 @@ var PopoverContent = React2__namespace.forwardRef(({ className, align = "start",
2551
2809
  }
2552
2810
  ) }));
2553
2811
  PopoverContent.displayName = PopoverPrimitive__namespace.Content.displayName;
2554
- var RadioGroup = React2__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(RadioGroupPrimitive__namespace.Root, { className: cn("grid gap-2", className), ...props, ref }));
2812
+ var RadioGroup = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(RadioGroupPrimitive__namespace.Root, { className: cn("grid gap-2", className), ...props, ref }));
2555
2813
  RadioGroup.displayName = RadioGroupPrimitive__namespace.Root.displayName;
2556
- var RadioGroupItem = React2__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2814
+ var RadioGroupItem = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2557
2815
  RadioGroupPrimitive__namespace.Item,
2558
2816
  {
2559
2817
  ref,
@@ -2685,7 +2943,7 @@ function ActionsEditor({ block, onChange }) {
2685
2943
  ] })
2686
2944
  ] });
2687
2945
  }
2688
- var Textarea = React2__namespace.forwardRef(
2946
+ var Textarea = React__namespace.forwardRef(
2689
2947
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2690
2948
  "textarea",
2691
2949
  {
@@ -3715,7 +3973,14 @@ function PlainTextInputEditor({
3715
3973
  }) {
3716
3974
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3717
3975
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
3718
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
3976
+ /* @__PURE__ */ jsxRuntime.jsx(
3977
+ PlaceholderField,
3978
+ {
3979
+ element,
3980
+ onChange,
3981
+ example: element.multiline ? "e.g. Enter a longer description" : "e.g. Enter some text"
3982
+ }
3983
+ ),
3719
3984
  /* @__PURE__ */ jsxRuntime.jsx(
3720
3985
  EditorField,
3721
3986
  {
@@ -3777,7 +4042,7 @@ function PlainTextInputEditor({
3777
4042
  function EmailInputEditor({ element, onChange }) {
3778
4043
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3779
4044
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
3780
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4045
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. name@example.com" }),
3781
4046
  /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Initial value", help: "Pre-filled email address.", htmlFor: "email-initial", children: /* @__PURE__ */ jsxRuntime.jsx(
3782
4047
  Input,
3783
4048
  {
@@ -3792,7 +4057,7 @@ function EmailInputEditor({ element, onChange }) {
3792
4057
  function URLInputEditor({ element, onChange }) {
3793
4058
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3794
4059
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
3795
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4060
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. https://example.com" }),
3796
4061
  /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Initial value", help: "Pre-filled URL.", htmlFor: "url-initial", children: /* @__PURE__ */ jsxRuntime.jsx(
3797
4062
  Input,
3798
4063
  {
@@ -3807,7 +4072,7 @@ function URLInputEditor({ element, onChange }) {
3807
4072
  function NumberInputEditor({ element, onChange }) {
3808
4073
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3809
4074
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
3810
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4075
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. 0" }),
3811
4076
  /* @__PURE__ */ jsxRuntime.jsx(
3812
4077
  CheckboxField,
3813
4078
  {
@@ -3860,7 +4125,7 @@ function NumberInputEditor({ element, onChange }) {
3860
4125
  function DatepickerEditor({ element, onChange }) {
3861
4126
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3862
4127
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
3863
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4128
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. Select a date" }),
3864
4129
  /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Initial date", help: "YYYY-MM-DD. Pre-selected on load.", htmlFor: "date-initial", children: /* @__PURE__ */ jsxRuntime.jsx(
3865
4130
  Input,
3866
4131
  {
@@ -3875,7 +4140,7 @@ function DatepickerEditor({ element, onChange }) {
3875
4140
  function TimepickerEditor({ element, onChange }) {
3876
4141
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3877
4142
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
3878
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4143
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. Select a time" }),
3879
4144
  /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Initial time", help: "HH:mm in 24-hour clock.", htmlFor: "time-initial", children: /* @__PURE__ */ jsxRuntime.jsx(
3880
4145
  Input,
3881
4146
  {
@@ -3928,7 +4193,7 @@ function DateTimepickerEditor({
3928
4193
  function StaticSelectEditor({ element, onChange }) {
3929
4194
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3930
4195
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
3931
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4196
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. Choose one" }),
3932
4197
  /* @__PURE__ */ jsxRuntime.jsx(
3933
4198
  PlainTextOptionsField,
3934
4199
  {
@@ -3944,7 +4209,7 @@ function MultiStaticSelectEditor({
3944
4209
  }) {
3945
4210
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3946
4211
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
3947
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4212
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. Choose one or more" }),
3948
4213
  /* @__PURE__ */ jsxRuntime.jsx(
3949
4214
  PlainTextOptionsField,
3950
4215
  {
@@ -3958,7 +4223,7 @@ function MultiStaticSelectEditor({
3958
4223
  function UsersSelectEditor({ element, onChange }) {
3959
4224
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3960
4225
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
3961
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4226
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. Select a user" }),
3962
4227
  /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Initial user ID", help: "Optional. Pre-selects this Slack user.", htmlFor: "users-initial", children: /* @__PURE__ */ jsxRuntime.jsx(
3963
4228
  Input,
3964
4229
  {
@@ -3976,7 +4241,7 @@ function MultiUsersSelectEditor({
3976
4241
  }) {
3977
4242
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3978
4243
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
3979
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4244
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. Select users" }),
3980
4245
  /* @__PURE__ */ jsxRuntime.jsx(MaxSelectedField, { element, onChange })
3981
4246
  ] });
3982
4247
  }
@@ -3986,7 +4251,7 @@ function ChannelsSelectEditor({
3986
4251
  }) {
3987
4252
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3988
4253
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
3989
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4254
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. Select a channel" }),
3990
4255
  /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Initial channel ID", help: "Optional. Pre-selects this channel.", htmlFor: "channels-initial", children: /* @__PURE__ */ jsxRuntime.jsx(
3991
4256
  Input,
3992
4257
  {
@@ -4007,7 +4272,7 @@ function MultiChannelsSelectEditor({
4007
4272
  }) {
4008
4273
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4009
4274
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
4010
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4275
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. Select channels" }),
4011
4276
  /* @__PURE__ */ jsxRuntime.jsx(MaxSelectedField, { element, onChange })
4012
4277
  ] });
4013
4278
  }
@@ -4017,7 +4282,7 @@ function ConversationsSelectEditor({
4017
4282
  }) {
4018
4283
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4019
4284
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
4020
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4285
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. Select a conversation" }),
4021
4286
  /* @__PURE__ */ jsxRuntime.jsx(
4022
4287
  EditorField,
4023
4288
  {
@@ -4059,7 +4324,7 @@ function MultiConversationsSelectEditor({
4059
4324
  }) {
4060
4325
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4061
4326
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
4062
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4327
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. Select conversations" }),
4063
4328
  /* @__PURE__ */ jsxRuntime.jsx(MaxSelectedField, { element, onChange }),
4064
4329
  /* @__PURE__ */ jsxRuntime.jsx(
4065
4330
  CheckboxField,
@@ -4082,7 +4347,7 @@ function ExternalSelectEditor({
4082
4347
  }) {
4083
4348
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4084
4349
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
4085
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4350
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. Choose one" }),
4086
4351
  /* @__PURE__ */ jsxRuntime.jsx(
4087
4352
  EditorField,
4088
4353
  {
@@ -4112,7 +4377,7 @@ function MultiExternalSelectEditor({
4112
4377
  }) {
4113
4378
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4114
4379
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
4115
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4380
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. Choose one or more" }),
4116
4381
  /* @__PURE__ */ jsxRuntime.jsx(
4117
4382
  EditorField,
4118
4383
  {
@@ -4167,7 +4432,7 @@ function RichTextInputEditor({
4167
4432
  }) {
4168
4433
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4169
4434
  /* @__PURE__ */ jsxRuntime.jsx(ActionIdField, { element, onChange }),
4170
- /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange }),
4435
+ /* @__PURE__ */ jsxRuntime.jsx(PlaceholderField, { element, onChange, example: "e.g. Type something" }),
4171
4436
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "Edit the initial rich-text value via the View JSON drawer." })
4172
4437
  ] });
4173
4438
  }
@@ -4236,13 +4501,14 @@ function ActionIdField({
4236
4501
  }
4237
4502
  );
4238
4503
  }
4239
- function PlaceholderField({ element, onChange }) {
4504
+ function PlaceholderField({ element, onChange, example = "e.g. Type a hint" }) {
4240
4505
  return /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Placeholder", help: "Greyed-out hint shown when the input is empty.", htmlFor: "placeholder", children: /* @__PURE__ */ jsxRuntime.jsx(
4241
4506
  Input,
4242
4507
  {
4243
4508
  id: "placeholder",
4244
4509
  value: element.placeholder?.text ?? "",
4245
4510
  maxLength: 150,
4511
+ placeholder: example,
4246
4512
  onChange: (e) => onChange({
4247
4513
  ...element,
4248
4514
  placeholder: e.target.value ? { type: "plain_text", text: e.target.value, emoji: true } : void 0
@@ -4390,6 +4656,96 @@ function MarkdownEditor({ block, onChange }) {
4390
4656
  }
4391
4657
  );
4392
4658
  }
4659
+ var STATUSES = ["pending", "in_progress", "complete", "error"];
4660
+ function PlanEditor({ block, onChange }) {
4661
+ const titleText = typeof block.title === "string" ? block.title : block.title?.text ?? "";
4662
+ const tasks = block.tasks ?? [];
4663
+ const updateTask = (idx, change) => {
4664
+ onChange({
4665
+ ...block,
4666
+ tasks: tasks.map((t, i) => i === idx ? { ...t, ...change } : t)
4667
+ });
4668
+ };
4669
+ const removeTask = (idx) => {
4670
+ const next = tasks.filter((_, i) => i !== idx);
4671
+ onChange({ ...block, tasks: next.length > 0 ? next : void 0 });
4672
+ };
4673
+ const addTask = () => {
4674
+ onChange({
4675
+ ...block,
4676
+ tasks: [
4677
+ ...tasks,
4678
+ {
4679
+ type: "task_card",
4680
+ task_id: `task_${nanoid.nanoid(6)}`,
4681
+ title: "New step",
4682
+ status: "pending"
4683
+ }
4684
+ ]
4685
+ });
4686
+ };
4687
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
4688
+ /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Title", help: "Heading shown above the task list.", htmlFor: "plan-title", children: /* @__PURE__ */ jsxRuntime.jsx(
4689
+ Input,
4690
+ {
4691
+ id: "plan-title",
4692
+ value: titleText,
4693
+ placeholder: "e.g. Investigating the issue",
4694
+ onChange: (e) => onChange({ ...block, title: e.target.value })
4695
+ }
4696
+ ) }),
4697
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 rounded-md border bg-muted/20 p-3", children: [
4698
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-foreground", children: "Tasks" }),
4699
+ tasks.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "No tasks. Add one to render a checklist beneath the title." }) : null,
4700
+ tasks.map((task, idx) => {
4701
+ const status = task.status ?? "pending";
4702
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 rounded border bg-background p-2", children: [
4703
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
4704
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-foreground", children: [
4705
+ "Task ",
4706
+ idx + 1
4707
+ ] }),
4708
+ /* @__PURE__ */ jsxRuntime.jsx(
4709
+ "button",
4710
+ {
4711
+ type: "button",
4712
+ "aria-label": "Remove task",
4713
+ onClick: () => removeTask(idx),
4714
+ className: "rounded p-1 text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
4715
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" })
4716
+ }
4717
+ )
4718
+ ] }),
4719
+ /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Title", htmlFor: `plan-task-title-${idx}`, children: /* @__PURE__ */ jsxRuntime.jsx(
4720
+ Input,
4721
+ {
4722
+ id: `plan-task-title-${idx}`,
4723
+ value: task.title,
4724
+ placeholder: "e.g. Reproduce the error locally",
4725
+ onChange: (e) => updateTask(idx, { title: e.target.value })
4726
+ }
4727
+ ) }),
4728
+ /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Status", children: /* @__PURE__ */ jsxRuntime.jsx(
4729
+ RadioGroup,
4730
+ {
4731
+ value: status,
4732
+ onValueChange: (v) => updateTask(idx, { status: v }),
4733
+ className: "flex flex-row flex-wrap gap-3",
4734
+ children: STATUSES.map((s) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
4735
+ /* @__PURE__ */ jsxRuntime.jsx(RadioGroupItem, { value: s, id: `plan-task-status-${idx}-${s}` }),
4736
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `plan-task-status-${idx}-${s}`, className: "text-xs capitalize", children: s.replace("_", " ") })
4737
+ ] }, s))
4738
+ }
4739
+ ) })
4740
+ ] }, idx);
4741
+ }),
4742
+ /* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", size: "sm", onClick: addTask, className: "self-start", children: [
4743
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-3.5 w-3.5" }),
4744
+ " Add task"
4745
+ ] })
4746
+ ] })
4747
+ ] });
4748
+ }
4393
4749
 
4394
4750
  // src/lib/rich-text-tiptap.ts
4395
4751
  var SUPPORTED_BLOCK_KINDS = /* @__PURE__ */ new Set([
@@ -5275,8 +5631,8 @@ function LossyBanner({ reasons }) {
5275
5631
  ] });
5276
5632
  }
5277
5633
  function RichTextWysiwygEditor({ block, onChange }) {
5278
- const lastEmittedRef = React2.useRef(null);
5279
- const handleUpdate = React2.useCallback(
5634
+ const lastEmittedRef = React.useRef(null);
5635
+ const handleUpdate = React.useCallback(
5280
5636
  (editor2) => {
5281
5637
  const next = proseMirrorToRichText(editor2.getJSON());
5282
5638
  lastEmittedRef.current = next;
@@ -5314,7 +5670,7 @@ function RichTextWysiwygEditor({ block, onChange }) {
5314
5670
  },
5315
5671
  onUpdate: ({ editor: ed }) => handleUpdate(ed)
5316
5672
  });
5317
- React2.useEffect(() => {
5673
+ React.useEffect(() => {
5318
5674
  if (!editor) {
5319
5675
  return;
5320
5676
  }
@@ -5463,10 +5819,10 @@ function Divider() {
5463
5819
  function LinkPopover({ editor }) {
5464
5820
  const active = editor.isActive("link");
5465
5821
  const currentHref = editor.getAttributes("link").href ?? "";
5466
- const [open, setOpen] = React2.useState(false);
5467
- const [url, setUrl] = React2.useState(currentHref);
5468
- const [error, setError] = React2.useState(null);
5469
- React2.useEffect(() => {
5822
+ const [open, setOpen] = React.useState(false);
5823
+ const [url, setUrl] = React.useState(currentHref);
5824
+ const [error, setError] = React.useState(null);
5825
+ React.useEffect(() => {
5470
5826
  if (open) {
5471
5827
  setUrl(currentHref);
5472
5828
  setError(null);
@@ -5880,21 +6236,260 @@ function TableEditor({ block, onChange }) {
5880
6236
  ] })
5881
6237
  ] });
5882
6238
  }
5883
- function BlockEditor({
5884
- block,
5885
- errors,
5886
- onChange
5887
- }) {
5888
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
5889
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "text-sm font-semibold text-foreground", children: [
5890
- "Edit ",
5891
- labelForBlockType(block.type)
5892
- ] }) }),
5893
- errors && errors.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-0.5 rounded-md border border-destructive/30 bg-destructive/5 p-2 text-xs text-destructive", children: errors.map((err, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: err }, i)) }) : null,
5894
- dispatch(block, onChange)
5895
- ] });
5896
- }
5897
- function dispatch(block, onChange) {
6239
+ var STATUSES2 = ["pending", "in_progress", "complete", "error"];
6240
+ function TaskCardEditor({ block, onChange }) {
6241
+ const status = block.status ?? "pending";
6242
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
6243
+ /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Title", help: "Short label shown at the top of the card.", htmlFor: "task-card-title", children: /* @__PURE__ */ jsxRuntime.jsx(
6244
+ Input,
6245
+ {
6246
+ id: "task-card-title",
6247
+ value: block.title,
6248
+ placeholder: "e.g. Reproduce the bug locally",
6249
+ onChange: (e) => onChange({ ...block, title: e.target.value })
6250
+ }
6251
+ ) }),
6252
+ /* @__PURE__ */ jsxRuntime.jsx(
6253
+ EditorField,
6254
+ {
6255
+ label: "Task ID",
6256
+ help: "Stable identifier you can reference from interaction payloads.",
6257
+ htmlFor: "task-card-id",
6258
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6259
+ Input,
6260
+ {
6261
+ id: "task-card-id",
6262
+ value: block.task_id,
6263
+ placeholder: "e.g. task_1",
6264
+ onChange: (e) => onChange({ ...block, task_id: e.target.value })
6265
+ }
6266
+ )
6267
+ }
6268
+ ),
6269
+ /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Status", help: "Slack renders a matching status chip on the card.", children: /* @__PURE__ */ jsxRuntime.jsx(
6270
+ RadioGroup,
6271
+ {
6272
+ value: status,
6273
+ onValueChange: (v) => onChange({ ...block, status: v }),
6274
+ className: "flex flex-row flex-wrap gap-3",
6275
+ children: STATUSES2.map((s) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
6276
+ /* @__PURE__ */ jsxRuntime.jsx(RadioGroupItem, { value: s, id: `task-card-status-${s}` }),
6277
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `task-card-status-${s}`, className: "text-xs capitalize", children: s.replace("_", " ") })
6278
+ ] }, s))
6279
+ }
6280
+ ) }),
6281
+ /* @__PURE__ */ jsxRuntime.jsx(
6282
+ SourcesField,
6283
+ {
6284
+ sources: block.sources ?? [],
6285
+ onChange: (next) => onChange({ ...block, sources: next.length > 0 ? next : void 0 })
6286
+ }
6287
+ )
6288
+ ] });
6289
+ }
6290
+ function SourcesField({
6291
+ sources,
6292
+ onChange
6293
+ }) {
6294
+ const update = (idx, change) => {
6295
+ onChange(sources.map((s, i) => i === idx ? { ...s, ...change } : s));
6296
+ };
6297
+ const removeAt = (idx) => onChange(sources.filter((_, i) => i !== idx));
6298
+ const addSource = () => {
6299
+ onChange([...sources, { type: "url", url: "", text: "" }]);
6300
+ };
6301
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 rounded-md border bg-muted/20 p-3", children: [
6302
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-foreground", children: "Sources" }),
6303
+ sources.length === 0 ? /* @__PURE__ */ jsxRuntime.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,
6304
+ sources.map((src, idx) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 rounded border bg-background p-2", children: [
6305
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
6306
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-foreground", children: [
6307
+ "Source ",
6308
+ idx + 1
6309
+ ] }),
6310
+ /* @__PURE__ */ jsxRuntime.jsx(
6311
+ "button",
6312
+ {
6313
+ type: "button",
6314
+ "aria-label": "Remove source",
6315
+ onClick: () => removeAt(idx),
6316
+ className: "rounded p-1 text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
6317
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" })
6318
+ }
6319
+ )
6320
+ ] }),
6321
+ /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Label", htmlFor: `task-card-source-text-${idx}`, children: /* @__PURE__ */ jsxRuntime.jsx(
6322
+ Input,
6323
+ {
6324
+ id: `task-card-source-text-${idx}`,
6325
+ value: src.text,
6326
+ placeholder: "e.g. Runbook",
6327
+ onChange: (e) => update(idx, { text: e.target.value })
6328
+ }
6329
+ ) }),
6330
+ /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "URL", htmlFor: `task-card-source-url-${idx}`, children: /* @__PURE__ */ jsxRuntime.jsx(
6331
+ Input,
6332
+ {
6333
+ id: `task-card-source-url-${idx}`,
6334
+ type: "url",
6335
+ value: src.url,
6336
+ placeholder: "e.g. https://example.com/runbook",
6337
+ onChange: (e) => update(idx, { url: e.target.value })
6338
+ }
6339
+ ) })
6340
+ ] }, idx)),
6341
+ /* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", size: "sm", onClick: addSource, className: "self-start", children: [
6342
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-3.5 w-3.5" }),
6343
+ " Add source"
6344
+ ] })
6345
+ ] });
6346
+ }
6347
+ function VideoEditor({ block, onChange }) {
6348
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
6349
+ /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Title", help: "Up to 199 characters. Shown above the embedded player.", htmlFor: "video-title", children: /* @__PURE__ */ jsxRuntime.jsx(
6350
+ Input,
6351
+ {
6352
+ id: "video-title",
6353
+ value: block.title?.text ?? "",
6354
+ maxLength: 199,
6355
+ placeholder: "e.g. Product demo",
6356
+ onChange: (e) => onChange({
6357
+ ...block,
6358
+ title: { type: "plain_text", text: e.target.value, emoji: true }
6359
+ })
6360
+ }
6361
+ ) }),
6362
+ /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Alt text", help: "Tooltip for the video. Required for accessibility.", htmlFor: "video-alt", children: /* @__PURE__ */ jsxRuntime.jsx(
6363
+ Input,
6364
+ {
6365
+ id: "video-alt",
6366
+ value: block.alt_text ?? "",
6367
+ placeholder: "e.g. A short walkthrough of the new release",
6368
+ onChange: (e) => onChange({ ...block, alt_text: e.target.value })
6369
+ }
6370
+ ) }),
6371
+ /* @__PURE__ */ jsxRuntime.jsx(
6372
+ EditorField,
6373
+ {
6374
+ label: "Video URL",
6375
+ help: "HTTPS embed URL. Must match an unfurl domain on your Slack app.",
6376
+ htmlFor: "video-url",
6377
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6378
+ Input,
6379
+ {
6380
+ id: "video-url",
6381
+ type: "url",
6382
+ value: block.video_url ?? "",
6383
+ placeholder: "e.g. https://www.youtube.com/embed/dQw4w9WgXcQ",
6384
+ onChange: (e) => onChange({ ...block, video_url: e.target.value })
6385
+ }
6386
+ )
6387
+ }
6388
+ ),
6389
+ /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Thumbnail URL", help: "Preview image shown before the video loads.", htmlFor: "video-thumbnail", children: /* @__PURE__ */ jsxRuntime.jsx(
6390
+ Input,
6391
+ {
6392
+ id: "video-thumbnail",
6393
+ type: "url",
6394
+ value: block.thumbnail_url ?? "",
6395
+ placeholder: "e.g. https://example.com/thumb.png",
6396
+ onChange: (e) => onChange({ ...block, thumbnail_url: e.target.value })
6397
+ }
6398
+ ) }),
6399
+ /* @__PURE__ */ jsxRuntime.jsx(
6400
+ EditorField,
6401
+ {
6402
+ label: "Title link URL",
6403
+ help: "Optional. HTTPS link the title text opens (the non-embed page).",
6404
+ htmlFor: "video-title-url",
6405
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6406
+ Input,
6407
+ {
6408
+ id: "video-title-url",
6409
+ type: "url",
6410
+ value: block.title_url ?? "",
6411
+ placeholder: "e.g. https://www.youtube.com/watch?v=dQw4w9WgXcQ",
6412
+ onChange: (e) => onChange({ ...block, title_url: e.target.value || void 0 })
6413
+ }
6414
+ )
6415
+ }
6416
+ ),
6417
+ /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Description", help: "Optional. Up to 199 characters.", htmlFor: "video-description", children: /* @__PURE__ */ jsxRuntime.jsx(
6418
+ Textarea,
6419
+ {
6420
+ id: "video-description",
6421
+ value: block.description?.text ?? "",
6422
+ maxLength: 199,
6423
+ rows: 2,
6424
+ placeholder: "e.g. A short walkthrough of the new release.",
6425
+ onChange: (e) => onChange({
6426
+ ...block,
6427
+ description: e.target.value ? { type: "plain_text", text: e.target.value, emoji: true } : void 0
6428
+ })
6429
+ }
6430
+ ) }),
6431
+ /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Author name", help: "Optional. Up to 49 characters.", htmlFor: "video-author", children: /* @__PURE__ */ jsxRuntime.jsx(
6432
+ Input,
6433
+ {
6434
+ id: "video-author",
6435
+ value: block.author_name ?? "",
6436
+ maxLength: 49,
6437
+ placeholder: "e.g. Acme",
6438
+ onChange: (e) => onChange({ ...block, author_name: e.target.value || void 0 })
6439
+ }
6440
+ ) }),
6441
+ /* @__PURE__ */ jsxRuntime.jsx(
6442
+ EditorField,
6443
+ {
6444
+ label: "Provider name",
6445
+ help: "Optional. Originating service (e.g. YouTube, Vimeo).",
6446
+ htmlFor: "video-provider-name",
6447
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6448
+ Input,
6449
+ {
6450
+ id: "video-provider-name",
6451
+ value: block.provider_name ?? "",
6452
+ placeholder: "e.g. YouTube",
6453
+ onChange: (e) => onChange({ ...block, provider_name: e.target.value || void 0 })
6454
+ }
6455
+ )
6456
+ }
6457
+ ),
6458
+ /* @__PURE__ */ jsxRuntime.jsx(
6459
+ EditorField,
6460
+ {
6461
+ label: "Provider icon URL",
6462
+ help: "Optional. Small icon shown next to the provider name.",
6463
+ htmlFor: "video-provider-icon",
6464
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6465
+ Input,
6466
+ {
6467
+ id: "video-provider-icon",
6468
+ type: "url",
6469
+ value: block.provider_icon_url ?? "",
6470
+ placeholder: "e.g. https://example.com/youtube-favicon.png",
6471
+ onChange: (e) => onChange({ ...block, provider_icon_url: e.target.value || void 0 })
6472
+ }
6473
+ )
6474
+ }
6475
+ )
6476
+ ] });
6477
+ }
6478
+ function BlockEditor({
6479
+ block,
6480
+ errors,
6481
+ onChange
6482
+ }) {
6483
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
6484
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "text-sm font-semibold text-foreground", children: [
6485
+ "Edit ",
6486
+ labelForBlockType(block.type)
6487
+ ] }) }),
6488
+ errors && errors.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-0.5 rounded-md border border-destructive/30 bg-destructive/5 p-2 text-xs text-destructive", children: errors.map((err, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: err }, i)) }) : null,
6489
+ dispatch(block, onChange)
6490
+ ] });
6491
+ }
6492
+ function dispatch(block, onChange) {
5898
6493
  switch (block.type) {
5899
6494
  case "section":
5900
6495
  return /* @__PURE__ */ jsxRuntime.jsx(SectionEditor, { block, onChange: (next) => onChange(next) });
@@ -5924,6 +6519,12 @@ function dispatch(block, onChange) {
5924
6519
  return /* @__PURE__ */ jsxRuntime.jsx(ContextActionsEditor, { block, onChange: (next) => onChange(next) });
5925
6520
  case "input":
5926
6521
  return /* @__PURE__ */ jsxRuntime.jsx(InputEditor, { block, onChange: (next) => onChange(next) });
6522
+ case "video":
6523
+ return /* @__PURE__ */ jsxRuntime.jsx(VideoEditor, { block, onChange: (next) => onChange(next) });
6524
+ case "plan":
6525
+ return /* @__PURE__ */ jsxRuntime.jsx(PlanEditor, { block, onChange: (next) => onChange(next) });
6526
+ case "task_card":
6527
+ return /* @__PURE__ */ jsxRuntime.jsx(TaskCardEditor, { block, onChange: (next) => onChange(next) });
5927
6528
  default:
5928
6529
  return null;
5929
6530
  }
@@ -5933,9 +6534,9 @@ function SlackBlockPreview({
5933
6534
  hooks,
5934
6535
  theme = "light"
5935
6536
  }) {
5936
- const rootRef = React2.useRef(null);
5937
- const safeBlock = React2.useMemo(() => sanitizeBlock(block), [block]);
5938
- React2.useEffect(() => {
6537
+ const rootRef = React.useRef(null);
6538
+ const safeBlock = React.useMemo(() => sanitizeBlock(block), [block]);
6539
+ React.useEffect(() => {
5939
6540
  const root = rootRef.current;
5940
6541
  if (!root) return;
5941
6542
  for (const wrapper of root.querySelectorAll(
@@ -5996,7 +6597,10 @@ var BLOCK_TYPE_LABELS = {
5996
6597
  card: "Card",
5997
6598
  carousel: "Carousel",
5998
6599
  context_actions: "Context Actions",
5999
- input: "Input"
6600
+ input: "Input",
6601
+ video: "Video",
6602
+ plan: "Plan",
6603
+ task_card: "Task Card"
6000
6604
  };
6001
6605
  function BlockRow({
6002
6606
  builderBlock,
@@ -6008,6 +6612,9 @@ function BlockRow({
6008
6612
  onUpdate,
6009
6613
  onDuplicate,
6010
6614
  onDelete,
6615
+ index,
6616
+ total,
6617
+ onReorder,
6011
6618
  isPaletteDrag = false
6012
6619
  }) {
6013
6620
  const { attributes, listeners, setNodeRef, transform, transition, isDragging, isOver } = sortable.useSortable({
@@ -6020,154 +6627,253 @@ function BlockRow({
6020
6627
  };
6021
6628
  const hasErrors = !!errors && errors.length > 0;
6022
6629
  const isRichText = builderBlock.block.type === "rich_text";
6023
- const [inlineEditing, setInlineEditing] = React2.useState(false);
6630
+ const [inlineEditing, setInlineEditing] = React.useState(false);
6024
6631
  const showDropIndicator = isPaletteDrag && isOver;
6025
6632
  const preview = /* @__PURE__ */ jsxRuntime.jsx(SlackBlockPreview, { block: builderBlock.block, hooks: previewHooks, theme: previewTheme });
6026
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: setNodeRef, style, className: cn("group relative hover:z-10", isDragging && "opacity-40"), children: [
6027
- showDropIndicator ? /* @__PURE__ */ jsxRuntime.jsx(
6028
- "div",
6029
- {
6030
- "aria-hidden": "true",
6031
- className: "-top-1 pointer-events-none absolute right-0 left-0 z-20 h-0.5 rounded-full bg-primary",
6032
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "-left-1 -top-[3px] absolute h-2 w-2 rounded-full bg-primary shadow-[0_0_0_2px_var(--color-background)]" })
6033
- }
6034
- ) : null,
6035
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
6036
- isRichText && inlineEditing ? /* @__PURE__ */ jsxRuntime.jsx(
6037
- RichTextInlineEditor,
6038
- {
6039
- block: builderBlock.block,
6040
- onSave: (next) => {
6041
- onUpdate(builderBlock.id, next);
6042
- setInlineEditing(false);
6043
- },
6044
- onCancel: () => setInlineEditing(false)
6045
- }
6046
- ) : isRichText ? /* @__PURE__ */ jsxRuntime.jsx(
6047
- "button",
6048
- {
6049
- type: "button",
6050
- "aria-label": "Edit block",
6051
- onClick: () => setInlineEditing(true),
6052
- ...attributes,
6053
- ...listeners,
6054
- className: cn(
6055
- "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",
6056
- hasErrors ? "ring-1 ring-destructive/60 hover:ring-destructive" : "hover:ring-1 hover:ring-border"
6057
- ),
6058
- children: preview
6059
- }
6060
- ) : /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: isOpen, onOpenChange, children: [
6061
- /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6633
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6634
+ "div",
6635
+ {
6636
+ ref: setNodeRef,
6637
+ style,
6638
+ className: cn("group relative mb-2 last:mb-0 hover:z-10 md:mb-0", isDragging && "opacity-40"),
6639
+ children: [
6640
+ showDropIndicator ? /* @__PURE__ */ jsxRuntime.jsx(
6062
6641
  "div",
6063
6642
  {
6064
- role: "button",
6065
- tabIndex: 0,
6066
- "aria-label": "Edit block",
6067
- ...sortableA11yAttrs,
6068
- ...listeners,
6069
- className: cn(
6070
- "block w-full cursor-grab rounded-sm transition-shadow hover:shadow-md focus-visible:ring-1 focus-visible:ring-ring active:cursor-grabbing",
6071
- hasErrors ? "ring-1 ring-destructive/60 hover:ring-destructive" : "hover:ring-1 hover:ring-border"
6072
- ),
6073
- children: preview
6643
+ "aria-hidden": "true",
6644
+ className: "-top-1 pointer-events-none absolute right-0 left-0 z-20 h-0.5 rounded-full bg-primary",
6645
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "-left-1 -top-[3px] absolute h-2 w-2 rounded-full bg-primary shadow-[0_0_0_2px_var(--color-background)]" })
6074
6646
  }
6075
- ) }),
6076
- /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "w-[32rem]", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
6077
- BlockEditor,
6078
- {
6079
- block: builderBlock.block,
6080
- errors,
6081
- onChange: (next) => onUpdate(builderBlock.id, next)
6082
- }
6083
- ) })
6084
- ] }),
6085
- /* @__PURE__ */ jsxRuntime.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] }),
6086
- /* @__PURE__ */ jsxRuntime.jsxs(
6087
- "div",
6088
- {
6089
- className: cn(
6090
- "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",
6091
- hasErrors ? "opacity-100" : "opacity-0 group-hover:opacity-100"
6092
- ),
6093
- children: [
6094
- hasErrors ? /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
6095
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6096
- "button",
6097
- {
6098
- type: "button",
6099
- "aria-label": `Show ${errors.length} validation ${errors.length === 1 ? "issue" : "issues"}`,
6100
- onClick: () => onOpenChange?.(true),
6101
- className: "flex h-6 w-6 items-center justify-center rounded text-destructive hover:bg-destructive/10",
6102
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3.5 w-3.5" })
6103
- }
6104
- ) }),
6105
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", align: "end", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "flex flex-col gap-0.5", children: [
6106
- errors.slice(0, 4).map((err, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: err }, i)),
6107
- errors.length > 4 ? /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "text-muted-foreground", children: [
6108
- "and ",
6109
- errors.length - 4,
6110
- " more"
6111
- ] }) : null
6112
- ] }) })
6113
- ] }) : null,
6114
- /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
6115
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6116
- "button",
6117
- {
6118
- type: "button",
6119
- "aria-label": "Edit block",
6120
- onClick: () => {
6121
- if (isRichText) {
6122
- setInlineEditing(true);
6123
- } else {
6124
- onOpenChange?.(true);
6647
+ ) : null,
6648
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
6649
+ isRichText && inlineEditing ? /* @__PURE__ */ jsxRuntime.jsx(
6650
+ RichTextInlineEditor,
6651
+ {
6652
+ block: builderBlock.block,
6653
+ onSave: (next) => {
6654
+ onUpdate(builderBlock.id, next);
6655
+ setInlineEditing(false);
6656
+ },
6657
+ onCancel: () => setInlineEditing(false)
6658
+ }
6659
+ ) : isRichText ? /* @__PURE__ */ jsxRuntime.jsx(
6660
+ "button",
6661
+ {
6662
+ type: "button",
6663
+ "aria-label": "Edit block",
6664
+ onClick: () => setInlineEditing(true),
6665
+ ...attributes,
6666
+ ...listeners,
6667
+ className: cn(
6668
+ "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",
6669
+ hasErrors ? "ring-1 ring-destructive/60 hover:ring-destructive" : "hover:ring-1 hover:ring-border"
6670
+ ),
6671
+ children: preview
6672
+ }
6673
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: isOpen, onOpenChange, children: [
6674
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6675
+ "div",
6676
+ {
6677
+ role: "button",
6678
+ tabIndex: 0,
6679
+ "aria-label": "Edit block",
6680
+ ...sortableA11yAttrs,
6681
+ ...listeners,
6682
+ onKeyDown: (e) => {
6683
+ if (e.key === "Enter" || e.key === " ") {
6684
+ e.preventDefault();
6685
+ onOpenChange?.(!isOpen);
6686
+ }
6687
+ },
6688
+ className: cn(
6689
+ "block w-full cursor-grab rounded-sm transition-shadow hover:shadow-md focus-visible:ring-1 focus-visible:ring-ring active:cursor-grabbing",
6690
+ hasErrors ? "ring-1 ring-destructive/60 hover:ring-destructive" : "hover:ring-1 hover:ring-border"
6691
+ ),
6692
+ children: preview
6693
+ }
6694
+ ) }),
6695
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "w-[min(32rem,calc(100vw-1.5rem))] sm:w-[32rem]", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
6696
+ BlockEditor,
6697
+ {
6698
+ block: builderBlock.block,
6699
+ errors,
6700
+ onChange: (next) => onUpdate(builderBlock.id, next)
6701
+ }
6702
+ ) })
6703
+ ] }),
6704
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "-translate-x-1/2 pointer-events-none absolute bottom-full left-1/2 z-10 hidden bg-background px-1.5 text-[11px] text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100 md:block", children: BLOCK_TYPE_LABELS[builderBlock.block.type] }),
6705
+ /* @__PURE__ */ jsxRuntime.jsxs(
6706
+ "div",
6707
+ {
6708
+ className: cn(
6709
+ // Hidden on mobile in favor of the inline row below; on desktop
6710
+ // reveal on hover, on focus inside the row (so Tab-stops on the
6711
+ // floating buttons themselves keep them visible), and when there
6712
+ // are validation errors worth surfacing immediately.
6713
+ "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",
6714
+ hasErrors ? "opacity-100" : "opacity-0 group-hover:opacity-100 group-focus-within:opacity-100"
6715
+ ),
6716
+ children: [
6717
+ hasErrors ? /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
6718
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6719
+ "button",
6720
+ {
6721
+ type: "button",
6722
+ "aria-label": `Show ${errors.length} validation ${errors.length === 1 ? "issue" : "issues"}`,
6723
+ onClick: () => onOpenChange?.(true),
6724
+ 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",
6725
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3.5 w-3.5" })
6125
6726
  }
6126
- },
6127
- className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground",
6128
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-3.5 w-3.5" })
6129
- }
6130
- ) }),
6131
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Edit" })
6132
- ] }),
6133
- /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
6134
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6135
- "button",
6136
- {
6137
- type: "button",
6138
- "aria-label": "Duplicate block",
6139
- onClick: () => onDuplicate(builderBlock.id),
6140
- className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground",
6141
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-3.5 w-3.5" })
6142
- }
6143
- ) }),
6144
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Duplicate" })
6145
- ] }),
6146
- /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
6147
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6148
- "button",
6149
- {
6150
- type: "button",
6151
- "aria-label": "Delete block",
6152
- onClick: () => onDelete(builderBlock.id),
6153
- className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
6154
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" })
6155
- }
6156
- ) }),
6157
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Delete" })
6158
- ] })
6159
- ]
6160
- }
6161
- )
6162
- ] })
6163
- ] });
6727
+ ) }),
6728
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", align: "end", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "flex flex-col gap-0.5", children: [
6729
+ errors.slice(0, 4).map((err, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: err }, i)),
6730
+ errors.length > 4 ? /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "text-muted-foreground", children: [
6731
+ "and ",
6732
+ errors.length - 4,
6733
+ " more"
6734
+ ] }) : null
6735
+ ] }) })
6736
+ ] }) : null,
6737
+ onReorder && typeof index === "number" && typeof total === "number" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6738
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
6739
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6740
+ "button",
6741
+ {
6742
+ type: "button",
6743
+ "aria-label": "Move block up",
6744
+ disabled: index === 0,
6745
+ onClick: () => onReorder(builderBlock.id, index - 1),
6746
+ 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",
6747
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-3.5 w-3.5" })
6748
+ }
6749
+ ) }),
6750
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Move up" })
6751
+ ] }),
6752
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
6753
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6754
+ "button",
6755
+ {
6756
+ type: "button",
6757
+ "aria-label": "Move block down",
6758
+ disabled: index >= total - 1,
6759
+ onClick: () => onReorder(builderBlock.id, index + 1),
6760
+ 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",
6761
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "h-3.5 w-3.5" })
6762
+ }
6763
+ ) }),
6764
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Move down" })
6765
+ ] })
6766
+ ] }) : null,
6767
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
6768
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6769
+ "button",
6770
+ {
6771
+ type: "button",
6772
+ "aria-label": "Edit block",
6773
+ onClick: () => {
6774
+ if (isRichText) {
6775
+ setInlineEditing(true);
6776
+ } else {
6777
+ onOpenChange?.(true);
6778
+ }
6779
+ },
6780
+ 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",
6781
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-3.5 w-3.5" })
6782
+ }
6783
+ ) }),
6784
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Edit" })
6785
+ ] }),
6786
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
6787
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6788
+ "button",
6789
+ {
6790
+ type: "button",
6791
+ "aria-label": "Duplicate block",
6792
+ onClick: () => onDuplicate(builderBlock.id),
6793
+ 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",
6794
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-3.5 w-3.5" })
6795
+ }
6796
+ ) }),
6797
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Duplicate" })
6798
+ ] }),
6799
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
6800
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6801
+ "button",
6802
+ {
6803
+ type: "button",
6804
+ "aria-label": "Delete block",
6805
+ onClick: () => onDelete(builderBlock.id),
6806
+ 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",
6807
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" })
6808
+ }
6809
+ ) }),
6810
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: "Delete" })
6811
+ ] })
6812
+ ]
6813
+ }
6814
+ )
6815
+ ] }),
6816
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex items-center justify-between gap-2 rounded-md border border-dashed bg-muted/40 px-2 py-1 md:hidden", children: [
6817
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[11px] font-medium text-muted-foreground", children: BLOCK_TYPE_LABELS[builderBlock.block.type] }),
6818
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
6819
+ hasErrors ? /* @__PURE__ */ jsxRuntime.jsx(
6820
+ "button",
6821
+ {
6822
+ type: "button",
6823
+ "aria-label": `Show ${errors.length} validation ${errors.length === 1 ? "issue" : "issues"}`,
6824
+ onClick: () => onOpenChange?.(true),
6825
+ className: "flex h-9 w-9 items-center justify-center rounded text-destructive hover:bg-destructive/10",
6826
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-4 w-4" })
6827
+ }
6828
+ ) : null,
6829
+ /* @__PURE__ */ jsxRuntime.jsx(
6830
+ "button",
6831
+ {
6832
+ type: "button",
6833
+ "aria-label": "Edit block",
6834
+ onClick: () => {
6835
+ if (isRichText) {
6836
+ setInlineEditing(true);
6837
+ } else {
6838
+ onOpenChange?.(true);
6839
+ }
6840
+ },
6841
+ className: "flex h-9 w-9 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground",
6842
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-4 w-4" })
6843
+ }
6844
+ ),
6845
+ /* @__PURE__ */ jsxRuntime.jsx(
6846
+ "button",
6847
+ {
6848
+ type: "button",
6849
+ "aria-label": "Duplicate block",
6850
+ onClick: () => onDuplicate(builderBlock.id),
6851
+ className: "flex h-9 w-9 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground",
6852
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-4 w-4" })
6853
+ }
6854
+ ),
6855
+ /* @__PURE__ */ jsxRuntime.jsx(
6856
+ "button",
6857
+ {
6858
+ type: "button",
6859
+ "aria-label": "Delete block",
6860
+ onClick: () => onDelete(builderBlock.id),
6861
+ className: "flex h-9 w-9 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
6862
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-4 w-4" })
6863
+ }
6864
+ )
6865
+ ] })
6866
+ ] })
6867
+ ]
6868
+ }
6869
+ );
6164
6870
  }
6165
6871
  function RichTextInlineEditor({
6166
6872
  block,
6167
6873
  onSave,
6168
6874
  onCancel
6169
6875
  }) {
6170
- const [draft, setDraft] = React2.useState(block);
6876
+ const [draft, setDraft] = React.useState(block);
6171
6877
  return /* @__PURE__ */ jsxRuntime.jsxs(
6172
6878
  "div",
6173
6879
  {
@@ -6201,7 +6907,9 @@ function Surface({
6201
6907
  onUpdate,
6202
6908
  onDuplicate,
6203
6909
  onDelete,
6204
- isPaletteDrag = false
6910
+ onReorder,
6911
+ isPaletteDrag = false,
6912
+ onOpenPalette
6205
6913
  }) {
6206
6914
  const { setNodeRef, isOver } = core.useDroppable({ id: SURFACE_DROPPABLE_ID });
6207
6915
  const isDark = previewTheme === "dark";
@@ -6211,13 +6919,13 @@ function Surface({
6211
6919
  {
6212
6920
  ref: setNodeRef,
6213
6921
  className: cn(
6214
- "flex min-h-[240px] flex-col px-5 py-2 transition-colors",
6922
+ "flex min-h-[180px] flex-col px-3 py-2 transition-colors sm:min-h-[240px] sm:px-5",
6215
6923
  isDark ? "bg-[#1a1d21]" : "bg-white",
6216
6924
  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"),
6217
6925
  isPaletteDrag && isOver && (isDark ? "bg-[#2c3036]" : "bg-[#eaf0ff]")
6218
6926
  ),
6219
- children: blocks.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { isDark, isPaletteDrag, isOver }) : /* @__PURE__ */ jsxRuntime.jsxs(sortable.SortableContext, { items: blocks.map((b) => b.id), strategy: sortable.verticalListSortingStrategy, children: [
6220
- blocks.map((block) => /* @__PURE__ */ jsxRuntime.jsx(
6927
+ children: blocks.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { isDark, isPaletteDrag, isOver, onOpenPalette }) : /* @__PURE__ */ jsxRuntime.jsxs(sortable.SortableContext, { items: blocks.map((b) => b.id), strategy: sortable.verticalListSortingStrategy, children: [
6928
+ blocks.map((block, idx) => /* @__PURE__ */ jsxRuntime.jsx(
6221
6929
  BlockRow,
6222
6930
  {
6223
6931
  builderBlock: block,
@@ -6229,6 +6937,9 @@ function Surface({
6229
6937
  onUpdate,
6230
6938
  onDuplicate,
6231
6939
  onDelete,
6940
+ index: idx,
6941
+ total: blocks.length,
6942
+ onReorder,
6232
6943
  isPaletteDrag
6233
6944
  },
6234
6945
  block.id
@@ -6237,7 +6948,14 @@ function Surface({
6237
6948
  ] })
6238
6949
  }
6239
6950
  );
6240
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-1 flex-col p-6", isDark ? "bg-[#0e0f12]" : "bg-[#f4f4f4]"), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-2xl", children: previewSurface === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(ModalFrame, { isDark, children: blocksList }) : previewSurface === "app_home" ? /* @__PURE__ */ jsxRuntime.jsx(AppHomeFrame, { workspaceName, isDark, children: blocksList }) : /* @__PURE__ */ jsxRuntime.jsx(MessageFrame, { workspaceName, isDark, children: blocksList }) }) });
6951
+ return /* @__PURE__ */ jsxRuntime.jsx(
6952
+ "main",
6953
+ {
6954
+ "aria-label": "Block preview",
6955
+ className: cn("flex min-w-0 flex-1 flex-col overflow-y-auto bg-muted p-3 sm:p-6"),
6956
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-2xl", children: previewSurface === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(ModalFrame, { isDark, children: blocksList }) : previewSurface === "app_home" ? /* @__PURE__ */ jsxRuntime.jsx(AppHomeFrame, { workspaceName, isDark, children: blocksList }) : /* @__PURE__ */ jsxRuntime.jsx(MessageFrame, { workspaceName, isDark, children: blocksList }) })
6957
+ }
6958
+ );
6241
6959
  }
6242
6960
  function MessageFrame({
6243
6961
  workspaceName,
@@ -6307,13 +7025,12 @@ function ModalFrame({ isDark, children }) {
6307
7025
  children: [
6308
7026
  /* @__PURE__ */ jsxRuntime.jsx("h2", { className: cn("text-base font-bold", isDark ? "text-white" : "text-[#1d1c1d]"), children: "Modal title" }),
6309
7027
  /* @__PURE__ */ jsxRuntime.jsx(
6310
- "button",
7028
+ "span",
6311
7029
  {
6312
- type: "button",
6313
- "aria-label": "Close",
7030
+ "aria-hidden": "true",
6314
7031
  className: cn(
6315
7032
  "flex h-6 w-6 items-center justify-center rounded",
6316
- isDark ? "text-white/60 hover:bg-white/10 hover:text-white" : "text-[#616061] hover:bg-[#f3f3f3] hover:text-[#1d1c1d]"
7033
+ isDark ? "text-white/60" : "text-[#616061]"
6317
7034
  ),
6318
7035
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" })
6319
7036
  }
@@ -6325,30 +7042,23 @@ function ModalFrame({ isDark, children }) {
6325
7042
  /* @__PURE__ */ jsxRuntime.jsxs(
6326
7043
  "div",
6327
7044
  {
7045
+ "aria-hidden": "true",
6328
7046
  className: cn(
6329
7047
  "flex items-center justify-end gap-2 border-t px-5 py-3",
6330
7048
  isDark ? "border-[#2c2d30]" : "border-[#e8e8e8]"
6331
7049
  ),
6332
7050
  children: [
6333
7051
  /* @__PURE__ */ jsxRuntime.jsx(
6334
- "button",
7052
+ "span",
6335
7053
  {
6336
- type: "button",
6337
7054
  className: cn(
6338
- "cursor-pointer rounded-sm border px-3 py-1.5 text-sm font-medium",
6339
- isDark ? "border-white/20 bg-transparent text-white hover:bg-white/5" : "border-[#e8e8e8] bg-white text-[#1d1c1d] hover:bg-[#f3f3f3]"
7055
+ "rounded-sm border px-3 py-1.5 text-sm font-medium",
7056
+ isDark ? "border-white/20 bg-transparent text-white" : "border-[#e8e8e8] bg-white text-[#1d1c1d]"
6340
7057
  ),
6341
7058
  children: "Cancel"
6342
7059
  }
6343
7060
  ),
6344
- /* @__PURE__ */ jsxRuntime.jsx(
6345
- "button",
6346
- {
6347
- type: "button",
6348
- className: "cursor-pointer rounded-sm bg-[#007a5a] px-3 py-1.5 text-sm font-bold text-white hover:bg-[#148567]",
6349
- children: "Submit"
6350
- }
6351
- )
7061
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-sm bg-[#007a5a] px-3 py-1.5 text-sm font-bold text-white", children: "Submit" })
6352
7062
  ]
6353
7063
  }
6354
7064
  )
@@ -6417,7 +7127,12 @@ function AppHomeFrame({
6417
7127
  }
6418
7128
  );
6419
7129
  }
6420
- function EmptyState({ isDark, isPaletteDrag, isOver }) {
7130
+ function EmptyState({
7131
+ isDark,
7132
+ isPaletteDrag,
7133
+ isOver,
7134
+ onOpenPalette
7135
+ }) {
6421
7136
  const active = isPaletteDrag && isOver;
6422
7137
  return /* @__PURE__ */ jsxRuntime.jsxs(
6423
7138
  "div",
@@ -6437,7 +7152,7 @@ function EmptyState({ isDark, isPaletteDrag, isOver }) {
6437
7152
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGrid, { className: "h-6 w-6" })
6438
7153
  }
6439
7154
  ),
6440
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
7155
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
6441
7156
  /* @__PURE__ */ jsxRuntime.jsx(
6442
7157
  "p",
6443
7158
  {
@@ -6448,8 +7163,23 @@ function EmptyState({ isDark, isPaletteDrag, isOver }) {
6448
7163
  children: active ? "Drop to add block" : "Start adding blocks!"
6449
7164
  }
6450
7165
  ),
6451
- /* @__PURE__ */ jsxRuntime.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." })
6452
- ] })
7166
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs", children: active ? "Release to insert it here." : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7167
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden md:inline", children: "Drag a block from the left, or click one to add it here." }),
7168
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "md:hidden", children: "Tap \u201CAdd a block\u201D below to get started." })
7169
+ ] }) })
7170
+ ] }),
7171
+ !active && onOpenPalette ? /* @__PURE__ */ jsxRuntime.jsxs(
7172
+ "button",
7173
+ {
7174
+ type: "button",
7175
+ onClick: onOpenPalette,
7176
+ 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",
7177
+ children: [
7178
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4" }),
7179
+ "Add a block"
7180
+ ]
7181
+ }
7182
+ ) : null
6453
7183
  ]
6454
7184
  }
6455
7185
  );
@@ -6473,6 +7203,7 @@ function Toolbar2({
6473
7203
  onOpenJson,
6474
7204
  onOpenIssues,
6475
7205
  onOpenSend,
7206
+ onOpenPalette,
6476
7207
  canSend,
6477
7208
  canClear,
6478
7209
  previewTheme,
@@ -6490,61 +7221,63 @@ function Toolbar2({
6490
7221
  const showSurfaceControl = surfaceOptions.length > 1;
6491
7222
  const docsHref = docsLink === false ? null : docsLink?.href ?? DEFAULT_DOCS_HREF;
6492
7223
  const docsLabel = docsLink === false ? null : docsLink?.label ?? DEFAULT_DOCS_LABEL;
6493
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 border-b bg-background px-3 py-2", children: [
6494
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6495
- showSurfaceControl ? /* @__PURE__ */ jsxRuntime.jsxs(Popover, { children: [
6496
- /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", variant: "ghost", size: "sm", children: [
7224
+ const [surfaceMenuOpen, setSurfaceMenuOpen] = React.useState(false);
7225
+ const [themeMenuOpen, setThemeMenuOpen] = React.useState(false);
7226
+ const [moreMenuOpen, setMoreMenuOpen] = React.useState(false);
7227
+ return /* @__PURE__ */ jsxRuntime.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: [
7228
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-1 sm:gap-2", children: [
7229
+ onOpenPalette ? /* @__PURE__ */ jsxRuntime.jsxs(
7230
+ Button,
7231
+ {
7232
+ type: "button",
7233
+ variant: "ghost",
7234
+ size: "sm",
7235
+ onClick: onOpenPalette,
7236
+ className: "md:hidden",
7237
+ "aria-label": "Add a block",
7238
+ children: [
7239
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4" }),
7240
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Blocks" })
7241
+ ]
7242
+ }
7243
+ ) : null,
7244
+ showSurfaceControl ? /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: surfaceMenuOpen, onOpenChange: setSurfaceMenuOpen, children: [
7245
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": `Preview surface: ${activeSurface.label}`, children: [
6497
7246
  /* @__PURE__ */ jsxRuntime.jsx(activeSurface.Icon, { className: "h-3.5 w-3.5" }),
6498
- activeSurface.label,
7247
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: activeSurface.label }),
6499
7248
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-3.5 w-3.5 opacity-60" })
6500
7249
  ] }) }),
6501
- /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { align: "start", className: "w-36 p-1", children: surfaceOptions.map(({ value, label, Icon }) => {
6502
- const isActive = value === previewSurface;
6503
- return /* @__PURE__ */ jsxRuntime.jsxs(
6504
- "button",
6505
- {
6506
- type: "button",
6507
- onClick: () => onPreviewSurfaceChange(value),
6508
- className: cn(
6509
- "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",
6510
- isActive ? "text-foreground" : "text-muted-foreground"
6511
- ),
6512
- children: [
6513
- /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-3.5 w-3.5" }),
6514
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: label }),
6515
- isActive ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3.5 w-3.5" }) : null
6516
- ]
6517
- },
6518
- value
6519
- );
6520
- }) })
7250
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { align: "start", className: "w-36 p-1", children: /* @__PURE__ */ jsxRuntime.jsx(
7251
+ Menu,
7252
+ {
7253
+ ariaLabel: "Preview surface",
7254
+ options: surfaceOptions,
7255
+ value: previewSurface,
7256
+ onChange: (next) => {
7257
+ onPreviewSurfaceChange(next);
7258
+ setSurfaceMenuOpen(false);
7259
+ }
7260
+ }
7261
+ ) })
6521
7262
  ] }) : null,
6522
- showThemeControl ? /* @__PURE__ */ jsxRuntime.jsxs(Popover, { children: [
6523
- /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", variant: "ghost", size: "sm", children: [
7263
+ showThemeControl ? /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: themeMenuOpen, onOpenChange: setThemeMenuOpen, children: [
7264
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": `Preview theme: ${activeTheme.label}`, children: [
6524
7265
  /* @__PURE__ */ jsxRuntime.jsx(activeTheme.Icon, { className: "h-3.5 w-3.5" }),
6525
- activeTheme.label,
7266
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: activeTheme.label }),
6526
7267
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-3.5 w-3.5 opacity-60" })
6527
7268
  ] }) }),
6528
- /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { align: "start", className: "w-32 p-1", children: THEME_OPTIONS.map(({ value, label, Icon }) => {
6529
- const isActive = value === previewTheme;
6530
- return /* @__PURE__ */ jsxRuntime.jsxs(
6531
- "button",
6532
- {
6533
- type: "button",
6534
- onClick: () => onPreviewThemeChange(value),
6535
- className: cn(
6536
- "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",
6537
- isActive ? "text-foreground" : "text-muted-foreground"
6538
- ),
6539
- children: [
6540
- /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-3.5 w-3.5" }),
6541
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: label }),
6542
- isActive ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3.5 w-3.5" }) : null
6543
- ]
6544
- },
6545
- value
6546
- );
6547
- }) })
7269
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { align: "start", className: "w-32 p-1", children: /* @__PURE__ */ jsxRuntime.jsx(
7270
+ Menu,
7271
+ {
7272
+ ariaLabel: "Preview theme",
7273
+ options: THEME_OPTIONS,
7274
+ value: previewTheme,
7275
+ onChange: (next) => {
7276
+ onPreviewThemeChange(next);
7277
+ setThemeMenuOpen(false);
7278
+ }
7279
+ }
7280
+ ) })
6548
7281
  ] }) : null,
6549
7282
  docsHref ? /* @__PURE__ */ jsxRuntime.jsxs(
6550
7283
  "a",
@@ -6552,7 +7285,8 @@ function Toolbar2({
6552
7285
  href: docsHref,
6553
7286
  target: "_blank",
6554
7287
  rel: "noreferrer noopener",
6555
- 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",
7288
+ 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",
7289
+ "aria-label": `${docsLabel} (opens in a new tab)`,
6556
7290
  children: [
6557
7291
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BookOpen, { className: "h-3.5 w-3.5" }),
6558
7292
  docsLabel,
@@ -6561,7 +7295,7 @@ function Toolbar2({
6561
7295
  }
6562
7296
  ) : null
6563
7297
  ] }),
6564
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7298
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 sm:gap-2", children: [
6565
7299
  errorCount > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
6566
7300
  Button,
6567
7301
  {
@@ -6570,11 +7304,14 @@ function Toolbar2({
6570
7304
  size: "sm",
6571
7305
  onClick: onOpenIssues,
6572
7306
  className: "text-destructive hover:text-destructive",
7307
+ "aria-label": `${errorCount} ${errorCount === 1 ? "issue" : "issues"}`,
6573
7308
  children: [
6574
7309
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3.5 w-3.5" }),
6575
- errorCount,
6576
- " ",
6577
- errorCount === 1 ? "issue" : "issues"
7310
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
7311
+ errorCount,
7312
+ " ",
7313
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: errorCount === 1 ? "issue" : "issues" })
7314
+ ] })
6578
7315
  ]
6579
7316
  }
6580
7317
  ) : null,
@@ -6586,24 +7323,188 @@ function Toolbar2({
6586
7323
  size: "sm",
6587
7324
  onClick: onClear,
6588
7325
  disabled: !canClear,
6589
- className: "hover:bg-destructive/10 hover:text-destructive",
7326
+ className: "hidden hover:bg-destructive/10 hover:text-destructive sm:inline-flex",
7327
+ "aria-label": "Clear all blocks",
6590
7328
  children: [
6591
7329
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" }),
6592
7330
  "Clear"
6593
7331
  ]
6594
7332
  }
6595
7333
  ),
6596
- /* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", variant: "ghost", size: "sm", onClick: onOpenJson, children: [
6597
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Code2, { className: "h-3.5 w-3.5" }),
6598
- "View JSON"
7334
+ /* @__PURE__ */ jsxRuntime.jsxs(
7335
+ Button,
7336
+ {
7337
+ type: "button",
7338
+ variant: "ghost",
7339
+ size: "sm",
7340
+ onClick: onOpenJson,
7341
+ "aria-label": "View JSON",
7342
+ className: "hidden sm:inline-flex",
7343
+ children: [
7344
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Code2, { className: "h-3.5 w-3.5" }),
7345
+ "View JSON"
7346
+ ]
7347
+ }
7348
+ ),
7349
+ /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: moreMenuOpen, onOpenChange: setMoreMenuOpen, children: [
7350
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
7351
+ Button,
7352
+ {
7353
+ type: "button",
7354
+ variant: "ghost",
7355
+ size: "sm",
7356
+ "aria-label": "More actions",
7357
+ "aria-haspopup": "menu",
7358
+ className: "px-2 sm:hidden",
7359
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "h-3.5 w-3.5" })
7360
+ }
7361
+ ) }),
7362
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { align: "end", className: "w-44 p-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "menu", "aria-label": "More actions", className: "flex flex-col", children: [
7363
+ /* @__PURE__ */ jsxRuntime.jsx(
7364
+ ActionMenuItem,
7365
+ {
7366
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" }),
7367
+ onSelect: () => {
7368
+ setMoreMenuOpen(false);
7369
+ onClear();
7370
+ },
7371
+ disabled: !canClear,
7372
+ tone: "destructive",
7373
+ children: "Clear"
7374
+ }
7375
+ ),
7376
+ /* @__PURE__ */ jsxRuntime.jsx(
7377
+ ActionMenuItem,
7378
+ {
7379
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Code2, { className: "h-3.5 w-3.5" }),
7380
+ onSelect: () => {
7381
+ setMoreMenuOpen(false);
7382
+ onOpenJson();
7383
+ },
7384
+ children: "View JSON"
7385
+ }
7386
+ ),
7387
+ docsHref ? /* @__PURE__ */ jsxRuntime.jsx(
7388
+ ActionMenuLink,
7389
+ {
7390
+ href: docsHref,
7391
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BookOpen, { className: "h-3.5 w-3.5" }),
7392
+ trailingIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3 w-3 opacity-50" }),
7393
+ onSelect: () => setMoreMenuOpen(false),
7394
+ children: docsLabel
7395
+ }
7396
+ ) : null
7397
+ ] }) })
6599
7398
  ] }),
6600
- /* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", size: "sm", onClick: onOpenSend, disabled: !canSend, children: [
7399
+ /* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", size: "sm", onClick: onOpenSend, disabled: !canSend, "aria-label": "Send", children: [
6601
7400
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "h-3.5 w-3.5" }),
6602
- "Send"
7401
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "Send" })
6603
7402
  ] })
6604
7403
  ] })
6605
7404
  ] });
6606
7405
  }
7406
+ function Menu({
7407
+ ariaLabel,
7408
+ options,
7409
+ value,
7410
+ onChange
7411
+ }) {
7412
+ const itemsRef = React.useRef([]);
7413
+ const moveFocus = (from, delta) => {
7414
+ const len = options.length;
7415
+ if (len === 0) return;
7416
+ const next = (from + delta + len) % len;
7417
+ itemsRef.current[next]?.focus();
7418
+ };
7419
+ const handleKeyDown = (e, idx) => {
7420
+ if (e.key === "ArrowDown") {
7421
+ e.preventDefault();
7422
+ moveFocus(idx, 1);
7423
+ } else if (e.key === "ArrowUp") {
7424
+ e.preventDefault();
7425
+ moveFocus(idx, -1);
7426
+ } else if (e.key === "Home") {
7427
+ e.preventDefault();
7428
+ itemsRef.current[0]?.focus();
7429
+ } else if (e.key === "End") {
7430
+ e.preventDefault();
7431
+ itemsRef.current[options.length - 1]?.focus();
7432
+ }
7433
+ };
7434
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "menu", "aria-label": ariaLabel, className: "flex flex-col", children: options.map(({ value: optValue, label, Icon }, idx) => {
7435
+ const isActive = optValue === value;
7436
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7437
+ "button",
7438
+ {
7439
+ ref: (el) => {
7440
+ itemsRef.current[idx] = el;
7441
+ },
7442
+ type: "button",
7443
+ role: "menuitemradio",
7444
+ "aria-checked": isActive,
7445
+ onClick: () => onChange(optValue),
7446
+ onKeyDown: (e) => handleKeyDown(e, idx),
7447
+ className: cn(
7448
+ "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",
7449
+ isActive ? "text-foreground" : "text-muted-foreground"
7450
+ ),
7451
+ children: [
7452
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-3.5 w-3.5" }),
7453
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: label }),
7454
+ isActive ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3.5 w-3.5" }) : null
7455
+ ]
7456
+ },
7457
+ optValue
7458
+ );
7459
+ }) });
7460
+ }
7461
+ 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";
7462
+ function ActionMenuItem({
7463
+ icon,
7464
+ children,
7465
+ onSelect,
7466
+ disabled,
7467
+ tone
7468
+ }) {
7469
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7470
+ "button",
7471
+ {
7472
+ type: "button",
7473
+ role: "menuitem",
7474
+ onClick: onSelect,
7475
+ disabled,
7476
+ className: cn(ACTION_ITEM_BASE, tone === "destructive" && "hover:bg-destructive/10 hover:text-destructive"),
7477
+ children: [
7478
+ icon,
7479
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children })
7480
+ ]
7481
+ }
7482
+ );
7483
+ }
7484
+ function ActionMenuLink({
7485
+ href,
7486
+ icon,
7487
+ trailingIcon,
7488
+ children,
7489
+ onSelect
7490
+ }) {
7491
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7492
+ "a",
7493
+ {
7494
+ role: "menuitem",
7495
+ href,
7496
+ target: "_blank",
7497
+ rel: "noreferrer noopener",
7498
+ onClick: onSelect,
7499
+ className: ACTION_ITEM_BASE,
7500
+ children: [
7501
+ icon,
7502
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children }),
7503
+ trailingIcon
7504
+ ]
7505
+ }
7506
+ );
7507
+ }
6607
7508
  function BlockKitchen(props) {
6608
7509
  const {
6609
7510
  workspaceName,
@@ -6614,6 +7515,7 @@ function BlockKitchen(props) {
6614
7515
  loadSendAsUserStatus,
6615
7516
  onSend,
6616
7517
  palette,
7518
+ disabledBlockTypes,
6617
7519
  showPaletteSearch,
6618
7520
  paletteSearchPlaceholder,
6619
7521
  defaultOpenSections,
@@ -6623,22 +7525,42 @@ function BlockKitchen(props) {
6623
7525
  defaultPreviewTheme = "light",
6624
7526
  theme
6625
7527
  } = props;
6626
- const paletteSections = palette ?? defaultPalette;
6627
- const variantById = React2.useMemo(() => buildVariantById(paletteSections), [paletteSections]);
7528
+ const paletteSections = React.useMemo(() => {
7529
+ const sections = palette ?? defaultPalette;
7530
+ if (!disabledBlockTypes || disabledBlockTypes.length === 0) {
7531
+ return sections;
7532
+ }
7533
+ const blocked = new Set(disabledBlockTypes);
7534
+ const filtered = [];
7535
+ for (const section of sections) {
7536
+ const variants = section.variants.filter((variant) => !blocked.has(variant.factory().type));
7537
+ if (variants.length > 0) {
7538
+ filtered.push({ ...section, variants });
7539
+ }
7540
+ }
7541
+ return filtered;
7542
+ }, [palette, disabledBlockTypes]);
7543
+ const variantById = React.useMemo(() => buildVariantById(paletteSections), [paletteSections]);
6628
7544
  const allowedSurfaces = allowedSurfacesProp && allowedSurfacesProp.length > 0 ? allowedSurfacesProp : ["message"];
6629
7545
  const { blocks, addBlock, updateBlock, removeBlock, duplicateBlock, reorderBlock, replaceAll } = useBlockKitchenState(
6630
7546
  { initialBlocks, onChange }
6631
7547
  );
6632
- const [jsonOpen, setJsonOpen] = React2.useState(false);
6633
- const [sendOpen, setSendOpen] = React2.useState(false);
6634
- const [issuesOpen, setIssuesOpen] = React2.useState(false);
6635
- const [openBlockId, setOpenBlockId] = React2.useState(null);
6636
- const [previewTheme, setPreviewTheme] = React2.useState(defaultPreviewTheme);
6637
- const [previewSurface, setPreviewSurface] = React2.useState(allowedSurfaces[0]);
6638
- const [activePaletteVariantId, setActivePaletteVariantId] = React2.useState(null);
7548
+ const [jsonOpen, setJsonOpen] = React.useState(false);
7549
+ const [sendOpen, setSendOpen] = React.useState(false);
7550
+ const [issuesOpen, setIssuesOpen] = React.useState(false);
7551
+ const [paletteOpen, setPaletteOpen] = React.useState(false);
7552
+ const [openBlockId, setOpenBlockId] = React.useState(null);
7553
+ const [previewTheme, setPreviewTheme] = React.useState(defaultPreviewTheme);
7554
+ const [previewSurface, setPreviewSurface] = React.useState(allowedSurfaces[0]);
7555
+ const [activePaletteVariantId, setActivePaletteVariantId] = React.useState(null);
7556
+ const isMobile = useIsMobile();
6639
7557
  const validation = useBlockKitValidation(blocks, "message");
6640
- const sensors = core.useSensors(core.useSensor(core.PointerSensor, { activationConstraint: { distance: 4 } }));
6641
- const collisionDetection = React2.useCallback((args) => {
7558
+ const sensors = core.useSensors(
7559
+ core.useSensor(core.PointerSensor, { activationConstraint: { distance: 4 } }),
7560
+ core.useSensor(core.TouchSensor, { activationConstraint: { delay: 150, tolerance: 8 } }),
7561
+ core.useSensor(core.KeyboardSensor, { coordinateGetter: sortable.sortableKeyboardCoordinates })
7562
+ );
7563
+ const collisionDetection = React.useCallback((args) => {
6642
7564
  const pointerHits = core.pointerWithin(args);
6643
7565
  if (pointerHits.length > 0) {
6644
7566
  const blockHit = pointerHits.find((c) => c.id !== SURFACE_DROPPABLE_ID);
@@ -6646,11 +7568,11 @@ function BlockKitchen(props) {
6646
7568
  }
6647
7569
  return core.closestCenter(args);
6648
7570
  }, []);
6649
- const handleDragStart = React2.useCallback((event) => {
7571
+ const handleDragStart = React.useCallback((event) => {
6650
7572
  const variantId = parsePaletteDragId(event.active.id);
6651
7573
  setActivePaletteVariantId(variantId);
6652
7574
  }, []);
6653
- const handleDragEnd = React2.useCallback(
7575
+ const handleDragEnd = React.useCallback(
6654
7576
  (event) => {
6655
7577
  setActivePaletteVariantId(null);
6656
7578
  const { active, over } = event;
@@ -6676,7 +7598,7 @@ function BlockKitchen(props) {
6676
7598
  },
6677
7599
  [addBlock, blocks, reorderBlock, variantById]
6678
7600
  );
6679
- const handleDragCancel = React2.useCallback(() => {
7601
+ const handleDragCancel = React.useCallback(() => {
6680
7602
  setActivePaletteVariantId(null);
6681
7603
  }, []);
6682
7604
  const activePaletteVariant = activePaletteVariantId ? variantById.get(activePaletteVariantId) : null;
@@ -6690,7 +7612,7 @@ function BlockKitchen(props) {
6690
7612
  onDragEnd: handleDragEnd,
6691
7613
  onDragCancel: handleDragCancel,
6692
7614
  children: [
6693
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bk-root flex h-full w-full flex-col rounded-md border bg-background text-foreground", children: [
7615
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bk-root flex h-full w-full flex-col overflow-hidden rounded-md border bg-background text-foreground", children: [
6694
7616
  /* @__PURE__ */ jsxRuntime.jsx(
6695
7617
  Toolbar2,
6696
7618
  {
@@ -6698,6 +7620,7 @@ function BlockKitchen(props) {
6698
7620
  onOpenJson: () => setJsonOpen(true),
6699
7621
  onOpenIssues: () => setIssuesOpen(true),
6700
7622
  onOpenSend: () => setSendOpen(true),
7623
+ onOpenPalette: () => setPaletteOpen(true),
6701
7624
  canSend: blocks.length > 0,
6702
7625
  canClear: blocks.length > 0,
6703
7626
  errorCount: validation.total,
@@ -6711,7 +7634,7 @@ function BlockKitchen(props) {
6711
7634
  }
6712
7635
  ),
6713
7636
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 items-stretch", children: [
6714
- /* @__PURE__ */ jsxRuntime.jsx(
7637
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden min-h-0 md:flex", children: /* @__PURE__ */ jsxRuntime.jsx(
6715
7638
  Palette,
6716
7639
  {
6717
7640
  onAddBlock: (block) => addBlock(block),
@@ -6720,7 +7643,7 @@ function BlockKitchen(props) {
6720
7643
  searchPlaceholder: paletteSearchPlaceholder,
6721
7644
  defaultOpenSections
6722
7645
  }
6723
- ),
7646
+ ) }),
6724
7647
  /* @__PURE__ */ jsxRuntime.jsx(
6725
7648
  Surface,
6726
7649
  {
@@ -6735,7 +7658,9 @@ function BlockKitchen(props) {
6735
7658
  onUpdate: updateBlock,
6736
7659
  onDuplicate: duplicateBlock,
6737
7660
  onDelete: removeBlock,
6738
- isPaletteDrag: activePaletteVariant !== null
7661
+ onReorder: reorderBlock,
7662
+ isPaletteDrag: activePaletteVariant !== null,
7663
+ onOpenPalette: () => setPaletteOpen(true)
6739
7664
  }
6740
7665
  )
6741
7666
  ] })
@@ -6744,6 +7669,33 @@ function BlockKitchen(props) {
6744
7669
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GripVertical, { className: "h-3 w-3 shrink-0" }),
6745
7670
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: activePaletteVariant.label })
6746
7671
  ] }) : null }),
7672
+ /* @__PURE__ */ jsxRuntime.jsx(Sheet, { open: paletteOpen && isMobile, onOpenChange: setPaletteOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(
7673
+ SheetContent,
7674
+ {
7675
+ side: "bottom",
7676
+ className: "bk-portal-content flex h-[85svh] max-h-[85svh] flex-col gap-3 p-0 sm:max-w-none",
7677
+ children: [
7678
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 px-4 pt-5", children: [
7679
+ /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { children: "Add a block" }),
7680
+ /* @__PURE__ */ jsxRuntime.jsx(SheetDescription, { children: "Tap a block to add it to the bottom of your draft." })
7681
+ ] }),
7682
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ jsxRuntime.jsx(
7683
+ Palette,
7684
+ {
7685
+ onAddBlock: (block) => {
7686
+ addBlock(block);
7687
+ setPaletteOpen(false);
7688
+ },
7689
+ sections: paletteSections,
7690
+ showSearch: showPaletteSearch,
7691
+ searchPlaceholder: paletteSearchPlaceholder,
7692
+ defaultOpenSections,
7693
+ variant: "sheet"
7694
+ }
7695
+ ) })
7696
+ ]
7697
+ }
7698
+ ) }),
6747
7699
  /* @__PURE__ */ jsxRuntime.jsx(JsonDrawer, { open: jsonOpen, onOpenChange: setJsonOpen, blocks: blockPayloads, onApply: replaceAll }),
6748
7700
  /* @__PURE__ */ jsxRuntime.jsx(
6749
7701
  SendDialog,
@@ -6876,11 +7828,11 @@ function TemplatePicker({
6876
7828
  }) {
6877
7829
  const visible = surface ? templates.filter((t) => t.surface === surface) : templates;
6878
7830
  const { grouped, sections } = groupByCategory(visible);
6879
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex h-full w-full flex-col gap-8 overflow-y-auto bg-muted/30 p-8", className), children: [
6880
- heading ? /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-semibold tracking-tight text-foreground", children: heading }) : null,
6881
- visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground/75", children: emptyLabel }) : sections.map((section) => /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex flex-col gap-4", children: [
7831
+ return /* @__PURE__ */ jsxRuntime.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: [
7832
+ heading ? /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold tracking-tight text-foreground sm:text-xl", children: heading }) : null,
7833
+ visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground/75", children: emptyLabel }) : sections.map((section) => /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex flex-col gap-3 sm:gap-4", children: [
6882
7834
  grouped ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs font-semibold tracking-wider text-foreground/60 uppercase", children: section.category }) : null,
6883
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-[repeat(auto-fill,minmax(280px,1fr))] gap-5", children: section.templates.map((template) => /* @__PURE__ */ jsxRuntime.jsx(TemplateCard, { template, theme, onSelect }, template.id)) })
7835
+ /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(TemplateCard, { template, theme, onSelect }, template.id)) })
6884
7836
  ] }, section.category))
6885
7837
  ] });
6886
7838
  }