@tightknitai/block-kitchen 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/dist/helpers.d.cts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.cjs +471 -201
- 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 +472 -202
- package/dist/index.js.map +1 -1
- package/dist/{palette-C8sPJuXx.d.cts → palette-BtSwlGUC.d.cts} +1 -1
- package/dist/{palette-C8sPJuXx.d.ts → palette-BtSwlGUC.d.ts} +1 -1
- package/dist/palette.d.cts +1 -1
- package/dist/palette.d.ts +1 -1
- package/dist/styles.css +1 -1
- package/package.json +44 -38
package/dist/index.cjs
CHANGED
|
@@ -2066,6 +2066,69 @@ function useBlockKitValidation(blocks, surface) {
|
|
|
2066
2066
|
}, [blocks, surface]);
|
|
2067
2067
|
return state;
|
|
2068
2068
|
}
|
|
2069
|
+
var MAX_HISTORY = 20;
|
|
2070
|
+
function useHistoryState(initial) {
|
|
2071
|
+
const [record, setRecord] = React.useState(() => ({
|
|
2072
|
+
past: [],
|
|
2073
|
+
present: typeof initial === "function" ? initial() : initial,
|
|
2074
|
+
future: [],
|
|
2075
|
+
lastTag: null
|
|
2076
|
+
}));
|
|
2077
|
+
const commit = React.useCallback((updater, options) => {
|
|
2078
|
+
const tag = options?.tag ?? null;
|
|
2079
|
+
setRecord((h) => {
|
|
2080
|
+
const next = typeof updater === "function" ? updater(h.present) : updater;
|
|
2081
|
+
if (Object.is(next, h.present)) {
|
|
2082
|
+
return h;
|
|
2083
|
+
}
|
|
2084
|
+
if (tag !== null && h.lastTag === tag) {
|
|
2085
|
+
return { ...h, present: next, future: [] };
|
|
2086
|
+
}
|
|
2087
|
+
const past = [...h.past, h.present];
|
|
2088
|
+
return {
|
|
2089
|
+
past: past.length > MAX_HISTORY ? past.slice(past.length - MAX_HISTORY) : past,
|
|
2090
|
+
present: next,
|
|
2091
|
+
future: [],
|
|
2092
|
+
lastTag: tag
|
|
2093
|
+
};
|
|
2094
|
+
});
|
|
2095
|
+
}, []);
|
|
2096
|
+
const undo = React.useCallback(() => {
|
|
2097
|
+
setRecord((h) => {
|
|
2098
|
+
if (h.past.length === 0) {
|
|
2099
|
+
return h;
|
|
2100
|
+
}
|
|
2101
|
+
const previous = h.past[h.past.length - 1];
|
|
2102
|
+
return { past: h.past.slice(0, -1), present: previous, future: [h.present, ...h.future], lastTag: null };
|
|
2103
|
+
});
|
|
2104
|
+
}, []);
|
|
2105
|
+
const redo = React.useCallback(() => {
|
|
2106
|
+
setRecord((h) => {
|
|
2107
|
+
if (h.future.length === 0) {
|
|
2108
|
+
return h;
|
|
2109
|
+
}
|
|
2110
|
+
const [next, ...rest] = h.future;
|
|
2111
|
+
return { past: [...h.past, h.present], present: next, future: rest, lastTag: null };
|
|
2112
|
+
});
|
|
2113
|
+
}, []);
|
|
2114
|
+
const reset = React.useCallback((next) => {
|
|
2115
|
+
setRecord({ past: [], present: next, future: [], lastTag: null });
|
|
2116
|
+
}, []);
|
|
2117
|
+
return React.useMemo(
|
|
2118
|
+
() => ({
|
|
2119
|
+
present: record.present,
|
|
2120
|
+
canUndo: record.past.length > 0,
|
|
2121
|
+
canRedo: record.future.length > 0,
|
|
2122
|
+
commit,
|
|
2123
|
+
undo,
|
|
2124
|
+
redo,
|
|
2125
|
+
reset
|
|
2126
|
+
}),
|
|
2127
|
+
[record, commit, undo, redo, reset]
|
|
2128
|
+
);
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
// src/state/use-block-kitchen-state.ts
|
|
2069
2132
|
function mirror(node) {
|
|
2070
2133
|
if (!node.children) {
|
|
2071
2134
|
return node;
|
|
@@ -2116,7 +2179,15 @@ function useBlockKitchenState({
|
|
|
2116
2179
|
initialBlocks,
|
|
2117
2180
|
onChange
|
|
2118
2181
|
} = {}) {
|
|
2119
|
-
const
|
|
2182
|
+
const {
|
|
2183
|
+
present: blocks,
|
|
2184
|
+
commit,
|
|
2185
|
+
undo,
|
|
2186
|
+
redo,
|
|
2187
|
+
reset,
|
|
2188
|
+
canUndo,
|
|
2189
|
+
canRedo
|
|
2190
|
+
} = useHistoryState(() => (initialBlocks ?? []).map(wrap));
|
|
2120
2191
|
const onChangeRef = React.useRef(onChange);
|
|
2121
2192
|
React.useEffect(() => {
|
|
2122
2193
|
onChangeRef.current = onChange;
|
|
@@ -2129,121 +2200,155 @@ function useBlockKitchenState({
|
|
|
2129
2200
|
}
|
|
2130
2201
|
onChangeRef.current?.(blocks.map((b) => b.block));
|
|
2131
2202
|
}, [blocks]);
|
|
2132
|
-
const addBlock = React.useCallback(
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
next.splice(idx, 0, wrap(block));
|
|
2137
|
-
return next;
|
|
2138
|
-
});
|
|
2139
|
-
}, []);
|
|
2140
|
-
const addChild = React.useCallback((parentId, block, atIndex) => {
|
|
2141
|
-
if (!isContainerChildType(block.type)) {
|
|
2142
|
-
return;
|
|
2143
|
-
}
|
|
2144
|
-
setBlocks(
|
|
2145
|
-
(prev) => withChildren(prev, parentId, (children) => {
|
|
2146
|
-
if (children.length >= MAX_CONTAINER_CHILDREN) {
|
|
2147
|
-
return children;
|
|
2148
|
-
}
|
|
2149
|
-
const next = [...children];
|
|
2203
|
+
const addBlock = React.useCallback(
|
|
2204
|
+
(block, atIndex) => {
|
|
2205
|
+
commit((prev) => {
|
|
2206
|
+
const next = [...prev];
|
|
2150
2207
|
const idx = atIndex === void 0 ? next.length : Math.max(0, Math.min(atIndex, next.length));
|
|
2151
2208
|
next.splice(idx, 0, wrap(block));
|
|
2152
2209
|
return next;
|
|
2153
|
-
})
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
}
|
|
2162
|
-
if (b.children?.some((c) => c.id === id)) {
|
|
2163
|
-
return mirror({ ...b, children: b.children.map((c) => c.id === id ? applyUpdate(c, block) : c) });
|
|
2164
|
-
}
|
|
2165
|
-
return b;
|
|
2166
|
-
})
|
|
2167
|
-
);
|
|
2168
|
-
}, []);
|
|
2169
|
-
const removeBlock = React.useCallback((id) => {
|
|
2170
|
-
setBlocks((prev) => {
|
|
2171
|
-
if (prev.some((b) => b.id === id)) {
|
|
2172
|
-
return prev.filter((b) => b.id !== id);
|
|
2210
|
+
});
|
|
2211
|
+
},
|
|
2212
|
+
[commit]
|
|
2213
|
+
);
|
|
2214
|
+
const addChild = React.useCallback(
|
|
2215
|
+
(parentId, block, atIndex) => {
|
|
2216
|
+
if (!isContainerChildType(block.type)) {
|
|
2217
|
+
return;
|
|
2173
2218
|
}
|
|
2174
|
-
|
|
2175
|
-
(
|
|
2219
|
+
commit(
|
|
2220
|
+
(prev) => withChildren(prev, parentId, (children) => {
|
|
2221
|
+
if (children.length >= MAX_CONTAINER_CHILDREN) {
|
|
2222
|
+
return children;
|
|
2223
|
+
}
|
|
2224
|
+
const next = [...children];
|
|
2225
|
+
const idx = atIndex === void 0 ? next.length : Math.max(0, Math.min(atIndex, next.length));
|
|
2226
|
+
next.splice(idx, 0, wrap(block));
|
|
2227
|
+
return next;
|
|
2228
|
+
})
|
|
2176
2229
|
);
|
|
2177
|
-
}
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2230
|
+
},
|
|
2231
|
+
[commit]
|
|
2232
|
+
);
|
|
2233
|
+
const updateBlock = React.useCallback(
|
|
2234
|
+
(id, block) => {
|
|
2235
|
+
commit(
|
|
2236
|
+
(prev) => prev.map((b) => {
|
|
2237
|
+
if (b.id === id) {
|
|
2238
|
+
return applyUpdate(b, block);
|
|
2239
|
+
}
|
|
2240
|
+
if (b.children?.some((c) => c.id === id)) {
|
|
2241
|
+
return mirror({ ...b, children: b.children.map((c) => c.id === id ? applyUpdate(c, block) : c) });
|
|
2242
|
+
}
|
|
2243
|
+
return b;
|
|
2244
|
+
}),
|
|
2245
|
+
// Coalesce a run of edits to the same block (every keystroke in an
|
|
2246
|
+
// editor field lands here) into a single undo step. Editing a
|
|
2247
|
+
// different block, or any structural change, starts a new step.
|
|
2248
|
+
{ tag: `update:${id}` }
|
|
2249
|
+
);
|
|
2250
|
+
},
|
|
2251
|
+
[commit]
|
|
2252
|
+
);
|
|
2253
|
+
const removeBlock = React.useCallback(
|
|
2254
|
+
(id) => {
|
|
2255
|
+
commit((prev) => {
|
|
2256
|
+
if (prev.some((b) => b.id === id)) {
|
|
2257
|
+
return prev.filter((b) => b.id !== id);
|
|
2258
|
+
}
|
|
2259
|
+
return prev.map(
|
|
2260
|
+
(b) => b.children?.some((c) => c.id === id) ? mirror({ ...b, children: b.children.filter((c) => c.id !== id) }) : b
|
|
2261
|
+
);
|
|
2194
2262
|
});
|
|
2195
|
-
}
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
const reorder = (list) => {
|
|
2204
|
-
const next = [...list];
|
|
2205
|
-
const [moved] = next.splice(loc.index, 1);
|
|
2206
|
-
next.splice(Math.max(0, Math.min(toIndex, next.length)), 0, moved);
|
|
2207
|
-
return next;
|
|
2208
|
-
};
|
|
2209
|
-
if (loc.kind === "top") {
|
|
2210
|
-
return reorder(prev);
|
|
2211
|
-
}
|
|
2212
|
-
return withChildren(prev, loc.parentId, reorder);
|
|
2213
|
-
});
|
|
2214
|
-
}, []);
|
|
2215
|
-
const moveBlock = React.useCallback((activeId, target) => {
|
|
2216
|
-
setBlocks((prev) => {
|
|
2217
|
-
const loc = locate(prev, activeId);
|
|
2218
|
-
if (!loc) {
|
|
2219
|
-
return prev;
|
|
2220
|
-
}
|
|
2221
|
-
const moved = loc.kind === "top" ? prev[loc.index] : prev.find((b) => b.id === loc.parentId)?.children?.[loc.index];
|
|
2222
|
-
if (!moved) {
|
|
2223
|
-
return prev;
|
|
2224
|
-
}
|
|
2225
|
-
if (target.kind === "container") {
|
|
2226
|
-
if (moved.children || !isContainerChildType(moved.block.type)) {
|
|
2263
|
+
},
|
|
2264
|
+
[commit]
|
|
2265
|
+
);
|
|
2266
|
+
const duplicateBlock = React.useCallback(
|
|
2267
|
+
(id) => {
|
|
2268
|
+
commit((prev) => {
|
|
2269
|
+
const loc = locate(prev, id);
|
|
2270
|
+
if (!loc) {
|
|
2227
2271
|
return prev;
|
|
2228
2272
|
}
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2273
|
+
if (loc.kind === "top") {
|
|
2274
|
+
const next = [...prev];
|
|
2275
|
+
next.splice(loc.index + 1, 0, cloneNode(prev[loc.index]));
|
|
2276
|
+
return next;
|
|
2277
|
+
}
|
|
2278
|
+
return withChildren(prev, loc.parentId, (children) => {
|
|
2279
|
+
const next = [...children];
|
|
2280
|
+
next.splice(loc.index + 1, 0, cloneNode(children[loc.index]));
|
|
2281
|
+
return next;
|
|
2282
|
+
});
|
|
2283
|
+
});
|
|
2284
|
+
},
|
|
2285
|
+
[commit]
|
|
2286
|
+
);
|
|
2287
|
+
const reorderBlock = React.useCallback(
|
|
2288
|
+
(fromId, toIndex) => {
|
|
2289
|
+
commit((prev) => {
|
|
2290
|
+
const loc = locate(prev, fromId);
|
|
2291
|
+
if (!loc) {
|
|
2232
2292
|
return prev;
|
|
2233
2293
|
}
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2294
|
+
const reorder = (list) => {
|
|
2295
|
+
const next = [...list];
|
|
2296
|
+
const [moved] = next.splice(loc.index, 1);
|
|
2297
|
+
next.splice(Math.max(0, Math.min(toIndex, next.length)), 0, moved);
|
|
2298
|
+
return next;
|
|
2299
|
+
};
|
|
2300
|
+
if (loc.kind === "top") {
|
|
2301
|
+
return reorder(prev);
|
|
2302
|
+
}
|
|
2303
|
+
return withChildren(prev, loc.parentId, reorder);
|
|
2304
|
+
});
|
|
2305
|
+
},
|
|
2306
|
+
[commit]
|
|
2307
|
+
);
|
|
2308
|
+
const moveBlock = React.useCallback(
|
|
2309
|
+
(activeId, target) => {
|
|
2310
|
+
commit((prev) => {
|
|
2311
|
+
const loc = locate(prev, activeId);
|
|
2312
|
+
if (!loc) {
|
|
2313
|
+
return prev;
|
|
2314
|
+
}
|
|
2315
|
+
const moved = loc.kind === "top" ? prev[loc.index] : prev.find((b) => b.id === loc.parentId)?.children?.[loc.index];
|
|
2316
|
+
if (!moved) {
|
|
2317
|
+
return prev;
|
|
2318
|
+
}
|
|
2319
|
+
if (target.kind === "container") {
|
|
2320
|
+
if (moved.children || !isContainerChildType(moved.block.type)) {
|
|
2321
|
+
return prev;
|
|
2322
|
+
}
|
|
2323
|
+
const sameContainer = loc.kind === "child" && loc.parentId === target.parentId;
|
|
2324
|
+
const destCount = prev.find((b) => b.id === target.parentId)?.children?.length ?? 0;
|
|
2325
|
+
if (!sameContainer && destCount >= MAX_CONTAINER_CHILDREN) {
|
|
2326
|
+
return prev;
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
const detached = loc.kind === "top" ? prev.filter((_, i) => i !== loc.index) : withChildren(prev, loc.parentId, (children) => children.filter((_, i) => i !== loc.index));
|
|
2330
|
+
const insert = (list) => {
|
|
2331
|
+
const next = [...list];
|
|
2332
|
+
next.splice(Math.max(0, Math.min(target.index, next.length)), 0, moved);
|
|
2333
|
+
return next;
|
|
2334
|
+
};
|
|
2335
|
+
return target.kind === "container" ? withChildren(detached, target.parentId, insert) : insert(detached);
|
|
2336
|
+
});
|
|
2337
|
+
},
|
|
2338
|
+
[commit]
|
|
2339
|
+
);
|
|
2340
|
+
const replaceAll = React.useCallback(
|
|
2341
|
+
(newBlocks) => {
|
|
2342
|
+
commit(sanitizeBlocks(newBlocks).map(wrap));
|
|
2343
|
+
},
|
|
2344
|
+
[commit]
|
|
2345
|
+
);
|
|
2346
|
+
const resetAll = React.useCallback(
|
|
2347
|
+
(newBlocks) => {
|
|
2348
|
+
reset(sanitizeBlocks(newBlocks).map(wrap));
|
|
2349
|
+
},
|
|
2350
|
+
[reset]
|
|
2351
|
+
);
|
|
2247
2352
|
return {
|
|
2248
2353
|
blocks,
|
|
2249
2354
|
addBlock,
|
|
@@ -2253,7 +2358,12 @@ function useBlockKitchenState({
|
|
|
2253
2358
|
duplicateBlock,
|
|
2254
2359
|
reorderBlock,
|
|
2255
2360
|
moveBlock,
|
|
2256
|
-
replaceAll
|
|
2361
|
+
replaceAll,
|
|
2362
|
+
resetAll,
|
|
2363
|
+
undo,
|
|
2364
|
+
redo,
|
|
2365
|
+
canUndo,
|
|
2366
|
+
canRedo
|
|
2257
2367
|
};
|
|
2258
2368
|
}
|
|
2259
2369
|
function useDevWarning(condition, message) {
|
|
@@ -3801,6 +3911,27 @@ function EditorField({
|
|
|
3801
3911
|
help && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: help })
|
|
3802
3912
|
] });
|
|
3803
3913
|
}
|
|
3914
|
+
function AdvancedIdField({
|
|
3915
|
+
label,
|
|
3916
|
+
help,
|
|
3917
|
+
htmlFor,
|
|
3918
|
+
value,
|
|
3919
|
+
placeholder,
|
|
3920
|
+
onChange
|
|
3921
|
+
}) {
|
|
3922
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "rounded-md border bg-muted/20 px-2.5 py-1.5", children: [
|
|
3923
|
+
/* @__PURE__ */ jsxRuntime.jsx("summary", { className: "cursor-pointer text-[11px] font-medium text-muted-foreground hover:text-foreground", children: "Advanced" }),
|
|
3924
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-2 pb-1", children: /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label, help, htmlFor, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3925
|
+
Input,
|
|
3926
|
+
{
|
|
3927
|
+
id: htmlFor,
|
|
3928
|
+
value: value ?? "",
|
|
3929
|
+
placeholder,
|
|
3930
|
+
onChange: (e) => onChange(e.target.value || void 0)
|
|
3931
|
+
}
|
|
3932
|
+
) }) })
|
|
3933
|
+
] });
|
|
3934
|
+
}
|
|
3804
3935
|
function ActionsEditor({ block, onChange }) {
|
|
3805
3936
|
const elements = block.elements ?? [];
|
|
3806
3937
|
const updateButton = (idx, update) => {
|
|
@@ -3899,7 +4030,18 @@ function ActionsEditor({ block, onChange }) {
|
|
|
3899
4030
|
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `btn-style-${idx}-${s}`, className: "text-xs capitalize", children: s })
|
|
3900
4031
|
] }, s))
|
|
3901
4032
|
}
|
|
3902
|
-
) })
|
|
4033
|
+
) }),
|
|
4034
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4035
|
+
AdvancedIdField,
|
|
4036
|
+
{
|
|
4037
|
+
label: "Action ID",
|
|
4038
|
+
help: "Optional. Sent in the interaction payload so your app knows which button was clicked.",
|
|
4039
|
+
htmlFor: `btn-action-${idx}`,
|
|
4040
|
+
value: el.action_id,
|
|
4041
|
+
placeholder: "e.g. approve_request",
|
|
4042
|
+
onChange: (next) => updateButton(idx, { action_id: next })
|
|
4043
|
+
}
|
|
4044
|
+
)
|
|
3903
4045
|
] }, idx);
|
|
3904
4046
|
}),
|
|
3905
4047
|
/* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", size: "sm", onClick: addButton, className: "self-start", children: [
|
|
@@ -4182,7 +4324,18 @@ function ButtonsField({
|
|
|
4182
4324
|
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `${idPrefix}-btn-style-${idx}-${s}`, className: "text-xs capitalize", children: s })
|
|
4183
4325
|
] }, s))
|
|
4184
4326
|
}
|
|
4185
|
-
) })
|
|
4327
|
+
) }),
|
|
4328
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4329
|
+
AdvancedIdField,
|
|
4330
|
+
{
|
|
4331
|
+
label: "Action ID",
|
|
4332
|
+
help: "Optional. Sent in the interaction payload so your app knows which button was clicked.",
|
|
4333
|
+
htmlFor: `${idPrefix}-btn-action-${idx}`,
|
|
4334
|
+
value: btn.action_id,
|
|
4335
|
+
placeholder: "e.g. open_details",
|
|
4336
|
+
onChange: (next) => update(idx, { action_id: next })
|
|
4337
|
+
}
|
|
4338
|
+
)
|
|
4186
4339
|
] }, idx);
|
|
4187
4340
|
}),
|
|
4188
4341
|
/* @__PURE__ */ jsxRuntime.jsxs(Button, { type: "button", size: "sm", onClick: addButton, disabled: atLimit, className: "self-start", children: [
|
|
@@ -8010,7 +8163,18 @@ function ButtonAccessoryFields({ button, onChange }) {
|
|
|
8010
8163
|
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `section-acc-btn-style-${s}`, className: "text-xs capitalize", children: s })
|
|
8011
8164
|
] }, s))
|
|
8012
8165
|
}
|
|
8013
|
-
) })
|
|
8166
|
+
) }),
|
|
8167
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8168
|
+
AdvancedIdField,
|
|
8169
|
+
{
|
|
8170
|
+
label: "Action ID",
|
|
8171
|
+
help: "Optional. Sent in the interaction payload so your app knows which button was clicked.",
|
|
8172
|
+
htmlFor: "section-acc-btn-action",
|
|
8173
|
+
value: button.action_id,
|
|
8174
|
+
placeholder: "e.g. learn_more",
|
|
8175
|
+
onChange: (next) => onChange({ ...button, action_id: next })
|
|
8176
|
+
}
|
|
8177
|
+
)
|
|
8014
8178
|
] });
|
|
8015
8179
|
}
|
|
8016
8180
|
function ImageAccessoryFields({ image, onChange }) {
|
|
@@ -8482,7 +8646,8 @@ function VideoEditor({ block, onChange }) {
|
|
|
8482
8646
|
function BlockEditor({
|
|
8483
8647
|
block,
|
|
8484
8648
|
errors,
|
|
8485
|
-
onChange
|
|
8649
|
+
onChange,
|
|
8650
|
+
onDone
|
|
8486
8651
|
}) {
|
|
8487
8652
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
8488
8653
|
/* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "text-sm font-semibold text-foreground", children: [
|
|
@@ -8490,7 +8655,19 @@ function BlockEditor({
|
|
|
8490
8655
|
labelForBlockType(block.type)
|
|
8491
8656
|
] }) }),
|
|
8492
8657
|
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,
|
|
8493
|
-
dispatch(block, onChange)
|
|
8658
|
+
dispatch(block, onChange),
|
|
8659
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8660
|
+
AdvancedIdField,
|
|
8661
|
+
{
|
|
8662
|
+
label: "Block ID",
|
|
8663
|
+
help: "Optional. Unique within the message or view. Slack returns it in interaction payloads.",
|
|
8664
|
+
htmlFor: "block-id",
|
|
8665
|
+
value: block.block_id,
|
|
8666
|
+
placeholder: "e.g. approval_row",
|
|
8667
|
+
onChange: (next) => onChange({ ...block, block_id: next })
|
|
8668
|
+
}
|
|
8669
|
+
),
|
|
8670
|
+
onDone ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end border-t pt-3", children: /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", size: "sm", onClick: onDone, children: "Done" }) }) : null
|
|
8494
8671
|
] });
|
|
8495
8672
|
}
|
|
8496
8673
|
function dispatch(block, onChange) {
|
|
@@ -8707,7 +8884,8 @@ function BlockRow({
|
|
|
8707
8884
|
{
|
|
8708
8885
|
block: builderBlock.block,
|
|
8709
8886
|
errors,
|
|
8710
|
-
onChange: (next) => onUpdate(builderBlock.id, next)
|
|
8887
|
+
onChange: (next) => onUpdate(builderBlock.id, next),
|
|
8888
|
+
onDone: () => onOpenChange?.(false)
|
|
8711
8889
|
}
|
|
8712
8890
|
) })
|
|
8713
8891
|
] }),
|
|
@@ -8971,7 +9149,15 @@ function ContainerRow({
|
|
|
8971
9149
|
]
|
|
8972
9150
|
}
|
|
8973
9151
|
) }),
|
|
8974
|
-
/* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "w-[min(32rem,calc(100vw-1.5rem))] sm:w-[32rem]", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9152
|
+
/* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "w-[min(32rem,calc(100vw-1.5rem))] sm:w-[32rem]", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9153
|
+
BlockEditor,
|
|
9154
|
+
{
|
|
9155
|
+
block,
|
|
9156
|
+
errors,
|
|
9157
|
+
onChange: (next) => onUpdate(id, next),
|
|
9158
|
+
onDone: () => onOpenBlockChange?.(null)
|
|
9159
|
+
}
|
|
9160
|
+
) })
|
|
8975
9161
|
] }),
|
|
8976
9162
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8977
9163
|
"div",
|
|
@@ -9452,6 +9638,10 @@ function formatMessageTs(ts) {
|
|
|
9452
9638
|
}
|
|
9453
9639
|
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";
|
|
9454
9640
|
function Toolbar2({
|
|
9641
|
+
canUndo = false,
|
|
9642
|
+
canRedo = false,
|
|
9643
|
+
onUndo,
|
|
9644
|
+
onRedo,
|
|
9455
9645
|
onClear,
|
|
9456
9646
|
onOpenJson,
|
|
9457
9647
|
onOpenIssues,
|
|
@@ -9565,6 +9755,36 @@ function Toolbar2({
|
|
|
9565
9755
|
) : null
|
|
9566
9756
|
] }),
|
|
9567
9757
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 sm:gap-2", children: [
|
|
9758
|
+
onUndo && onRedo ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
|
|
9759
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9760
|
+
Button,
|
|
9761
|
+
{
|
|
9762
|
+
type: "button",
|
|
9763
|
+
variant: "ghost",
|
|
9764
|
+
size: "sm",
|
|
9765
|
+
onClick: onUndo,
|
|
9766
|
+
disabled: !canUndo,
|
|
9767
|
+
"aria-label": "Undo",
|
|
9768
|
+
title: "Undo (Ctrl+Z)",
|
|
9769
|
+
className: "px-2",
|
|
9770
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Undo2, { className: "h-3.5 w-3.5" })
|
|
9771
|
+
}
|
|
9772
|
+
),
|
|
9773
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9774
|
+
Button,
|
|
9775
|
+
{
|
|
9776
|
+
type: "button",
|
|
9777
|
+
variant: "ghost",
|
|
9778
|
+
size: "sm",
|
|
9779
|
+
onClick: onRedo,
|
|
9780
|
+
disabled: !canRedo,
|
|
9781
|
+
"aria-label": "Redo",
|
|
9782
|
+
title: "Redo (Ctrl+Shift+Z)",
|
|
9783
|
+
className: "px-2",
|
|
9784
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Redo2, { className: "h-3.5 w-3.5" })
|
|
9785
|
+
}
|
|
9786
|
+
)
|
|
9787
|
+
] }) : null,
|
|
9568
9788
|
errorCount > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9569
9789
|
Button,
|
|
9570
9790
|
{
|
|
@@ -9965,7 +10185,22 @@ function BlockKitchen(props) {
|
|
|
9965
10185
|
Boolean(primaryAction && sendEnabled),
|
|
9966
10186
|
"[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`."
|
|
9967
10187
|
);
|
|
9968
|
-
const {
|
|
10188
|
+
const {
|
|
10189
|
+
blocks,
|
|
10190
|
+
addBlock,
|
|
10191
|
+
addChild,
|
|
10192
|
+
updateBlock,
|
|
10193
|
+
removeBlock,
|
|
10194
|
+
duplicateBlock,
|
|
10195
|
+
reorderBlock,
|
|
10196
|
+
moveBlock,
|
|
10197
|
+
replaceAll,
|
|
10198
|
+
resetAll,
|
|
10199
|
+
undo,
|
|
10200
|
+
redo,
|
|
10201
|
+
canUndo,
|
|
10202
|
+
canRedo
|
|
10203
|
+
} = useBlockKitchenState({ initialBlocks: seededBlocks, onChange });
|
|
9969
10204
|
const childParentById = React.useMemo(() => {
|
|
9970
10205
|
const map = /* @__PURE__ */ new Map();
|
|
9971
10206
|
for (const top of blocks) {
|
|
@@ -10081,6 +10316,30 @@ function BlockKitchen(props) {
|
|
|
10081
10316
|
const handleDragCancel = React.useCallback(() => {
|
|
10082
10317
|
setActivePaletteVariantId(null);
|
|
10083
10318
|
}, []);
|
|
10319
|
+
const handleKeyDown = React.useCallback(
|
|
10320
|
+
(event) => {
|
|
10321
|
+
if (!(event.metaKey || event.ctrlKey) || event.altKey) {
|
|
10322
|
+
return;
|
|
10323
|
+
}
|
|
10324
|
+
const key = event.key.toLowerCase();
|
|
10325
|
+
const isUndo = key === "z" && !event.shiftKey;
|
|
10326
|
+
const isRedo = key === "y" || key === "z" && event.shiftKey;
|
|
10327
|
+
if (!isUndo && !isRedo) {
|
|
10328
|
+
return;
|
|
10329
|
+
}
|
|
10330
|
+
const target = event.target;
|
|
10331
|
+
if (target && (target.isContentEditable || ["INPUT", "TEXTAREA", "SELECT"].includes(target.tagName))) {
|
|
10332
|
+
return;
|
|
10333
|
+
}
|
|
10334
|
+
event.preventDefault();
|
|
10335
|
+
if (isRedo) {
|
|
10336
|
+
if (canRedo) redo();
|
|
10337
|
+
} else if (canUndo) {
|
|
10338
|
+
undo();
|
|
10339
|
+
}
|
|
10340
|
+
},
|
|
10341
|
+
[canRedo, canUndo, redo, undo]
|
|
10342
|
+
);
|
|
10084
10343
|
const activePaletteVariant = activePaletteVariantId ? variantById.get(activePaletteVariantId) : null;
|
|
10085
10344
|
const blockPayloads = blocks.map((b) => b.block);
|
|
10086
10345
|
return /* @__PURE__ */ jsxRuntime.jsx(BrandThemeScope, { theme, children: /* @__PURE__ */ jsxRuntime.jsx(CustomEmojiProvider, { customEmojis, children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -10092,91 +10351,102 @@ function BlockKitchen(props) {
|
|
|
10092
10351
|
onDragEnd: handleDragEnd,
|
|
10093
10352
|
onDragCancel: handleDragCancel,
|
|
10094
10353
|
children: [
|
|
10095
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10096
|
-
|
|
10097
|
-
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
10104
|
-
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
|
|
10109
|
-
|
|
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
|
-
|
|
10354
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10355
|
+
"div",
|
|
10356
|
+
{
|
|
10357
|
+
className: "bk-root flex h-full w-full flex-col overflow-hidden rounded-md border bg-background text-foreground",
|
|
10358
|
+
onKeyDown: handleKeyDown,
|
|
10359
|
+
children: [
|
|
10360
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10361
|
+
Toolbar2,
|
|
10362
|
+
{
|
|
10363
|
+
canUndo,
|
|
10364
|
+
canRedo,
|
|
10365
|
+
onUndo: undo,
|
|
10366
|
+
onRedo: redo,
|
|
10367
|
+
onClear: () => replaceAll([]),
|
|
10368
|
+
onOpenJson: () => setJsonOpen(true),
|
|
10369
|
+
onOpenIssues: () => setIssuesOpen(true),
|
|
10370
|
+
onOpenSend: () => setSendOpen(true),
|
|
10371
|
+
onOpenPalette: () => setPaletteOpen(true),
|
|
10372
|
+
canSend: blocks.length > 0,
|
|
10373
|
+
canClear: blocks.length > 0,
|
|
10374
|
+
errorCount: validation.total,
|
|
10375
|
+
previewTheme,
|
|
10376
|
+
onPreviewThemeChange: setUncontrolledPreviewTheme,
|
|
10377
|
+
previewSurface,
|
|
10378
|
+
onPreviewSurfaceChange: setPreviewSurface,
|
|
10379
|
+
allowedSurfaces,
|
|
10380
|
+
showThemeControl: isPreviewThemeControlled ? false : showThemeControl,
|
|
10381
|
+
docsLink,
|
|
10382
|
+
showSend: sendEnabled,
|
|
10383
|
+
primaryAction: !sendEnabled && primaryAction ? {
|
|
10384
|
+
label: primaryAction.label,
|
|
10385
|
+
onClick: () => primaryAction.onClick({
|
|
10386
|
+
blocks: blockPayloads,
|
|
10387
|
+
validation: validationSummary,
|
|
10388
|
+
loadedMessage: activeEditTarget
|
|
10389
|
+
}),
|
|
10390
|
+
disabled: primaryAction.disableWhenInvalid ? !validationSummary.valid : false
|
|
10391
|
+
} : null,
|
|
10392
|
+
sendButtonLabel,
|
|
10393
|
+
loadEnabled,
|
|
10394
|
+
updateEnabled: Boolean(onUpdate),
|
|
10395
|
+
editBadge: activeEditTarget ? {
|
|
10396
|
+
channelLabel: activeEditTarget.channelName ? `#${activeEditTarget.channelName}` : activeEditTarget.channelId,
|
|
10397
|
+
ts: activeEditTarget.ts
|
|
10398
|
+
} : null,
|
|
10399
|
+
onOpenLoad: () => setLoadOpen(true),
|
|
10400
|
+
onOpenUpdate: () => setUpdateOpen(true),
|
|
10401
|
+
onExitEdit: () => {
|
|
10402
|
+
if (sendEnabled) {
|
|
10403
|
+
setEditTarget(null);
|
|
10404
|
+
resetAll([]);
|
|
10405
|
+
setLoadOpen(true);
|
|
10406
|
+
return;
|
|
10407
|
+
}
|
|
10408
|
+
setEditTarget(null);
|
|
10409
|
+
},
|
|
10410
|
+
loadButtonLabel,
|
|
10411
|
+
updateButtonLabel
|
|
10139
10412
|
}
|
|
10140
|
-
|
|
10141
|
-
|
|
10142
|
-
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
|
|
10146
|
-
|
|
10147
|
-
|
|
10148
|
-
|
|
10149
|
-
|
|
10150
|
-
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
|
|
10157
|
-
|
|
10158
|
-
|
|
10159
|
-
|
|
10160
|
-
|
|
10161
|
-
|
|
10162
|
-
|
|
10163
|
-
|
|
10164
|
-
|
|
10165
|
-
|
|
10166
|
-
|
|
10167
|
-
|
|
10168
|
-
|
|
10169
|
-
|
|
10170
|
-
|
|
10171
|
-
|
|
10172
|
-
|
|
10173
|
-
|
|
10174
|
-
|
|
10175
|
-
|
|
10176
|
-
|
|
10177
|
-
)
|
|
10178
|
-
] })
|
|
10179
|
-
] }),
|
|
10413
|
+
),
|
|
10414
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 items-stretch", children: [
|
|
10415
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden min-h-0 md:flex", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10416
|
+
Palette,
|
|
10417
|
+
{
|
|
10418
|
+
onAddBlock: (block) => addBlock(block),
|
|
10419
|
+
sections: paletteSections,
|
|
10420
|
+
showSearch: showPaletteSearch,
|
|
10421
|
+
searchPlaceholder: paletteSearchPlaceholder,
|
|
10422
|
+
defaultOpenSections
|
|
10423
|
+
}
|
|
10424
|
+
) }),
|
|
10425
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10426
|
+
Surface,
|
|
10427
|
+
{
|
|
10428
|
+
blocks,
|
|
10429
|
+
workspaceName,
|
|
10430
|
+
authorName: activeEditTarget?.username,
|
|
10431
|
+
authorIcon: activeEditTarget?.iconUrl,
|
|
10432
|
+
previewHooks: mergedPreviewHooks,
|
|
10433
|
+
previewTheme,
|
|
10434
|
+
previewSurface,
|
|
10435
|
+
errorsByBlockId: validation.byBlockId,
|
|
10436
|
+
openBlockId,
|
|
10437
|
+
onOpenBlockChange: setOpenBlockId,
|
|
10438
|
+
onUpdate: updateBlock,
|
|
10439
|
+
onDuplicate: duplicateBlock,
|
|
10440
|
+
onDelete: removeBlock,
|
|
10441
|
+
onReorder: reorderBlock,
|
|
10442
|
+
isPaletteDrag: activePaletteVariant !== null,
|
|
10443
|
+
onOpenPalette: () => setPaletteOpen(true)
|
|
10444
|
+
}
|
|
10445
|
+
)
|
|
10446
|
+
] })
|
|
10447
|
+
]
|
|
10448
|
+
}
|
|
10449
|
+
),
|
|
10180
10450
|
/* @__PURE__ */ jsxRuntime.jsx(core.DragOverlay, { dropAnimation: null, children: activePaletteVariant ? /* @__PURE__ */ jsxRuntime.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: [
|
|
10181
10451
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.GripVertical, { className: "h-3 w-3 shrink-0" }),
|
|
10182
10452
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: activePaletteVariant.label })
|
|
@@ -10253,13 +10523,13 @@ function BlockKitchen(props) {
|
|
|
10253
10523
|
loadRecentMessages: loading.loadRecentMessages,
|
|
10254
10524
|
loadChannels: recentChannelSource,
|
|
10255
10525
|
onLoaded: (result) => {
|
|
10256
|
-
|
|
10526
|
+
resetAll(result.blocks);
|
|
10257
10527
|
setEditTarget(toLoadedMessage(result));
|
|
10258
10528
|
setLoadOpen(false);
|
|
10259
10529
|
},
|
|
10260
10530
|
onOpenAsNew: (loadedBlocks) => {
|
|
10261
10531
|
if (loadedBlocks) {
|
|
10262
|
-
|
|
10532
|
+
resetAll(loadedBlocks);
|
|
10263
10533
|
}
|
|
10264
10534
|
setEditTarget(null);
|
|
10265
10535
|
setLoadOpen(false);
|