@tightknitai/block-kitchen 0.10.0 → 0.10.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/README.md +31 -0
- package/dist/index.cjs +403 -198
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +404 -199
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useSensors, useSensor, PointerSensor, TouchSensor, KeyboardSensor, pointerWithin, closestCenter, DndContext, DragOverlay, useDroppable, useDraggable } from '@dnd-kit/core';
|
|
2
2
|
import { sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable';
|
|
3
|
-
import { X, Circle, Sparkles, FileText, AlignLeft, MousePointerClick, TextCursorInput, LayoutTemplate, Bell, Pilcrow, Image, Video, GalleryHorizontal, Table, ChartColumnBig, Container, Loader2, ExternalLink, AlertTriangle, GripVertical, Sun, Moon, MessageSquare, AppWindow, Home, MailSearch, Plus, ChevronDown, BookOpen, Trash2, Code2, Pencil, Send, Search, Check, Copy, Info, CheckCircle2, ChevronRight, LayoutGrid, ArrowUp, ArrowDown, Type, Bold, Italic, Strikethrough, Underline, Code, List, ListOrdered, Quote,
|
|
3
|
+
import { X, Circle, Sparkles, FileText, AlignLeft, MousePointerClick, TextCursorInput, LayoutTemplate, Bell, Pilcrow, Image, Video, GalleryHorizontal, Table, ChartColumnBig, Container, Loader2, ExternalLink, AlertTriangle, GripVertical, Sun, Moon, MessageSquare, AppWindow, Home, MailSearch, Plus, ChevronDown, BookOpen, Undo2, Redo2, Trash2, Code2, Pencil, Send, Search, Check, Copy, Info, CheckCircle2, ChevronRight, LayoutGrid, ArrowUp, ArrowDown, Type, Bold, Italic, Strikethrough, Underline, Code, List, ListOrdered, Quote, Smile, Link as Link$1 } from 'lucide-react';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { createContext, useState, useRef, useEffect, useCallback, useMemo, useId, useContext } from 'react';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -2036,6 +2036,69 @@ function useBlockKitValidation(blocks, surface) {
|
|
|
2036
2036
|
}, [blocks, surface]);
|
|
2037
2037
|
return state;
|
|
2038
2038
|
}
|
|
2039
|
+
var MAX_HISTORY = 20;
|
|
2040
|
+
function useHistoryState(initial) {
|
|
2041
|
+
const [record, setRecord] = useState(() => ({
|
|
2042
|
+
past: [],
|
|
2043
|
+
present: typeof initial === "function" ? initial() : initial,
|
|
2044
|
+
future: [],
|
|
2045
|
+
lastTag: null
|
|
2046
|
+
}));
|
|
2047
|
+
const commit = useCallback((updater, options) => {
|
|
2048
|
+
const tag = options?.tag ?? null;
|
|
2049
|
+
setRecord((h) => {
|
|
2050
|
+
const next = typeof updater === "function" ? updater(h.present) : updater;
|
|
2051
|
+
if (Object.is(next, h.present)) {
|
|
2052
|
+
return h;
|
|
2053
|
+
}
|
|
2054
|
+
if (tag !== null && h.lastTag === tag) {
|
|
2055
|
+
return { ...h, present: next, future: [] };
|
|
2056
|
+
}
|
|
2057
|
+
const past = [...h.past, h.present];
|
|
2058
|
+
return {
|
|
2059
|
+
past: past.length > MAX_HISTORY ? past.slice(past.length - MAX_HISTORY) : past,
|
|
2060
|
+
present: next,
|
|
2061
|
+
future: [],
|
|
2062
|
+
lastTag: tag
|
|
2063
|
+
};
|
|
2064
|
+
});
|
|
2065
|
+
}, []);
|
|
2066
|
+
const undo = useCallback(() => {
|
|
2067
|
+
setRecord((h) => {
|
|
2068
|
+
if (h.past.length === 0) {
|
|
2069
|
+
return h;
|
|
2070
|
+
}
|
|
2071
|
+
const previous = h.past[h.past.length - 1];
|
|
2072
|
+
return { past: h.past.slice(0, -1), present: previous, future: [h.present, ...h.future], lastTag: null };
|
|
2073
|
+
});
|
|
2074
|
+
}, []);
|
|
2075
|
+
const redo = useCallback(() => {
|
|
2076
|
+
setRecord((h) => {
|
|
2077
|
+
if (h.future.length === 0) {
|
|
2078
|
+
return h;
|
|
2079
|
+
}
|
|
2080
|
+
const [next, ...rest] = h.future;
|
|
2081
|
+
return { past: [...h.past, h.present], present: next, future: rest, lastTag: null };
|
|
2082
|
+
});
|
|
2083
|
+
}, []);
|
|
2084
|
+
const reset = useCallback((next) => {
|
|
2085
|
+
setRecord({ past: [], present: next, future: [], lastTag: null });
|
|
2086
|
+
}, []);
|
|
2087
|
+
return useMemo(
|
|
2088
|
+
() => ({
|
|
2089
|
+
present: record.present,
|
|
2090
|
+
canUndo: record.past.length > 0,
|
|
2091
|
+
canRedo: record.future.length > 0,
|
|
2092
|
+
commit,
|
|
2093
|
+
undo,
|
|
2094
|
+
redo,
|
|
2095
|
+
reset
|
|
2096
|
+
}),
|
|
2097
|
+
[record, commit, undo, redo, reset]
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
// src/state/use-block-kitchen-state.ts
|
|
2039
2102
|
function mirror(node) {
|
|
2040
2103
|
if (!node.children) {
|
|
2041
2104
|
return node;
|
|
@@ -2086,7 +2149,15 @@ function useBlockKitchenState({
|
|
|
2086
2149
|
initialBlocks,
|
|
2087
2150
|
onChange
|
|
2088
2151
|
} = {}) {
|
|
2089
|
-
const
|
|
2152
|
+
const {
|
|
2153
|
+
present: blocks,
|
|
2154
|
+
commit,
|
|
2155
|
+
undo,
|
|
2156
|
+
redo,
|
|
2157
|
+
reset,
|
|
2158
|
+
canUndo,
|
|
2159
|
+
canRedo
|
|
2160
|
+
} = useHistoryState(() => (initialBlocks ?? []).map(wrap));
|
|
2090
2161
|
const onChangeRef = useRef(onChange);
|
|
2091
2162
|
useEffect(() => {
|
|
2092
2163
|
onChangeRef.current = onChange;
|
|
@@ -2099,121 +2170,155 @@ function useBlockKitchenState({
|
|
|
2099
2170
|
}
|
|
2100
2171
|
onChangeRef.current?.(blocks.map((b) => b.block));
|
|
2101
2172
|
}, [blocks]);
|
|
2102
|
-
const addBlock = useCallback(
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
next.splice(idx, 0, wrap(block));
|
|
2107
|
-
return next;
|
|
2108
|
-
});
|
|
2109
|
-
}, []);
|
|
2110
|
-
const addChild = useCallback((parentId, block, atIndex) => {
|
|
2111
|
-
if (!isContainerChildType(block.type)) {
|
|
2112
|
-
return;
|
|
2113
|
-
}
|
|
2114
|
-
setBlocks(
|
|
2115
|
-
(prev) => withChildren(prev, parentId, (children) => {
|
|
2116
|
-
if (children.length >= MAX_CONTAINER_CHILDREN) {
|
|
2117
|
-
return children;
|
|
2118
|
-
}
|
|
2119
|
-
const next = [...children];
|
|
2173
|
+
const addBlock = useCallback(
|
|
2174
|
+
(block, atIndex) => {
|
|
2175
|
+
commit((prev) => {
|
|
2176
|
+
const next = [...prev];
|
|
2120
2177
|
const idx = atIndex === void 0 ? next.length : Math.max(0, Math.min(atIndex, next.length));
|
|
2121
2178
|
next.splice(idx, 0, wrap(block));
|
|
2122
2179
|
return next;
|
|
2123
|
-
})
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
}
|
|
2132
|
-
if (b.children?.some((c) => c.id === id)) {
|
|
2133
|
-
return mirror({ ...b, children: b.children.map((c) => c.id === id ? applyUpdate(c, block) : c) });
|
|
2134
|
-
}
|
|
2135
|
-
return b;
|
|
2136
|
-
})
|
|
2137
|
-
);
|
|
2138
|
-
}, []);
|
|
2139
|
-
const removeBlock = useCallback((id) => {
|
|
2140
|
-
setBlocks((prev) => {
|
|
2141
|
-
if (prev.some((b) => b.id === id)) {
|
|
2142
|
-
return prev.filter((b) => b.id !== id);
|
|
2180
|
+
});
|
|
2181
|
+
},
|
|
2182
|
+
[commit]
|
|
2183
|
+
);
|
|
2184
|
+
const addChild = useCallback(
|
|
2185
|
+
(parentId, block, atIndex) => {
|
|
2186
|
+
if (!isContainerChildType(block.type)) {
|
|
2187
|
+
return;
|
|
2143
2188
|
}
|
|
2144
|
-
|
|
2145
|
-
(
|
|
2189
|
+
commit(
|
|
2190
|
+
(prev) => withChildren(prev, parentId, (children) => {
|
|
2191
|
+
if (children.length >= MAX_CONTAINER_CHILDREN) {
|
|
2192
|
+
return children;
|
|
2193
|
+
}
|
|
2194
|
+
const next = [...children];
|
|
2195
|
+
const idx = atIndex === void 0 ? next.length : Math.max(0, Math.min(atIndex, next.length));
|
|
2196
|
+
next.splice(idx, 0, wrap(block));
|
|
2197
|
+
return next;
|
|
2198
|
+
})
|
|
2146
2199
|
);
|
|
2147
|
-
}
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2200
|
+
},
|
|
2201
|
+
[commit]
|
|
2202
|
+
);
|
|
2203
|
+
const updateBlock = useCallback(
|
|
2204
|
+
(id, block) => {
|
|
2205
|
+
commit(
|
|
2206
|
+
(prev) => prev.map((b) => {
|
|
2207
|
+
if (b.id === id) {
|
|
2208
|
+
return applyUpdate(b, block);
|
|
2209
|
+
}
|
|
2210
|
+
if (b.children?.some((c) => c.id === id)) {
|
|
2211
|
+
return mirror({ ...b, children: b.children.map((c) => c.id === id ? applyUpdate(c, block) : c) });
|
|
2212
|
+
}
|
|
2213
|
+
return b;
|
|
2214
|
+
}),
|
|
2215
|
+
// Coalesce a run of edits to the same block (every keystroke in an
|
|
2216
|
+
// editor field lands here) into a single undo step. Editing a
|
|
2217
|
+
// different block, or any structural change, starts a new step.
|
|
2218
|
+
{ tag: `update:${id}` }
|
|
2219
|
+
);
|
|
2220
|
+
},
|
|
2221
|
+
[commit]
|
|
2222
|
+
);
|
|
2223
|
+
const removeBlock = useCallback(
|
|
2224
|
+
(id) => {
|
|
2225
|
+
commit((prev) => {
|
|
2226
|
+
if (prev.some((b) => b.id === id)) {
|
|
2227
|
+
return prev.filter((b) => b.id !== id);
|
|
2228
|
+
}
|
|
2229
|
+
return prev.map(
|
|
2230
|
+
(b) => b.children?.some((c) => c.id === id) ? mirror({ ...b, children: b.children.filter((c) => c.id !== id) }) : b
|
|
2231
|
+
);
|
|
2164
2232
|
});
|
|
2165
|
-
}
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
const reorder = (list) => {
|
|
2174
|
-
const next = [...list];
|
|
2175
|
-
const [moved] = next.splice(loc.index, 1);
|
|
2176
|
-
next.splice(Math.max(0, Math.min(toIndex, next.length)), 0, moved);
|
|
2177
|
-
return next;
|
|
2178
|
-
};
|
|
2179
|
-
if (loc.kind === "top") {
|
|
2180
|
-
return reorder(prev);
|
|
2181
|
-
}
|
|
2182
|
-
return withChildren(prev, loc.parentId, reorder);
|
|
2183
|
-
});
|
|
2184
|
-
}, []);
|
|
2185
|
-
const moveBlock = useCallback((activeId, target) => {
|
|
2186
|
-
setBlocks((prev) => {
|
|
2187
|
-
const loc = locate(prev, activeId);
|
|
2188
|
-
if (!loc) {
|
|
2189
|
-
return prev;
|
|
2190
|
-
}
|
|
2191
|
-
const moved = loc.kind === "top" ? prev[loc.index] : prev.find((b) => b.id === loc.parentId)?.children?.[loc.index];
|
|
2192
|
-
if (!moved) {
|
|
2193
|
-
return prev;
|
|
2194
|
-
}
|
|
2195
|
-
if (target.kind === "container") {
|
|
2196
|
-
if (moved.children || !isContainerChildType(moved.block.type)) {
|
|
2233
|
+
},
|
|
2234
|
+
[commit]
|
|
2235
|
+
);
|
|
2236
|
+
const duplicateBlock = useCallback(
|
|
2237
|
+
(id) => {
|
|
2238
|
+
commit((prev) => {
|
|
2239
|
+
const loc = locate(prev, id);
|
|
2240
|
+
if (!loc) {
|
|
2197
2241
|
return prev;
|
|
2198
2242
|
}
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2243
|
+
if (loc.kind === "top") {
|
|
2244
|
+
const next = [...prev];
|
|
2245
|
+
next.splice(loc.index + 1, 0, cloneNode(prev[loc.index]));
|
|
2246
|
+
return next;
|
|
2247
|
+
}
|
|
2248
|
+
return withChildren(prev, loc.parentId, (children) => {
|
|
2249
|
+
const next = [...children];
|
|
2250
|
+
next.splice(loc.index + 1, 0, cloneNode(children[loc.index]));
|
|
2251
|
+
return next;
|
|
2252
|
+
});
|
|
2253
|
+
});
|
|
2254
|
+
},
|
|
2255
|
+
[commit]
|
|
2256
|
+
);
|
|
2257
|
+
const reorderBlock = useCallback(
|
|
2258
|
+
(fromId, toIndex) => {
|
|
2259
|
+
commit((prev) => {
|
|
2260
|
+
const loc = locate(prev, fromId);
|
|
2261
|
+
if (!loc) {
|
|
2202
2262
|
return prev;
|
|
2203
2263
|
}
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2264
|
+
const reorder = (list) => {
|
|
2265
|
+
const next = [...list];
|
|
2266
|
+
const [moved] = next.splice(loc.index, 1);
|
|
2267
|
+
next.splice(Math.max(0, Math.min(toIndex, next.length)), 0, moved);
|
|
2268
|
+
return next;
|
|
2269
|
+
};
|
|
2270
|
+
if (loc.kind === "top") {
|
|
2271
|
+
return reorder(prev);
|
|
2272
|
+
}
|
|
2273
|
+
return withChildren(prev, loc.parentId, reorder);
|
|
2274
|
+
});
|
|
2275
|
+
},
|
|
2276
|
+
[commit]
|
|
2277
|
+
);
|
|
2278
|
+
const moveBlock = useCallback(
|
|
2279
|
+
(activeId, target) => {
|
|
2280
|
+
commit((prev) => {
|
|
2281
|
+
const loc = locate(prev, activeId);
|
|
2282
|
+
if (!loc) {
|
|
2283
|
+
return prev;
|
|
2284
|
+
}
|
|
2285
|
+
const moved = loc.kind === "top" ? prev[loc.index] : prev.find((b) => b.id === loc.parentId)?.children?.[loc.index];
|
|
2286
|
+
if (!moved) {
|
|
2287
|
+
return prev;
|
|
2288
|
+
}
|
|
2289
|
+
if (target.kind === "container") {
|
|
2290
|
+
if (moved.children || !isContainerChildType(moved.block.type)) {
|
|
2291
|
+
return prev;
|
|
2292
|
+
}
|
|
2293
|
+
const sameContainer = loc.kind === "child" && loc.parentId === target.parentId;
|
|
2294
|
+
const destCount = prev.find((b) => b.id === target.parentId)?.children?.length ?? 0;
|
|
2295
|
+
if (!sameContainer && destCount >= MAX_CONTAINER_CHILDREN) {
|
|
2296
|
+
return prev;
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
const detached = loc.kind === "top" ? prev.filter((_, i) => i !== loc.index) : withChildren(prev, loc.parentId, (children) => children.filter((_, i) => i !== loc.index));
|
|
2300
|
+
const insert = (list) => {
|
|
2301
|
+
const next = [...list];
|
|
2302
|
+
next.splice(Math.max(0, Math.min(target.index, next.length)), 0, moved);
|
|
2303
|
+
return next;
|
|
2304
|
+
};
|
|
2305
|
+
return target.kind === "container" ? withChildren(detached, target.parentId, insert) : insert(detached);
|
|
2306
|
+
});
|
|
2307
|
+
},
|
|
2308
|
+
[commit]
|
|
2309
|
+
);
|
|
2310
|
+
const replaceAll = useCallback(
|
|
2311
|
+
(newBlocks) => {
|
|
2312
|
+
commit(sanitizeBlocks(newBlocks).map(wrap));
|
|
2313
|
+
},
|
|
2314
|
+
[commit]
|
|
2315
|
+
);
|
|
2316
|
+
const resetAll = useCallback(
|
|
2317
|
+
(newBlocks) => {
|
|
2318
|
+
reset(sanitizeBlocks(newBlocks).map(wrap));
|
|
2319
|
+
},
|
|
2320
|
+
[reset]
|
|
2321
|
+
);
|
|
2217
2322
|
return {
|
|
2218
2323
|
blocks,
|
|
2219
2324
|
addBlock,
|
|
@@ -2223,7 +2328,12 @@ function useBlockKitchenState({
|
|
|
2223
2328
|
duplicateBlock,
|
|
2224
2329
|
reorderBlock,
|
|
2225
2330
|
moveBlock,
|
|
2226
|
-
replaceAll
|
|
2331
|
+
replaceAll,
|
|
2332
|
+
resetAll,
|
|
2333
|
+
undo,
|
|
2334
|
+
redo,
|
|
2335
|
+
canUndo,
|
|
2336
|
+
canRedo
|
|
2227
2337
|
};
|
|
2228
2338
|
}
|
|
2229
2339
|
function useDevWarning(condition, message) {
|
|
@@ -8452,7 +8562,8 @@ function VideoEditor({ block, onChange }) {
|
|
|
8452
8562
|
function BlockEditor({
|
|
8453
8563
|
block,
|
|
8454
8564
|
errors,
|
|
8455
|
-
onChange
|
|
8565
|
+
onChange,
|
|
8566
|
+
onDone
|
|
8456
8567
|
}) {
|
|
8457
8568
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
8458
8569
|
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("h3", { className: "text-sm font-semibold text-foreground", children: [
|
|
@@ -8460,7 +8571,8 @@ function BlockEditor({
|
|
|
8460
8571
|
labelForBlockType(block.type)
|
|
8461
8572
|
] }) }),
|
|
8462
8573
|
errors && errors.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-0.5 rounded-md border border-destructive/30 bg-destructive/5 p-2 text-xs text-destructive", children: errors.map((err, i) => /* @__PURE__ */ jsx("li", { children: err }, i)) }) : null,
|
|
8463
|
-
dispatch(block, onChange)
|
|
8574
|
+
dispatch(block, onChange),
|
|
8575
|
+
onDone ? /* @__PURE__ */ jsx("div", { className: "flex justify-end border-t pt-3", children: /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", onClick: onDone, children: "Done" }) }) : null
|
|
8464
8576
|
] });
|
|
8465
8577
|
}
|
|
8466
8578
|
function dispatch(block, onChange) {
|
|
@@ -8677,7 +8789,8 @@ function BlockRow({
|
|
|
8677
8789
|
{
|
|
8678
8790
|
block: builderBlock.block,
|
|
8679
8791
|
errors,
|
|
8680
|
-
onChange: (next) => onUpdate(builderBlock.id, next)
|
|
8792
|
+
onChange: (next) => onUpdate(builderBlock.id, next),
|
|
8793
|
+
onDone: () => onOpenChange?.(false)
|
|
8681
8794
|
}
|
|
8682
8795
|
) })
|
|
8683
8796
|
] }),
|
|
@@ -8941,7 +9054,15 @@ function ContainerRow({
|
|
|
8941
9054
|
]
|
|
8942
9055
|
}
|
|
8943
9056
|
) }),
|
|
8944
|
-
/* @__PURE__ */ jsx(PopoverContent, { className: "w-[min(32rem,calc(100vw-1.5rem))] sm:w-[32rem]", align: "start", children: /* @__PURE__ */ jsx(
|
|
9057
|
+
/* @__PURE__ */ jsx(PopoverContent, { className: "w-[min(32rem,calc(100vw-1.5rem))] sm:w-[32rem]", align: "start", children: /* @__PURE__ */ jsx(
|
|
9058
|
+
BlockEditor,
|
|
9059
|
+
{
|
|
9060
|
+
block,
|
|
9061
|
+
errors,
|
|
9062
|
+
onChange: (next) => onUpdate(id, next),
|
|
9063
|
+
onDone: () => onOpenBlockChange?.(null)
|
|
9064
|
+
}
|
|
9065
|
+
) })
|
|
8945
9066
|
] }),
|
|
8946
9067
|
/* @__PURE__ */ jsx(
|
|
8947
9068
|
"div",
|
|
@@ -9422,6 +9543,10 @@ function formatMessageTs(ts) {
|
|
|
9422
9543
|
}
|
|
9423
9544
|
var SEND_MENU_ITEM = "flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-left text-sm text-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50";
|
|
9424
9545
|
function Toolbar2({
|
|
9546
|
+
canUndo = false,
|
|
9547
|
+
canRedo = false,
|
|
9548
|
+
onUndo,
|
|
9549
|
+
onRedo,
|
|
9425
9550
|
onClear,
|
|
9426
9551
|
onOpenJson,
|
|
9427
9552
|
onOpenIssues,
|
|
@@ -9535,6 +9660,36 @@ function Toolbar2({
|
|
|
9535
9660
|
) : null
|
|
9536
9661
|
] }),
|
|
9537
9662
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 sm:gap-2", children: [
|
|
9663
|
+
onUndo && onRedo ? /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
|
9664
|
+
/* @__PURE__ */ jsx(
|
|
9665
|
+
Button,
|
|
9666
|
+
{
|
|
9667
|
+
type: "button",
|
|
9668
|
+
variant: "ghost",
|
|
9669
|
+
size: "sm",
|
|
9670
|
+
onClick: onUndo,
|
|
9671
|
+
disabled: !canUndo,
|
|
9672
|
+
"aria-label": "Undo",
|
|
9673
|
+
title: "Undo (Ctrl+Z)",
|
|
9674
|
+
className: "px-2",
|
|
9675
|
+
children: /* @__PURE__ */ jsx(Undo2, { className: "h-3.5 w-3.5" })
|
|
9676
|
+
}
|
|
9677
|
+
),
|
|
9678
|
+
/* @__PURE__ */ jsx(
|
|
9679
|
+
Button,
|
|
9680
|
+
{
|
|
9681
|
+
type: "button",
|
|
9682
|
+
variant: "ghost",
|
|
9683
|
+
size: "sm",
|
|
9684
|
+
onClick: onRedo,
|
|
9685
|
+
disabled: !canRedo,
|
|
9686
|
+
"aria-label": "Redo",
|
|
9687
|
+
title: "Redo (Ctrl+Shift+Z)",
|
|
9688
|
+
className: "px-2",
|
|
9689
|
+
children: /* @__PURE__ */ jsx(Redo2, { className: "h-3.5 w-3.5" })
|
|
9690
|
+
}
|
|
9691
|
+
)
|
|
9692
|
+
] }) : null,
|
|
9538
9693
|
errorCount > 0 ? /* @__PURE__ */ jsxs(
|
|
9539
9694
|
Button,
|
|
9540
9695
|
{
|
|
@@ -9935,7 +10090,22 @@ function BlockKitchen(props) {
|
|
|
9935
10090
|
Boolean(primaryAction && sendEnabled),
|
|
9936
10091
|
"[BlockKitchen] `primaryAction` is only available in compose-only mode \u2014 with the send integration wired, the built-in Send/Update flow owns the toolbar\u2019s primary action; ignoring `primaryAction`."
|
|
9937
10092
|
);
|
|
9938
|
-
const {
|
|
10093
|
+
const {
|
|
10094
|
+
blocks,
|
|
10095
|
+
addBlock,
|
|
10096
|
+
addChild,
|
|
10097
|
+
updateBlock,
|
|
10098
|
+
removeBlock,
|
|
10099
|
+
duplicateBlock,
|
|
10100
|
+
reorderBlock,
|
|
10101
|
+
moveBlock,
|
|
10102
|
+
replaceAll,
|
|
10103
|
+
resetAll,
|
|
10104
|
+
undo,
|
|
10105
|
+
redo,
|
|
10106
|
+
canUndo,
|
|
10107
|
+
canRedo
|
|
10108
|
+
} = useBlockKitchenState({ initialBlocks: seededBlocks, onChange });
|
|
9939
10109
|
const childParentById = useMemo(() => {
|
|
9940
10110
|
const map = /* @__PURE__ */ new Map();
|
|
9941
10111
|
for (const top of blocks) {
|
|
@@ -10051,6 +10221,30 @@ function BlockKitchen(props) {
|
|
|
10051
10221
|
const handleDragCancel = useCallback(() => {
|
|
10052
10222
|
setActivePaletteVariantId(null);
|
|
10053
10223
|
}, []);
|
|
10224
|
+
const handleKeyDown = useCallback(
|
|
10225
|
+
(event) => {
|
|
10226
|
+
if (!(event.metaKey || event.ctrlKey) || event.altKey) {
|
|
10227
|
+
return;
|
|
10228
|
+
}
|
|
10229
|
+
const key = event.key.toLowerCase();
|
|
10230
|
+
const isUndo = key === "z" && !event.shiftKey;
|
|
10231
|
+
const isRedo = key === "y" || key === "z" && event.shiftKey;
|
|
10232
|
+
if (!isUndo && !isRedo) {
|
|
10233
|
+
return;
|
|
10234
|
+
}
|
|
10235
|
+
const target = event.target;
|
|
10236
|
+
if (target && (target.isContentEditable || ["INPUT", "TEXTAREA", "SELECT"].includes(target.tagName))) {
|
|
10237
|
+
return;
|
|
10238
|
+
}
|
|
10239
|
+
event.preventDefault();
|
|
10240
|
+
if (isRedo) {
|
|
10241
|
+
if (canRedo) redo();
|
|
10242
|
+
} else if (canUndo) {
|
|
10243
|
+
undo();
|
|
10244
|
+
}
|
|
10245
|
+
},
|
|
10246
|
+
[canRedo, canUndo, redo, undo]
|
|
10247
|
+
);
|
|
10054
10248
|
const activePaletteVariant = activePaletteVariantId ? variantById.get(activePaletteVariantId) : null;
|
|
10055
10249
|
const blockPayloads = blocks.map((b) => b.block);
|
|
10056
10250
|
return /* @__PURE__ */ jsx(BrandThemeScope, { theme, children: /* @__PURE__ */ jsx(CustomEmojiProvider, { customEmojis, children: /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs(
|
|
@@ -10062,91 +10256,102 @@ function BlockKitchen(props) {
|
|
|
10062
10256
|
onDragEnd: handleDragEnd,
|
|
10063
10257
|
onDragCancel: handleDragCancel,
|
|
10064
10258
|
children: [
|
|
10065
|
-
/* @__PURE__ */ jsxs(
|
|
10066
|
-
|
|
10067
|
-
|
|
10068
|
-
|
|
10069
|
-
|
|
10070
|
-
|
|
10071
|
-
|
|
10072
|
-
|
|
10073
|
-
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
|
|
10077
|
-
|
|
10078
|
-
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
|
|
10082
|
-
|
|
10083
|
-
|
|
10084
|
-
|
|
10085
|
-
|
|
10086
|
-
|
|
10087
|
-
|
|
10088
|
-
|
|
10089
|
-
|
|
10090
|
-
|
|
10091
|
-
|
|
10092
|
-
|
|
10093
|
-
|
|
10094
|
-
|
|
10095
|
-
|
|
10096
|
-
|
|
10097
|
-
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
10104
|
-
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
|
|
10259
|
+
/* @__PURE__ */ jsxs(
|
|
10260
|
+
"div",
|
|
10261
|
+
{
|
|
10262
|
+
className: "bk-root flex h-full w-full flex-col overflow-hidden rounded-md border bg-background text-foreground",
|
|
10263
|
+
onKeyDown: handleKeyDown,
|
|
10264
|
+
children: [
|
|
10265
|
+
/* @__PURE__ */ jsx(
|
|
10266
|
+
Toolbar2,
|
|
10267
|
+
{
|
|
10268
|
+
canUndo,
|
|
10269
|
+
canRedo,
|
|
10270
|
+
onUndo: undo,
|
|
10271
|
+
onRedo: redo,
|
|
10272
|
+
onClear: () => replaceAll([]),
|
|
10273
|
+
onOpenJson: () => setJsonOpen(true),
|
|
10274
|
+
onOpenIssues: () => setIssuesOpen(true),
|
|
10275
|
+
onOpenSend: () => setSendOpen(true),
|
|
10276
|
+
onOpenPalette: () => setPaletteOpen(true),
|
|
10277
|
+
canSend: blocks.length > 0,
|
|
10278
|
+
canClear: blocks.length > 0,
|
|
10279
|
+
errorCount: validation.total,
|
|
10280
|
+
previewTheme,
|
|
10281
|
+
onPreviewThemeChange: setUncontrolledPreviewTheme,
|
|
10282
|
+
previewSurface,
|
|
10283
|
+
onPreviewSurfaceChange: setPreviewSurface,
|
|
10284
|
+
allowedSurfaces,
|
|
10285
|
+
showThemeControl: isPreviewThemeControlled ? false : showThemeControl,
|
|
10286
|
+
docsLink,
|
|
10287
|
+
showSend: sendEnabled,
|
|
10288
|
+
primaryAction: !sendEnabled && primaryAction ? {
|
|
10289
|
+
label: primaryAction.label,
|
|
10290
|
+
onClick: () => primaryAction.onClick({
|
|
10291
|
+
blocks: blockPayloads,
|
|
10292
|
+
validation: validationSummary,
|
|
10293
|
+
loadedMessage: activeEditTarget
|
|
10294
|
+
}),
|
|
10295
|
+
disabled: primaryAction.disableWhenInvalid ? !validationSummary.valid : false
|
|
10296
|
+
} : null,
|
|
10297
|
+
sendButtonLabel,
|
|
10298
|
+
loadEnabled,
|
|
10299
|
+
updateEnabled: Boolean(onUpdate),
|
|
10300
|
+
editBadge: activeEditTarget ? {
|
|
10301
|
+
channelLabel: activeEditTarget.channelName ? `#${activeEditTarget.channelName}` : activeEditTarget.channelId,
|
|
10302
|
+
ts: activeEditTarget.ts
|
|
10303
|
+
} : null,
|
|
10304
|
+
onOpenLoad: () => setLoadOpen(true),
|
|
10305
|
+
onOpenUpdate: () => setUpdateOpen(true),
|
|
10306
|
+
onExitEdit: () => {
|
|
10307
|
+
if (sendEnabled) {
|
|
10308
|
+
setEditTarget(null);
|
|
10309
|
+
resetAll([]);
|
|
10310
|
+
setLoadOpen(true);
|
|
10311
|
+
return;
|
|
10312
|
+
}
|
|
10313
|
+
setEditTarget(null);
|
|
10314
|
+
},
|
|
10315
|
+
loadButtonLabel,
|
|
10316
|
+
updateButtonLabel
|
|
10109
10317
|
}
|
|
10110
|
-
|
|
10111
|
-
|
|
10112
|
-
|
|
10113
|
-
|
|
10114
|
-
|
|
10115
|
-
|
|
10116
|
-
|
|
10117
|
-
|
|
10118
|
-
|
|
10119
|
-
|
|
10120
|
-
|
|
10121
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
10124
|
-
|
|
10125
|
-
|
|
10126
|
-
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
|
|
10130
|
-
|
|
10131
|
-
|
|
10132
|
-
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
10142
|
-
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
|
|
10146
|
-
|
|
10147
|
-
)
|
|
10148
|
-
] })
|
|
10149
|
-
] }),
|
|
10318
|
+
),
|
|
10319
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 items-stretch", children: [
|
|
10320
|
+
/* @__PURE__ */ jsx("div", { className: "hidden min-h-0 md:flex", children: /* @__PURE__ */ jsx(
|
|
10321
|
+
Palette,
|
|
10322
|
+
{
|
|
10323
|
+
onAddBlock: (block) => addBlock(block),
|
|
10324
|
+
sections: paletteSections,
|
|
10325
|
+
showSearch: showPaletteSearch,
|
|
10326
|
+
searchPlaceholder: paletteSearchPlaceholder,
|
|
10327
|
+
defaultOpenSections
|
|
10328
|
+
}
|
|
10329
|
+
) }),
|
|
10330
|
+
/* @__PURE__ */ jsx(
|
|
10331
|
+
Surface,
|
|
10332
|
+
{
|
|
10333
|
+
blocks,
|
|
10334
|
+
workspaceName,
|
|
10335
|
+
authorName: activeEditTarget?.username,
|
|
10336
|
+
authorIcon: activeEditTarget?.iconUrl,
|
|
10337
|
+
previewHooks: mergedPreviewHooks,
|
|
10338
|
+
previewTheme,
|
|
10339
|
+
previewSurface,
|
|
10340
|
+
errorsByBlockId: validation.byBlockId,
|
|
10341
|
+
openBlockId,
|
|
10342
|
+
onOpenBlockChange: setOpenBlockId,
|
|
10343
|
+
onUpdate: updateBlock,
|
|
10344
|
+
onDuplicate: duplicateBlock,
|
|
10345
|
+
onDelete: removeBlock,
|
|
10346
|
+
onReorder: reorderBlock,
|
|
10347
|
+
isPaletteDrag: activePaletteVariant !== null,
|
|
10348
|
+
onOpenPalette: () => setPaletteOpen(true)
|
|
10349
|
+
}
|
|
10350
|
+
)
|
|
10351
|
+
] })
|
|
10352
|
+
]
|
|
10353
|
+
}
|
|
10354
|
+
),
|
|
10150
10355
|
/* @__PURE__ */ jsx(DragOverlay, { dropAnimation: null, children: activePaletteVariant ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 rounded border bg-background px-1.5 py-1 text-xs text-foreground shadow-md", children: [
|
|
10151
10356
|
/* @__PURE__ */ jsx(GripVertical, { className: "h-3 w-3 shrink-0" }),
|
|
10152
10357
|
/* @__PURE__ */ jsx("span", { className: "truncate", children: activePaletteVariant.label })
|
|
@@ -10223,13 +10428,13 @@ function BlockKitchen(props) {
|
|
|
10223
10428
|
loadRecentMessages: loading.loadRecentMessages,
|
|
10224
10429
|
loadChannels: recentChannelSource,
|
|
10225
10430
|
onLoaded: (result) => {
|
|
10226
|
-
|
|
10431
|
+
resetAll(result.blocks);
|
|
10227
10432
|
setEditTarget(toLoadedMessage(result));
|
|
10228
10433
|
setLoadOpen(false);
|
|
10229
10434
|
},
|
|
10230
10435
|
onOpenAsNew: (loadedBlocks) => {
|
|
10231
10436
|
if (loadedBlocks) {
|
|
10232
|
-
|
|
10437
|
+
resetAll(loadedBlocks);
|
|
10233
10438
|
}
|
|
10234
10439
|
setEditTarget(null);
|
|
10235
10440
|
setLoadOpen(false);
|