@tightknitai/block-kitchen 0.8.8 → 0.8.9
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/helpers.d.cts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.cjs +478 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +479 -106
- package/dist/index.js.map +1 -1
- package/dist/{palette-5_Tx97Gk.d.cts → palette-DBTHRygt.d.cts} +7 -0
- package/dist/{palette-5_Tx97Gk.d.ts → palette-DBTHRygt.d.ts} +7 -0
- package/dist/palette.d.cts +1 -1
- package/dist/palette.d.ts +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -53,6 +53,34 @@ var Link__default = /*#__PURE__*/_interopDefault(Link);
|
|
|
53
53
|
var StarterKit__default = /*#__PURE__*/_interopDefault(StarterKit);
|
|
54
54
|
|
|
55
55
|
// src/components/block-kitchen.tsx
|
|
56
|
+
|
|
57
|
+
// src/lib/container-blocks.ts
|
|
58
|
+
var CONTAINER_CHILD_TYPES = /* @__PURE__ */ new Set([
|
|
59
|
+
"actions",
|
|
60
|
+
"context",
|
|
61
|
+
"divider",
|
|
62
|
+
"header",
|
|
63
|
+
"image",
|
|
64
|
+
"input",
|
|
65
|
+
"rich_text",
|
|
66
|
+
"section",
|
|
67
|
+
"table",
|
|
68
|
+
"video"
|
|
69
|
+
]);
|
|
70
|
+
var MAX_CONTAINER_CHILDREN = 10;
|
|
71
|
+
function isContainerChildType(type) {
|
|
72
|
+
return CONTAINER_CHILD_TYPES.has(type);
|
|
73
|
+
}
|
|
74
|
+
var BODY_PREFIX = "container-body:";
|
|
75
|
+
function containerBodyId(containerId) {
|
|
76
|
+
return `${BODY_PREFIX}${containerId}`;
|
|
77
|
+
}
|
|
78
|
+
function parseContainerBodyId(id) {
|
|
79
|
+
if (typeof id !== "string" || !id.startsWith(BODY_PREFIX)) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
return id.slice(BODY_PREFIX.length);
|
|
83
|
+
}
|
|
56
84
|
function makeEmojiHook(byName) {
|
|
57
85
|
return (data, parse) => {
|
|
58
86
|
const entry = byName.get(data.name);
|
|
@@ -2012,9 +2040,52 @@ function useBlockKitValidation(blocks, surface) {
|
|
|
2012
2040
|
}, [blocks, surface]);
|
|
2013
2041
|
return state;
|
|
2014
2042
|
}
|
|
2043
|
+
function mirror(node) {
|
|
2044
|
+
if (!node.children) {
|
|
2045
|
+
return node;
|
|
2046
|
+
}
|
|
2047
|
+
return {
|
|
2048
|
+
...node,
|
|
2049
|
+
block: { ...node.block, child_blocks: node.children.map((c) => c.block) }
|
|
2050
|
+
};
|
|
2051
|
+
}
|
|
2015
2052
|
function wrap(block) {
|
|
2053
|
+
if (block.type === "container") {
|
|
2054
|
+
const children = (block.child_blocks ?? []).map(wrap);
|
|
2055
|
+
return mirror({ id: nanoid.nanoid(8), block, children });
|
|
2056
|
+
}
|
|
2016
2057
|
return { id: nanoid.nanoid(8), block };
|
|
2017
2058
|
}
|
|
2059
|
+
function cloneNode(node) {
|
|
2060
|
+
if (node.children) {
|
|
2061
|
+
return mirror({ id: nanoid.nanoid(8), block: structuredClone(node.block), children: node.children.map(cloneNode) });
|
|
2062
|
+
}
|
|
2063
|
+
return { id: nanoid.nanoid(8), block: structuredClone(node.block) };
|
|
2064
|
+
}
|
|
2065
|
+
function applyUpdate(node, block) {
|
|
2066
|
+
if (node.children) {
|
|
2067
|
+
return mirror({ ...node, block });
|
|
2068
|
+
}
|
|
2069
|
+
return { ...node, block };
|
|
2070
|
+
}
|
|
2071
|
+
function locate(blocks, id) {
|
|
2072
|
+
const top = blocks.findIndex((b) => b.id === id);
|
|
2073
|
+
if (top !== -1) {
|
|
2074
|
+
return { kind: "top", index: top };
|
|
2075
|
+
}
|
|
2076
|
+
for (const block of blocks) {
|
|
2077
|
+
if (block.children) {
|
|
2078
|
+
const idx = block.children.findIndex((c) => c.id === id);
|
|
2079
|
+
if (idx !== -1) {
|
|
2080
|
+
return { kind: "child", parentId: block.id, index: idx };
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
return null;
|
|
2085
|
+
}
|
|
2086
|
+
function withChildren(blocks, parentId, fn) {
|
|
2087
|
+
return blocks.map((b) => b.id === parentId && b.children ? mirror({ ...b, children: fn(b.children) }) : b);
|
|
2088
|
+
}
|
|
2018
2089
|
function useBlockKitchenState({
|
|
2019
2090
|
initialBlocks,
|
|
2020
2091
|
onChange
|
|
@@ -2035,41 +2106,113 @@ function useBlockKitchenState({
|
|
|
2035
2106
|
const addBlock = React.useCallback((block, atIndex) => {
|
|
2036
2107
|
setBlocks((prev) => {
|
|
2037
2108
|
const next = [...prev];
|
|
2038
|
-
const inserted = wrap(block);
|
|
2039
2109
|
const idx = atIndex === void 0 ? next.length : Math.max(0, Math.min(atIndex, next.length));
|
|
2040
|
-
next.splice(idx, 0,
|
|
2110
|
+
next.splice(idx, 0, wrap(block));
|
|
2041
2111
|
return next;
|
|
2042
2112
|
});
|
|
2043
2113
|
}, []);
|
|
2114
|
+
const addChild = React.useCallback((parentId, block, atIndex) => {
|
|
2115
|
+
if (!isContainerChildType(block.type)) {
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2118
|
+
setBlocks(
|
|
2119
|
+
(prev) => withChildren(prev, parentId, (children) => {
|
|
2120
|
+
if (children.length >= MAX_CONTAINER_CHILDREN) {
|
|
2121
|
+
return children;
|
|
2122
|
+
}
|
|
2123
|
+
const next = [...children];
|
|
2124
|
+
const idx = atIndex === void 0 ? next.length : Math.max(0, Math.min(atIndex, next.length));
|
|
2125
|
+
next.splice(idx, 0, wrap(block));
|
|
2126
|
+
return next;
|
|
2127
|
+
})
|
|
2128
|
+
);
|
|
2129
|
+
}, []);
|
|
2044
2130
|
const updateBlock = React.useCallback((id, block) => {
|
|
2045
|
-
setBlocks(
|
|
2131
|
+
setBlocks(
|
|
2132
|
+
(prev) => prev.map((b) => {
|
|
2133
|
+
if (b.id === id) {
|
|
2134
|
+
return applyUpdate(b, block);
|
|
2135
|
+
}
|
|
2136
|
+
if (b.children?.some((c) => c.id === id)) {
|
|
2137
|
+
return mirror({ ...b, children: b.children.map((c) => c.id === id ? applyUpdate(c, block) : c) });
|
|
2138
|
+
}
|
|
2139
|
+
return b;
|
|
2140
|
+
})
|
|
2141
|
+
);
|
|
2046
2142
|
}, []);
|
|
2047
2143
|
const removeBlock = React.useCallback((id) => {
|
|
2048
|
-
setBlocks((prev) =>
|
|
2144
|
+
setBlocks((prev) => {
|
|
2145
|
+
if (prev.some((b) => b.id === id)) {
|
|
2146
|
+
return prev.filter((b) => b.id !== id);
|
|
2147
|
+
}
|
|
2148
|
+
return prev.map(
|
|
2149
|
+
(b) => b.children?.some((c) => c.id === id) ? mirror({ ...b, children: b.children.filter((c) => c.id !== id) }) : b
|
|
2150
|
+
);
|
|
2151
|
+
});
|
|
2049
2152
|
}, []);
|
|
2050
2153
|
const duplicateBlock = React.useCallback((id) => {
|
|
2051
2154
|
setBlocks((prev) => {
|
|
2052
|
-
const
|
|
2053
|
-
if (
|
|
2155
|
+
const loc = locate(prev, id);
|
|
2156
|
+
if (!loc) {
|
|
2054
2157
|
return prev;
|
|
2055
2158
|
}
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2159
|
+
if (loc.kind === "top") {
|
|
2160
|
+
const next = [...prev];
|
|
2161
|
+
next.splice(loc.index + 1, 0, cloneNode(prev[loc.index]));
|
|
2162
|
+
return next;
|
|
2163
|
+
}
|
|
2164
|
+
return withChildren(prev, loc.parentId, (children) => {
|
|
2165
|
+
const next = [...children];
|
|
2166
|
+
next.splice(loc.index + 1, 0, cloneNode(children[loc.index]));
|
|
2167
|
+
return next;
|
|
2168
|
+
});
|
|
2060
2169
|
});
|
|
2061
2170
|
}, []);
|
|
2062
2171
|
const reorderBlock = React.useCallback((fromId, toIndex) => {
|
|
2063
2172
|
setBlocks((prev) => {
|
|
2064
|
-
const
|
|
2065
|
-
if (
|
|
2173
|
+
const loc = locate(prev, fromId);
|
|
2174
|
+
if (!loc) {
|
|
2066
2175
|
return prev;
|
|
2067
2176
|
}
|
|
2068
|
-
const
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2177
|
+
const reorder = (list) => {
|
|
2178
|
+
const next = [...list];
|
|
2179
|
+
const [moved] = next.splice(loc.index, 1);
|
|
2180
|
+
next.splice(Math.max(0, Math.min(toIndex, next.length)), 0, moved);
|
|
2181
|
+
return next;
|
|
2182
|
+
};
|
|
2183
|
+
if (loc.kind === "top") {
|
|
2184
|
+
return reorder(prev);
|
|
2185
|
+
}
|
|
2186
|
+
return withChildren(prev, loc.parentId, reorder);
|
|
2187
|
+
});
|
|
2188
|
+
}, []);
|
|
2189
|
+
const moveBlock = React.useCallback((activeId, target) => {
|
|
2190
|
+
setBlocks((prev) => {
|
|
2191
|
+
const loc = locate(prev, activeId);
|
|
2192
|
+
if (!loc) {
|
|
2193
|
+
return prev;
|
|
2194
|
+
}
|
|
2195
|
+
const moved = loc.kind === "top" ? prev[loc.index] : prev.find((b) => b.id === loc.parentId)?.children?.[loc.index];
|
|
2196
|
+
if (!moved) {
|
|
2197
|
+
return prev;
|
|
2198
|
+
}
|
|
2199
|
+
if (target.kind === "container") {
|
|
2200
|
+
if (moved.children || !isContainerChildType(moved.block.type)) {
|
|
2201
|
+
return prev;
|
|
2202
|
+
}
|
|
2203
|
+
const sameContainer = loc.kind === "child" && loc.parentId === target.parentId;
|
|
2204
|
+
const destCount = prev.find((b) => b.id === target.parentId)?.children?.length ?? 0;
|
|
2205
|
+
if (!sameContainer && destCount >= MAX_CONTAINER_CHILDREN) {
|
|
2206
|
+
return prev;
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
const detached = loc.kind === "top" ? prev.filter((_, i) => i !== loc.index) : withChildren(prev, loc.parentId, (children) => children.filter((_, i) => i !== loc.index));
|
|
2210
|
+
const insert = (list) => {
|
|
2211
|
+
const next = [...list];
|
|
2212
|
+
next.splice(Math.max(0, Math.min(target.index, next.length)), 0, moved);
|
|
2213
|
+
return next;
|
|
2214
|
+
};
|
|
2215
|
+
return target.kind === "container" ? withChildren(detached, target.parentId, insert) : insert(detached);
|
|
2073
2216
|
});
|
|
2074
2217
|
}, []);
|
|
2075
2218
|
const replaceAll = React.useCallback((newBlocks) => {
|
|
@@ -2078,10 +2221,12 @@ function useBlockKitchenState({
|
|
|
2078
2221
|
return {
|
|
2079
2222
|
blocks,
|
|
2080
2223
|
addBlock,
|
|
2224
|
+
addChild,
|
|
2081
2225
|
updateBlock,
|
|
2082
2226
|
removeBlock,
|
|
2083
2227
|
duplicateBlock,
|
|
2084
2228
|
reorderBlock,
|
|
2229
|
+
moveBlock,
|
|
2085
2230
|
replaceAll
|
|
2086
2231
|
};
|
|
2087
2232
|
}
|
|
@@ -3590,22 +3735,10 @@ function CarouselEditor({ block, onChange }) {
|
|
|
3590
3735
|
] })
|
|
3591
3736
|
] });
|
|
3592
3737
|
}
|
|
3593
|
-
var MAX_CHILDREN = 10;
|
|
3594
3738
|
var WIDTHS = ["narrow", "standard", "wide", "full"];
|
|
3595
3739
|
function ContainerEditor({ block, onChange }) {
|
|
3596
|
-
const children = block.child_blocks ?? [];
|
|
3597
3740
|
const iconUrl = block.icon && "image_url" in block.icon ? block.icon.image_url ?? "" : "";
|
|
3598
3741
|
const iconAlt = block.icon?.alt_text ?? "";
|
|
3599
|
-
const removeChildAt = (idx) => {
|
|
3600
|
-
onChange({ ...block, child_blocks: children.filter((_, i) => i !== idx) });
|
|
3601
|
-
};
|
|
3602
|
-
const addChild = () => {
|
|
3603
|
-
const child = {
|
|
3604
|
-
type: "section",
|
|
3605
|
-
text: { type: "mrkdwn", text: "New block." }
|
|
3606
|
-
};
|
|
3607
|
-
onChange({ ...block, child_blocks: [...children, child] });
|
|
3608
|
-
};
|
|
3609
3742
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
3610
3743
|
/* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Title", help: "Heading shown at the top of the container.", htmlFor: "container-title", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3611
3744
|
Input,
|
|
@@ -3680,42 +3813,7 @@ function ContainerEditor({ block, onChange }) {
|
|
|
3680
3813
|
onChange: (checked) => onChange({ ...block, default_collapsed: checked || void 0 })
|
|
3681
3814
|
}
|
|
3682
3815
|
),
|
|
3683
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3684
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: "Child blocks" }),
|
|
3685
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "A container holds 1-10 blocks. To edit a child's content, use the View JSON drawer." }),
|
|
3686
|
-
children.map((child, idx) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 rounded-md border bg-muted/20 px-3 py-2", children: [
|
|
3687
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-foreground", children: [
|
|
3688
|
-
idx + 1,
|
|
3689
|
-
". ",
|
|
3690
|
-
labelForBlockType(child.type)
|
|
3691
|
-
] }),
|
|
3692
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3693
|
-
"button",
|
|
3694
|
-
{
|
|
3695
|
-
type: "button",
|
|
3696
|
-
"aria-label": "Remove child block",
|
|
3697
|
-
onClick: () => removeChildAt(idx),
|
|
3698
|
-
disabled: children.length <= 1,
|
|
3699
|
-
className: "rounded p-1 text-muted-foreground hover:bg-destructive/10 hover:text-destructive disabled:cursor-not-allowed disabled:opacity-40",
|
|
3700
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" })
|
|
3701
|
-
}
|
|
3702
|
-
)
|
|
3703
|
-
] }, idx)),
|
|
3704
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3705
|
-
Button,
|
|
3706
|
-
{
|
|
3707
|
-
type: "button",
|
|
3708
|
-
size: "sm",
|
|
3709
|
-
onClick: addChild,
|
|
3710
|
-
disabled: children.length >= MAX_CHILDREN,
|
|
3711
|
-
className: "self-start",
|
|
3712
|
-
children: [
|
|
3713
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-3.5 w-3.5" }),
|
|
3714
|
-
" Add block"
|
|
3715
|
-
]
|
|
3716
|
-
}
|
|
3717
|
-
)
|
|
3718
|
-
] })
|
|
3816
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "Drag blocks into the container on the canvas to add them (1-10), and drag them out to remove. Click a child to edit it." })
|
|
3719
3817
|
] });
|
|
3720
3818
|
}
|
|
3721
3819
|
function Checkbox({
|
|
@@ -8286,6 +8384,225 @@ function RichTextInlineEditor({
|
|
|
8286
8384
|
}
|
|
8287
8385
|
);
|
|
8288
8386
|
}
|
|
8387
|
+
function ContainerRow({
|
|
8388
|
+
builderBlock,
|
|
8389
|
+
previewHooks,
|
|
8390
|
+
previewTheme,
|
|
8391
|
+
errorsByBlockId,
|
|
8392
|
+
openBlockId,
|
|
8393
|
+
onOpenBlockChange,
|
|
8394
|
+
onUpdate,
|
|
8395
|
+
onDuplicate,
|
|
8396
|
+
onDelete,
|
|
8397
|
+
onReorder,
|
|
8398
|
+
index,
|
|
8399
|
+
total,
|
|
8400
|
+
isPaletteDrag = false
|
|
8401
|
+
}) {
|
|
8402
|
+
const { id } = builderBlock;
|
|
8403
|
+
const block = builderBlock.block;
|
|
8404
|
+
const children = builderBlock.children ?? [];
|
|
8405
|
+
const errors = errorsByBlockId?.get(id);
|
|
8406
|
+
const hasErrors = !!errors && errors.length > 0;
|
|
8407
|
+
const isOpen = openBlockId === id;
|
|
8408
|
+
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = sortable.useSortable({ id });
|
|
8409
|
+
const { role: _dndRole, tabIndex: _dndTabIndex, ...sortableA11yAttrs } = attributes;
|
|
8410
|
+
const { setNodeRef: setBodyRef, isOver: isBodyOver } = core.useDroppable({ id: containerBodyId(id) });
|
|
8411
|
+
const style = { transform: utilities.CSS.Transform.toString(transform), transition };
|
|
8412
|
+
const icon = block.icon && "image_url" in block.icon ? block.icon.image_url : void 0;
|
|
8413
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8414
|
+
"div",
|
|
8415
|
+
{
|
|
8416
|
+
ref: setNodeRef,
|
|
8417
|
+
style,
|
|
8418
|
+
className: cn("group/container relative mb-2 last:mb-0 hover:z-10", isDragging && "opacity-40"),
|
|
8419
|
+
children: [
|
|
8420
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8421
|
+
"div",
|
|
8422
|
+
{
|
|
8423
|
+
className: cn(
|
|
8424
|
+
"overflow-hidden rounded-md border bg-card transition-shadow",
|
|
8425
|
+
hasErrors ? "border-destructive/60" : "border-border"
|
|
8426
|
+
),
|
|
8427
|
+
children: [
|
|
8428
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: isOpen, onOpenChange: (open) => onOpenBlockChange?.(open ? id : null), children: [
|
|
8429
|
+
/* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8430
|
+
"div",
|
|
8431
|
+
{
|
|
8432
|
+
role: "button",
|
|
8433
|
+
tabIndex: 0,
|
|
8434
|
+
"aria-label": "Edit container",
|
|
8435
|
+
...sortableA11yAttrs,
|
|
8436
|
+
...listeners,
|
|
8437
|
+
onKeyDown: (e) => {
|
|
8438
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
8439
|
+
e.preventDefault();
|
|
8440
|
+
onOpenBlockChange?.(!isOpen ? id : null);
|
|
8441
|
+
}
|
|
8442
|
+
},
|
|
8443
|
+
className: "flex w-full cursor-grab items-center gap-2 border-b bg-muted/40 px-3 py-2 text-left transition-colors hover:bg-muted active:cursor-grabbing",
|
|
8444
|
+
children: [
|
|
8445
|
+
icon ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: icon, alt: "", "aria-hidden": "true", className: "h-5 w-5 shrink-0 rounded object-cover" }) : null,
|
|
8446
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
|
|
8447
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs font-semibold text-foreground", children: block.title?.text || "Container" }),
|
|
8448
|
+
block.subtitle?.text ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[11px] text-muted-foreground", children: block.subtitle.text }) : null
|
|
8449
|
+
] }),
|
|
8450
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto shrink-0 text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: "Container" })
|
|
8451
|
+
]
|
|
8452
|
+
}
|
|
8453
|
+
) }),
|
|
8454
|
+
/* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "w-[min(32rem,calc(100vw-1.5rem))] sm:w-[32rem]", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(BlockEditor, { block, errors, onChange: (next) => onUpdate(id, next) }) })
|
|
8455
|
+
] }),
|
|
8456
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8457
|
+
"div",
|
|
8458
|
+
{
|
|
8459
|
+
ref: setBodyRef,
|
|
8460
|
+
className: cn(
|
|
8461
|
+
"flex flex-col gap-2 p-3 transition-colors",
|
|
8462
|
+
isPaletteDrag && "outline-2 -outline-offset-2 outline-dashed outline-primary/40",
|
|
8463
|
+
isPaletteDrag && isBodyOver && "bg-primary/5"
|
|
8464
|
+
),
|
|
8465
|
+
children: children.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8466
|
+
"div",
|
|
8467
|
+
{
|
|
8468
|
+
className: cn(
|
|
8469
|
+
"flex items-center justify-center rounded-md border border-dashed px-3 py-6 text-center text-[11px] transition-colors",
|
|
8470
|
+
isBodyOver ? "border-primary/60 text-primary" : "border-border text-muted-foreground"
|
|
8471
|
+
),
|
|
8472
|
+
children: "Drag blocks here"
|
|
8473
|
+
}
|
|
8474
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(sortable.SortableContext, { items: children.map((c) => c.id), strategy: sortable.verticalListSortingStrategy, children: [
|
|
8475
|
+
children.map((child, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8476
|
+
BlockRow,
|
|
8477
|
+
{
|
|
8478
|
+
builderBlock: child,
|
|
8479
|
+
previewHooks,
|
|
8480
|
+
previewTheme,
|
|
8481
|
+
errors: errorsByBlockId?.get(child.id),
|
|
8482
|
+
isOpen: openBlockId === child.id,
|
|
8483
|
+
onOpenChange: (open) => onOpenBlockChange?.(open ? child.id : null),
|
|
8484
|
+
onUpdate,
|
|
8485
|
+
onDuplicate,
|
|
8486
|
+
onDelete,
|
|
8487
|
+
index: idx,
|
|
8488
|
+
total: children.length,
|
|
8489
|
+
onReorder,
|
|
8490
|
+
isPaletteDrag
|
|
8491
|
+
},
|
|
8492
|
+
child.id
|
|
8493
|
+
)),
|
|
8494
|
+
isPaletteDrag && isBodyOver ? /* @__PURE__ */ jsxRuntime.jsx(DropIndicator, {}) : null
|
|
8495
|
+
] })
|
|
8496
|
+
}
|
|
8497
|
+
)
|
|
8498
|
+
]
|
|
8499
|
+
}
|
|
8500
|
+
),
|
|
8501
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8502
|
+
"div",
|
|
8503
|
+
{
|
|
8504
|
+
className: cn(
|
|
8505
|
+
"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",
|
|
8506
|
+
hasErrors ? "opacity-100" : "opacity-0 group-hover/container:opacity-100 group-focus-within/container:opacity-100"
|
|
8507
|
+
),
|
|
8508
|
+
children: [
|
|
8509
|
+
hasErrors ? /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
8510
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8511
|
+
"button",
|
|
8512
|
+
{
|
|
8513
|
+
type: "button",
|
|
8514
|
+
"aria-label": `Show ${errors.length} validation ${errors.length === 1 ? "issue" : "issues"}`,
|
|
8515
|
+
onClick: () => onOpenBlockChange?.(id),
|
|
8516
|
+
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",
|
|
8517
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3.5 w-3.5" })
|
|
8518
|
+
}
|
|
8519
|
+
) }),
|
|
8520
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", align: "end", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "flex flex-col gap-0.5", children: [
|
|
8521
|
+
errors.slice(0, 4).map((err, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: err }, i)),
|
|
8522
|
+
errors.length > 4 ? /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "text-muted-foreground", children: [
|
|
8523
|
+
"and ",
|
|
8524
|
+
errors.length - 4,
|
|
8525
|
+
" more"
|
|
8526
|
+
] }) : null
|
|
8527
|
+
] }) })
|
|
8528
|
+
] }) : null,
|
|
8529
|
+
onReorder && typeof index === "number" && typeof total === "number" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8530
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Move up", disabled: index === 0, onClick: () => onReorder(id, index - 1), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-3.5 w-3.5" }) }),
|
|
8531
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Move down", disabled: index >= total - 1, onClick: () => onReorder(id, index + 1), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "h-3.5 w-3.5" }) })
|
|
8532
|
+
] }) : null,
|
|
8533
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Edit", onClick: () => onOpenBlockChange?.(id), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-3.5 w-3.5" }) }),
|
|
8534
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Duplicate", onClick: () => onDuplicate(id), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-3.5 w-3.5" }) }),
|
|
8535
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Delete", destructive: true, onClick: () => onDelete(id), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" }) })
|
|
8536
|
+
]
|
|
8537
|
+
}
|
|
8538
|
+
),
|
|
8539
|
+
/* @__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: [
|
|
8540
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[11px] font-medium text-muted-foreground", children: "Container" }),
|
|
8541
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
8542
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8543
|
+
"button",
|
|
8544
|
+
{
|
|
8545
|
+
type: "button",
|
|
8546
|
+
"aria-label": "Edit container",
|
|
8547
|
+
onClick: () => onOpenBlockChange?.(id),
|
|
8548
|
+
className: "flex h-9 w-9 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
8549
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-4 w-4" })
|
|
8550
|
+
}
|
|
8551
|
+
),
|
|
8552
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8553
|
+
"button",
|
|
8554
|
+
{
|
|
8555
|
+
type: "button",
|
|
8556
|
+
"aria-label": "Duplicate container",
|
|
8557
|
+
onClick: () => onDuplicate(id),
|
|
8558
|
+
className: "flex h-9 w-9 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
8559
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-4 w-4" })
|
|
8560
|
+
}
|
|
8561
|
+
),
|
|
8562
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8563
|
+
"button",
|
|
8564
|
+
{
|
|
8565
|
+
type: "button",
|
|
8566
|
+
"aria-label": "Delete container",
|
|
8567
|
+
onClick: () => onDelete(id),
|
|
8568
|
+
className: "flex h-9 w-9 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
|
|
8569
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-4 w-4" })
|
|
8570
|
+
}
|
|
8571
|
+
)
|
|
8572
|
+
] })
|
|
8573
|
+
] })
|
|
8574
|
+
]
|
|
8575
|
+
}
|
|
8576
|
+
);
|
|
8577
|
+
}
|
|
8578
|
+
function ToolbarButton2({
|
|
8579
|
+
label,
|
|
8580
|
+
onClick,
|
|
8581
|
+
disabled,
|
|
8582
|
+
destructive,
|
|
8583
|
+
children
|
|
8584
|
+
}) {
|
|
8585
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
8586
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8587
|
+
"button",
|
|
8588
|
+
{
|
|
8589
|
+
type: "button",
|
|
8590
|
+
"aria-label": label,
|
|
8591
|
+
disabled,
|
|
8592
|
+
onClick,
|
|
8593
|
+
className: cn(
|
|
8594
|
+
"flex h-6 w-6 items-center justify-center rounded text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-40",
|
|
8595
|
+
destructive ? "hover:bg-destructive/10 hover:text-destructive" : "hover:bg-accent hover:text-foreground"
|
|
8596
|
+
),
|
|
8597
|
+
children
|
|
8598
|
+
}
|
|
8599
|
+
) }),
|
|
8600
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", children: label })
|
|
8601
|
+
] });
|
|
8602
|
+
}
|
|
8603
|
+
function DropIndicator() {
|
|
8604
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": "true", className: "pointer-events-none relative my-1 h-0.5 w-full rounded-full bg-primary", 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)]" }) });
|
|
8605
|
+
}
|
|
8289
8606
|
var SURFACE_DROPPABLE_ID = "builder-surface";
|
|
8290
8607
|
function Surface({
|
|
8291
8608
|
blocks,
|
|
@@ -8317,26 +8634,46 @@ function Surface({
|
|
|
8317
8634
|
isPaletteDrag && isOver && (isDark ? "bg-[#2c3036]" : "bg-[#eaf0ff]")
|
|
8318
8635
|
),
|
|
8319
8636
|
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: [
|
|
8320
|
-
blocks.map(
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8637
|
+
blocks.map(
|
|
8638
|
+
(block, idx) => block.block.type === "container" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8639
|
+
ContainerRow,
|
|
8640
|
+
{
|
|
8641
|
+
builderBlock: block,
|
|
8642
|
+
previewHooks,
|
|
8643
|
+
previewTheme,
|
|
8644
|
+
errorsByBlockId,
|
|
8645
|
+
openBlockId,
|
|
8646
|
+
onOpenBlockChange,
|
|
8647
|
+
onUpdate,
|
|
8648
|
+
onDuplicate,
|
|
8649
|
+
onDelete,
|
|
8650
|
+
index: idx,
|
|
8651
|
+
total: blocks.length,
|
|
8652
|
+
onReorder,
|
|
8653
|
+
isPaletteDrag
|
|
8654
|
+
},
|
|
8655
|
+
block.id
|
|
8656
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
8657
|
+
BlockRow,
|
|
8658
|
+
{
|
|
8659
|
+
builderBlock: block,
|
|
8660
|
+
previewHooks,
|
|
8661
|
+
previewTheme,
|
|
8662
|
+
errors: errorsByBlockId?.get(block.id),
|
|
8663
|
+
isOpen: openBlockId === block.id,
|
|
8664
|
+
onOpenChange: (open) => onOpenBlockChange?.(open ? block.id : null),
|
|
8665
|
+
onUpdate,
|
|
8666
|
+
onDuplicate,
|
|
8667
|
+
onDelete,
|
|
8668
|
+
index: idx,
|
|
8669
|
+
total: blocks.length,
|
|
8670
|
+
onReorder,
|
|
8671
|
+
isPaletteDrag
|
|
8672
|
+
},
|
|
8673
|
+
block.id
|
|
8674
|
+
)
|
|
8675
|
+
),
|
|
8676
|
+
showEndDropZone ? /* @__PURE__ */ jsxRuntime.jsx(DropIndicator2, {}) : null
|
|
8340
8677
|
] })
|
|
8341
8678
|
}
|
|
8342
8679
|
);
|
|
@@ -8576,7 +8913,7 @@ function EmptyState({
|
|
|
8576
8913
|
}
|
|
8577
8914
|
);
|
|
8578
8915
|
}
|
|
8579
|
-
function
|
|
8916
|
+
function DropIndicator2() {
|
|
8580
8917
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": "true", className: "pointer-events-none relative my-1 h-0.5 w-full rounded-full bg-primary", 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)]" }) });
|
|
8581
8918
|
}
|
|
8582
8919
|
var THEME_OPTIONS = [
|
|
@@ -8939,9 +9276,18 @@ function BlockKitchen(props) {
|
|
|
8939
9276
|
}, [palette, disabledBlockTypes]);
|
|
8940
9277
|
const variantById = React.useMemo(() => buildVariantById(paletteSections), [paletteSections]);
|
|
8941
9278
|
const allowedSurfaces = allowedSurfacesProp && allowedSurfacesProp.length > 0 ? allowedSurfacesProp : ["message"];
|
|
8942
|
-
const { blocks, addBlock, updateBlock, removeBlock, duplicateBlock, reorderBlock, replaceAll } = useBlockKitchenState(
|
|
8943
|
-
|
|
8944
|
-
|
|
9279
|
+
const { blocks, addBlock, addChild, updateBlock, removeBlock, duplicateBlock, reorderBlock, moveBlock, replaceAll } = useBlockKitchenState({ initialBlocks, onChange });
|
|
9280
|
+
const childParentById = React.useMemo(() => {
|
|
9281
|
+
const map = /* @__PURE__ */ new Map();
|
|
9282
|
+
for (const top of blocks) {
|
|
9283
|
+
if (top.children) {
|
|
9284
|
+
for (const child of top.children) {
|
|
9285
|
+
map.set(child.id, top.id);
|
|
9286
|
+
}
|
|
9287
|
+
}
|
|
9288
|
+
}
|
|
9289
|
+
return map;
|
|
9290
|
+
}, [blocks]);
|
|
8945
9291
|
const [jsonOpen, setJsonOpen] = React.useState(false);
|
|
8946
9292
|
const [sendOpen, setSendOpen] = React.useState(false);
|
|
8947
9293
|
const [issuesOpen, setIssuesOpen] = React.useState(false);
|
|
@@ -8966,14 +9312,22 @@ function BlockKitchen(props) {
|
|
|
8966
9312
|
core.useSensor(core.TouchSensor, { activationConstraint: { delay: 150, tolerance: 8 } }),
|
|
8967
9313
|
core.useSensor(core.KeyboardSensor, { coordinateGetter: sortable.sortableKeyboardCoordinates })
|
|
8968
9314
|
);
|
|
8969
|
-
const collisionDetection = React.useCallback(
|
|
8970
|
-
|
|
8971
|
-
|
|
8972
|
-
|
|
8973
|
-
|
|
8974
|
-
|
|
8975
|
-
|
|
8976
|
-
|
|
9315
|
+
const collisionDetection = React.useCallback(
|
|
9316
|
+
(args) => {
|
|
9317
|
+
const hits = core.pointerWithin(args);
|
|
9318
|
+
if (hits.length > 0) {
|
|
9319
|
+
const child = hits.find((c) => childParentById.has(c.id));
|
|
9320
|
+
if (child) return [child];
|
|
9321
|
+
const body = hits.find((c) => parseContainerBodyId(c.id) !== null);
|
|
9322
|
+
if (body) return [body];
|
|
9323
|
+
const block = hits.find((c) => c.id !== SURFACE_DROPPABLE_ID && parseContainerBodyId(c.id) === null);
|
|
9324
|
+
if (block) return [block];
|
|
9325
|
+
return hits;
|
|
9326
|
+
}
|
|
9327
|
+
return core.closestCenter(args);
|
|
9328
|
+
},
|
|
9329
|
+
[childParentById]
|
|
9330
|
+
);
|
|
8977
9331
|
const handleDragStart = React.useCallback((event) => {
|
|
8978
9332
|
const variantId = parsePaletteDragId(event.active.id);
|
|
8979
9333
|
setActivePaletteVariantId(variantId);
|
|
@@ -8985,24 +9339,43 @@ function BlockKitchen(props) {
|
|
|
8985
9339
|
if (!over) {
|
|
8986
9340
|
return;
|
|
8987
9341
|
}
|
|
9342
|
+
const overId = over.id;
|
|
9343
|
+
let target;
|
|
9344
|
+
const bodyParent = parseContainerBodyId(overId);
|
|
9345
|
+
const childParent = childParentById.get(overId);
|
|
9346
|
+
if (overId === SURFACE_DROPPABLE_ID) {
|
|
9347
|
+
target = { kind: "top", index: blocks.length };
|
|
9348
|
+
} else if (bodyParent) {
|
|
9349
|
+
const count = blocks.find((b) => b.id === bodyParent)?.children?.length ?? 0;
|
|
9350
|
+
target = { kind: "container", parentId: bodyParent, index: count };
|
|
9351
|
+
} else if (childParent) {
|
|
9352
|
+
const siblings = blocks.find((b) => b.id === childParent)?.children ?? [];
|
|
9353
|
+
target = { kind: "container", parentId: childParent, index: siblings.findIndex((c) => c.id === overId) };
|
|
9354
|
+
} else {
|
|
9355
|
+
const topIndex = blocks.findIndex((b) => b.id === overId);
|
|
9356
|
+
target = topIndex === -1 ? null : { kind: "top", index: topIndex };
|
|
9357
|
+
}
|
|
9358
|
+
if (!target) {
|
|
9359
|
+
return;
|
|
9360
|
+
}
|
|
8988
9361
|
const variantId = parsePaletteDragId(active.id);
|
|
8989
9362
|
if (variantId) {
|
|
8990
9363
|
const variant = variantById.get(variantId);
|
|
8991
9364
|
if (!variant) {
|
|
8992
9365
|
return;
|
|
8993
9366
|
}
|
|
8994
|
-
|
|
8995
|
-
|
|
9367
|
+
if (target.kind === "container") {
|
|
9368
|
+
addChild(target.parentId, variant.factory(), target.index);
|
|
9369
|
+
} else {
|
|
9370
|
+
addBlock(variant.factory(), target.index);
|
|
9371
|
+
}
|
|
8996
9372
|
return;
|
|
8997
9373
|
}
|
|
8998
|
-
if (active.id !==
|
|
8999
|
-
|
|
9000
|
-
if (overIndex !== -1) {
|
|
9001
|
-
reorderBlock(active.id, overIndex);
|
|
9002
|
-
}
|
|
9374
|
+
if (active.id !== overId) {
|
|
9375
|
+
moveBlock(active.id, target);
|
|
9003
9376
|
}
|
|
9004
9377
|
},
|
|
9005
|
-
[addBlock, blocks,
|
|
9378
|
+
[addBlock, addChild, blocks, childParentById, moveBlock, variantById]
|
|
9006
9379
|
);
|
|
9007
9380
|
const handleDragCancel = React.useCallback(() => {
|
|
9008
9381
|
setActivePaletteVariantId(null);
|