@tightknitai/block-kitchen 0.10.25 → 0.10.27
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 +4 -1
- package/dist/helpers.d.cts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.cjs +437 -85
- 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 +438 -86
- package/dist/index.js.map +1 -1
- package/dist/{palette-DTE9U5si.d.cts → palette-xi4VWU0p.d.cts} +37 -1
- package/dist/{palette-DTE9U5si.d.ts → palette-xi4VWU0p.d.ts} +37 -1
- package/dist/palette.cjs.map +1 -1
- package/dist/palette.d.cts +1 -1
- package/dist/palette.d.ts +1 -1
- package/dist/palette.js.map +1 -1
- package/dist/styles.css +2 -2
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -1958,6 +1958,36 @@ function CustomEmojiProvider({ customEmojis, children }) {
|
|
|
1958
1958
|
function useCustomEmojis() {
|
|
1959
1959
|
return React.useContext(CustomEmojiContext);
|
|
1960
1960
|
}
|
|
1961
|
+
var DEFAULT_IMAGE_UPLOAD_ACCEPT = ["image/png", "image/jpeg", "image/gif"];
|
|
1962
|
+
var ImageUploadContext = React.createContext(null);
|
|
1963
|
+
function ImageUploadProvider({
|
|
1964
|
+
imageUpload,
|
|
1965
|
+
children
|
|
1966
|
+
}) {
|
|
1967
|
+
const uploadImage = imageUpload?.uploadImage;
|
|
1968
|
+
const accept = imageUpload?.accept;
|
|
1969
|
+
const value = React.useMemo(
|
|
1970
|
+
() => uploadImage ? { uploadImage, accept: accept ?? DEFAULT_IMAGE_UPLOAD_ACCEPT } : null,
|
|
1971
|
+
[uploadImage, accept]
|
|
1972
|
+
);
|
|
1973
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ImageUploadContext.Provider, { value, children });
|
|
1974
|
+
}
|
|
1975
|
+
function useImageUpload() {
|
|
1976
|
+
return React.useContext(ImageUploadContext);
|
|
1977
|
+
}
|
|
1978
|
+
function isAcceptedImage(file, accept) {
|
|
1979
|
+
return accept.includes(file.type);
|
|
1980
|
+
}
|
|
1981
|
+
function uploadErrorMessage(error) {
|
|
1982
|
+
return error instanceof Error && error.message ? error.message : "Upload failed. Try again.";
|
|
1983
|
+
}
|
|
1984
|
+
function isFileDrag(dataTransfer) {
|
|
1985
|
+
return Boolean(dataTransfer && Array.from(dataTransfer.types).includes("Files"));
|
|
1986
|
+
}
|
|
1987
|
+
function formatList(accept) {
|
|
1988
|
+
const names = accept.map((type) => type.replace(/^image\//, "").toUpperCase());
|
|
1989
|
+
return names.length > 1 ? `${names.slice(0, -1).join(", ")} or ${names[names.length - 1]}` : names[0] ?? "";
|
|
1990
|
+
}
|
|
1961
1991
|
var MentionsContext = React.createContext(null);
|
|
1962
1992
|
function MentionsProvider({ mentions, children }) {
|
|
1963
1993
|
return /* @__PURE__ */ jsxRuntime.jsx(MentionsContext.Provider, { value: mentions ?? null, children });
|
|
@@ -3269,6 +3299,13 @@ var PopoverContent = React__namespace.forwardRef(({ className, align = "start",
|
|
|
3269
3299
|
}
|
|
3270
3300
|
) }));
|
|
3271
3301
|
PopoverContent.displayName = PopoverPrimitive__namespace.Content.displayName;
|
|
3302
|
+
function returnFocusUnlessMoved(event) {
|
|
3303
|
+
const active = document.activeElement;
|
|
3304
|
+
const closing = event.target instanceof Node ? event.target : null;
|
|
3305
|
+
if (active && active !== document.body && !closing?.contains(active)) {
|
|
3306
|
+
event.preventDefault();
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3272
3309
|
function matchesQuery(name, query) {
|
|
3273
3310
|
const needle = query.replace(/^\s*#\s*/, "").trim().toLowerCase();
|
|
3274
3311
|
return needle === "" || name.toLowerCase().includes(needle);
|
|
@@ -4504,7 +4541,7 @@ function PaletteItem({
|
|
|
4504
4541
|
{
|
|
4505
4542
|
ref: setNodeRef,
|
|
4506
4543
|
className: cn(
|
|
4507
|
-
"group flex items-
|
|
4544
|
+
"group flex items-start gap-2 rounded px-2 py-1 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-foreground has-[:focus-visible]:bg-accent has-[:focus-visible]:text-foreground",
|
|
4508
4545
|
isDragging && "opacity-50"
|
|
4509
4546
|
),
|
|
4510
4547
|
children: [
|
|
@@ -4512,16 +4549,12 @@ function PaletteItem({
|
|
|
4512
4549
|
"div",
|
|
4513
4550
|
{
|
|
4514
4551
|
ref: setActivatorNodeRef,
|
|
4515
|
-
className: "-my-1 flex min-w-0 flex-1 cursor-grab items-
|
|
4552
|
+
className: "-my-1 flex min-w-0 flex-1 cursor-grab items-start gap-2 rounded py-1 active:cursor-grabbing focus-visible:outline-none",
|
|
4516
4553
|
...attributes,
|
|
4517
4554
|
...listeners,
|
|
4518
4555
|
children: [
|
|
4519
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.GripVertical, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
4520
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4521
|
-
variant.badge ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4522
|
-
" ",
|
|
4523
|
-
/* @__PURE__ */ jsxRuntime.jsx(VariantBadge, { badge: variant.badge })
|
|
4524
|
-
] }) : null
|
|
4556
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.GripVertical, { className: "mt-[3px] h-3.5 w-3.5 shrink-0" }),
|
|
4557
|
+
/* @__PURE__ */ jsxRuntime.jsx(RailLabel, { variant })
|
|
4525
4558
|
]
|
|
4526
4559
|
}
|
|
4527
4560
|
),
|
|
@@ -4546,13 +4579,15 @@ function LockedPaletteItem({
|
|
|
4546
4579
|
}) {
|
|
4547
4580
|
const select = variant.onLockedSelect;
|
|
4548
4581
|
const className = cn(
|
|
4549
|
-
"flex w-full
|
|
4550
|
-
isSheet ? "min-h-11 gap-3 rounded-md px-3 py-2 text-sm font-medium" : "gap-2 rounded px-2 py-1 text-sm"
|
|
4582
|
+
"flex w-full text-left text-muted-foreground",
|
|
4583
|
+
isSheet ? "min-h-11 items-center gap-3 rounded-md px-3 py-2 text-sm font-medium" : "items-start gap-2 rounded px-2 py-1 text-sm"
|
|
4551
4584
|
);
|
|
4552
4585
|
const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4553
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { "aria-hidden": true, className: cn("shrink-0", isSheet ? "h-4 w-4" : "h-3.5 w-3.5") }),
|
|
4554
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4555
|
-
|
|
4586
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { "aria-hidden": true, className: cn("shrink-0", isSheet ? "h-4 w-4" : "mt-[3px] h-3.5 w-3.5") }),
|
|
4587
|
+
isSheet ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4588
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: variant.label }),
|
|
4589
|
+
variant.badge ? /* @__PURE__ */ jsxRuntime.jsx(VariantBadge, { badge: variant.badge }) : null
|
|
4590
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(RailLabel, { variant })
|
|
4556
4591
|
] });
|
|
4557
4592
|
if (!select) {
|
|
4558
4593
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-disabled": "true", className, children: content });
|
|
@@ -4574,12 +4609,31 @@ function LockedPaletteItem({
|
|
|
4574
4609
|
}
|
|
4575
4610
|
);
|
|
4576
4611
|
}
|
|
4612
|
+
function RailLabel({ variant }) {
|
|
4613
|
+
if (!variant.badge) {
|
|
4614
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: variant.label });
|
|
4615
|
+
}
|
|
4616
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col items-start gap-0.5", children: [
|
|
4617
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate", children: variant.label }),
|
|
4618
|
+
" ",
|
|
4619
|
+
/* @__PURE__ */ jsxRuntime.jsx(VariantBadge, { badge: variant.badge })
|
|
4620
|
+
] });
|
|
4621
|
+
}
|
|
4577
4622
|
function VariantBadge({ badge }) {
|
|
4578
4623
|
const Icon = badge.icon;
|
|
4579
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4624
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4625
|
+
"span",
|
|
4626
|
+
{
|
|
4627
|
+
className: cn(
|
|
4628
|
+
"inline-flex shrink-0 items-center gap-1 rounded-full border bg-background px-1.5 text-[10px] font-medium leading-4 text-muted-foreground",
|
|
4629
|
+
badge.className
|
|
4630
|
+
),
|
|
4631
|
+
children: [
|
|
4632
|
+
Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { "aria-hidden": true, className: "h-2.5 w-2.5 shrink-0" }) : null,
|
|
4633
|
+
badge.label
|
|
4634
|
+
]
|
|
4635
|
+
}
|
|
4636
|
+
);
|
|
4583
4637
|
}
|
|
4584
4638
|
function SendDialog({
|
|
4585
4639
|
open,
|
|
@@ -4743,6 +4797,73 @@ function SendDialog({
|
|
|
4743
4797
|
] })
|
|
4744
4798
|
] }) });
|
|
4745
4799
|
}
|
|
4800
|
+
var ALT_TEXT_MAX_LENGTH = 2e3;
|
|
4801
|
+
function altTextFromFileName(file) {
|
|
4802
|
+
const name = file.name.replace(/\.[^.]+$/, "").trim();
|
|
4803
|
+
return (name || "Image").slice(0, ALT_TEXT_MAX_LENGTH);
|
|
4804
|
+
}
|
|
4805
|
+
function useCanvasImageDrop({
|
|
4806
|
+
upload,
|
|
4807
|
+
enabled,
|
|
4808
|
+
onAddBlock
|
|
4809
|
+
}) {
|
|
4810
|
+
const [dragging, setDragging] = React.useState(false);
|
|
4811
|
+
const [pending, setPending] = React.useState(0);
|
|
4812
|
+
const [error, setError] = React.useState(null);
|
|
4813
|
+
const onAddBlockRef = React.useRef(onAddBlock);
|
|
4814
|
+
onAddBlockRef.current = onAddBlock;
|
|
4815
|
+
const addFiles = async (activeUpload, files) => {
|
|
4816
|
+
const images = files.filter((file) => isAcceptedImage(file, activeUpload.accept));
|
|
4817
|
+
const skipped = files.length - images.length;
|
|
4818
|
+
setError(
|
|
4819
|
+
skipped > 0 ? `${skipped === 1 ? "1 file was" : `${skipped} files were`} skipped. Only ${formatList(activeUpload.accept)} images can be added.` : null
|
|
4820
|
+
);
|
|
4821
|
+
if (images.length === 0) {
|
|
4822
|
+
return;
|
|
4823
|
+
}
|
|
4824
|
+
setPending((count) => count + images.length);
|
|
4825
|
+
const results = await Promise.allSettled(images.map((file) => activeUpload.uploadImage(file)));
|
|
4826
|
+
setPending((count) => count - images.length);
|
|
4827
|
+
const failures = [];
|
|
4828
|
+
results.forEach((result, idx) => {
|
|
4829
|
+
const file = images[idx];
|
|
4830
|
+
if (result.status === "fulfilled") {
|
|
4831
|
+
onAddBlockRef.current?.({ type: "image", image_url: result.value.url, alt_text: altTextFromFileName(file) });
|
|
4832
|
+
} else {
|
|
4833
|
+
failures.push(`Couldn't upload "${file.name}": ${uploadErrorMessage(result.reason)}`);
|
|
4834
|
+
}
|
|
4835
|
+
});
|
|
4836
|
+
if (failures.length > 0) {
|
|
4837
|
+
setError(failures.join(" "));
|
|
4838
|
+
}
|
|
4839
|
+
};
|
|
4840
|
+
const isOwnEvent = (e) => isFileDrag(e.dataTransfer) && e.currentTarget.contains(e.target);
|
|
4841
|
+
const handlers = upload && enabled && onAddBlock ? {
|
|
4842
|
+
onDragOver: (e) => {
|
|
4843
|
+
if (!isOwnEvent(e)) {
|
|
4844
|
+
return;
|
|
4845
|
+
}
|
|
4846
|
+
e.preventDefault();
|
|
4847
|
+
e.dataTransfer.dropEffect = "copy";
|
|
4848
|
+
setDragging(true);
|
|
4849
|
+
},
|
|
4850
|
+
onDragLeave: (e) => {
|
|
4851
|
+
const next = e.relatedTarget;
|
|
4852
|
+
if (!next || !e.currentTarget.contains(next)) {
|
|
4853
|
+
setDragging(false);
|
|
4854
|
+
}
|
|
4855
|
+
},
|
|
4856
|
+
onDrop: (e) => {
|
|
4857
|
+
if (!isOwnEvent(e)) {
|
|
4858
|
+
return;
|
|
4859
|
+
}
|
|
4860
|
+
e.preventDefault();
|
|
4861
|
+
setDragging(false);
|
|
4862
|
+
void addFiles(upload, Array.from(e.dataTransfer.files));
|
|
4863
|
+
}
|
|
4864
|
+
} : void 0;
|
|
4865
|
+
return { handlers, dragging, pending, error, dismissError: () => setError(null) };
|
|
4866
|
+
}
|
|
4746
4867
|
function BlockActionButtons({
|
|
4747
4868
|
actions,
|
|
4748
4869
|
position,
|
|
@@ -4997,6 +5118,129 @@ function AlertEditor({ block, onChange }) {
|
|
|
4997
5118
|
) })
|
|
4998
5119
|
] });
|
|
4999
5120
|
}
|
|
5121
|
+
function ImageUrlInput({
|
|
5122
|
+
id,
|
|
5123
|
+
value,
|
|
5124
|
+
placeholder,
|
|
5125
|
+
onChange
|
|
5126
|
+
}) {
|
|
5127
|
+
const upload = useImageUpload();
|
|
5128
|
+
const input = /* @__PURE__ */ jsxRuntime.jsx(Input, { id, type: "url", value, placeholder, onChange: (e) => onChange(e.target.value) });
|
|
5129
|
+
if (!upload) {
|
|
5130
|
+
return input;
|
|
5131
|
+
}
|
|
5132
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
5133
|
+
/* @__PURE__ */ jsxRuntime.jsx(UploadDropZone, { upload, inputId: id, onUploaded: onChange, variant: "inline" }),
|
|
5134
|
+
input
|
|
5135
|
+
] });
|
|
5136
|
+
}
|
|
5137
|
+
function UploadDropZone({
|
|
5138
|
+
upload,
|
|
5139
|
+
inputId,
|
|
5140
|
+
onUploaded,
|
|
5141
|
+
variant
|
|
5142
|
+
}) {
|
|
5143
|
+
const [uploading, setUploading] = React.useState(false);
|
|
5144
|
+
const [dragging, setDragging] = React.useState(false);
|
|
5145
|
+
const [error, setError] = React.useState(null);
|
|
5146
|
+
const fileInputRef = React.useRef(null);
|
|
5147
|
+
const onUploadedRef = React.useRef(onUploaded);
|
|
5148
|
+
onUploadedRef.current = onUploaded;
|
|
5149
|
+
const uploadFile = async (file) => {
|
|
5150
|
+
if (!isAcceptedImage(file, upload.accept)) {
|
|
5151
|
+
setError(`"${file.name}" isn't a supported image. Use ${formatList(upload.accept)}.`);
|
|
5152
|
+
return;
|
|
5153
|
+
}
|
|
5154
|
+
setError(null);
|
|
5155
|
+
setUploading(true);
|
|
5156
|
+
try {
|
|
5157
|
+
const { url } = await upload.uploadImage(file);
|
|
5158
|
+
onUploadedRef.current(url);
|
|
5159
|
+
} catch (err) {
|
|
5160
|
+
setError(uploadErrorMessage(err));
|
|
5161
|
+
} finally {
|
|
5162
|
+
setUploading(false);
|
|
5163
|
+
}
|
|
5164
|
+
};
|
|
5165
|
+
const onDragOver = (e) => {
|
|
5166
|
+
if (!isFileDrag(e.dataTransfer)) {
|
|
5167
|
+
return;
|
|
5168
|
+
}
|
|
5169
|
+
e.preventDefault();
|
|
5170
|
+
e.stopPropagation();
|
|
5171
|
+
setDragging(true);
|
|
5172
|
+
};
|
|
5173
|
+
const onDrop = (e) => {
|
|
5174
|
+
if (!isFileDrag(e.dataTransfer)) {
|
|
5175
|
+
return;
|
|
5176
|
+
}
|
|
5177
|
+
e.preventDefault();
|
|
5178
|
+
e.stopPropagation();
|
|
5179
|
+
setDragging(false);
|
|
5180
|
+
const [file] = Array.from(e.dataTransfer.files);
|
|
5181
|
+
if (file && !uploading) {
|
|
5182
|
+
void uploadFile(file);
|
|
5183
|
+
}
|
|
5184
|
+
};
|
|
5185
|
+
const fileInput = /* @__PURE__ */ jsxRuntime.jsx(
|
|
5186
|
+
"input",
|
|
5187
|
+
{
|
|
5188
|
+
ref: fileInputRef,
|
|
5189
|
+
id: `${inputId}-file`,
|
|
5190
|
+
type: "file",
|
|
5191
|
+
accept: upload.accept.join(","),
|
|
5192
|
+
className: "hidden",
|
|
5193
|
+
tabIndex: -1,
|
|
5194
|
+
"aria-hidden": "true",
|
|
5195
|
+
onChange: (e) => {
|
|
5196
|
+
const file = e.target.files?.[0];
|
|
5197
|
+
e.target.value = "";
|
|
5198
|
+
if (file) {
|
|
5199
|
+
void uploadFile(file);
|
|
5200
|
+
}
|
|
5201
|
+
}
|
|
5202
|
+
}
|
|
5203
|
+
);
|
|
5204
|
+
const pickButton = (label) => /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", size: "sm", className: "h-7", disabled: uploading, onClick: () => fileInputRef.current?.click(), children: label });
|
|
5205
|
+
const dropHandlers = { onDragOver, onDragLeave: () => setDragging(false), onDrop };
|
|
5206
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5207
|
+
variant === "panel" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5208
|
+
"section",
|
|
5209
|
+
{
|
|
5210
|
+
"aria-label": "Upload an image",
|
|
5211
|
+
...dropHandlers,
|
|
5212
|
+
className: cn(
|
|
5213
|
+
"flex flex-col items-center justify-center gap-2 rounded-md border border-dashed px-4 py-6 text-center text-xs text-muted-foreground transition-colors",
|
|
5214
|
+
dragging && "border-primary bg-primary/5 text-primary"
|
|
5215
|
+
),
|
|
5216
|
+
children: [
|
|
5217
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: cn("h-5 w-5", uploading && "animate-pulse"), "aria-hidden": "true" }),
|
|
5218
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-live": "polite", children: uploading ? "Uploading\u2026" : dragging ? "Drop to upload" : "Drag an image here, or" }),
|
|
5219
|
+
pickButton("Choose file"),
|
|
5220
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px]", children: formatList(upload.accept) }),
|
|
5221
|
+
fileInput
|
|
5222
|
+
]
|
|
5223
|
+
}
|
|
5224
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5225
|
+
"section",
|
|
5226
|
+
{
|
|
5227
|
+
"aria-label": "Upload an image",
|
|
5228
|
+
...dropHandlers,
|
|
5229
|
+
className: cn(
|
|
5230
|
+
"flex items-center gap-2 rounded-md border border-dashed px-3 py-2 text-[11px] text-muted-foreground transition-colors",
|
|
5231
|
+
dragging && "border-primary bg-primary/5 text-primary"
|
|
5232
|
+
),
|
|
5233
|
+
children: [
|
|
5234
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: cn("h-3.5 w-3.5 shrink-0", uploading && "animate-pulse"), "aria-hidden": "true" }),
|
|
5235
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", "aria-live": "polite", children: uploading ? "Uploading\u2026" : dragging ? "Drop to upload" : "Drop an image here, or paste a URL below" }),
|
|
5236
|
+
pickButton("Upload image"),
|
|
5237
|
+
fileInput
|
|
5238
|
+
]
|
|
5239
|
+
}
|
|
5240
|
+
),
|
|
5241
|
+
error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-[11px] leading-snug text-destructive", children: error }) : null
|
|
5242
|
+
] });
|
|
5243
|
+
}
|
|
5000
5244
|
function CardEditor({
|
|
5001
5245
|
block,
|
|
5002
5246
|
onChange,
|
|
@@ -5103,13 +5347,12 @@ function ImageFields({
|
|
|
5103
5347
|
};
|
|
5104
5348
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 rounded-md border bg-muted/20 p-3", children: [
|
|
5105
5349
|
/* @__PURE__ */ jsxRuntime.jsx(EditorField, { label, help, htmlFor: `${idPrefix}-url`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5106
|
-
|
|
5350
|
+
ImageUrlInput,
|
|
5107
5351
|
{
|
|
5108
5352
|
id: `${idPrefix}-url`,
|
|
5109
|
-
type: "url",
|
|
5110
5353
|
value: url,
|
|
5111
5354
|
placeholder: "e.g. https://example.com/image.png",
|
|
5112
|
-
onChange: (
|
|
5355
|
+
onChange: (next) => update({ url: next })
|
|
5113
5356
|
}
|
|
5114
5357
|
) }),
|
|
5115
5358
|
/* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Alt text", help: "Describes the image for screen readers.", htmlFor: `${idPrefix}-alt`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -7669,15 +7912,14 @@ function ContainerEditor({ block, onChange }) {
|
|
|
7669
7912
|
}
|
|
7670
7913
|
) : null,
|
|
7671
7914
|
/* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Icon URL", help: "Optional image shown left of the title.", htmlFor: "container-icon", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7672
|
-
|
|
7915
|
+
ImageUrlInput,
|
|
7673
7916
|
{
|
|
7674
7917
|
id: "container-icon",
|
|
7675
|
-
type: "url",
|
|
7676
7918
|
value: iconUrl,
|
|
7677
7919
|
placeholder: "https://example.com/icon.png",
|
|
7678
|
-
onChange: (
|
|
7920
|
+
onChange: (url) => onChange({
|
|
7679
7921
|
...block,
|
|
7680
|
-
icon:
|
|
7922
|
+
icon: url ? { type: "image", image_url: url, alt_text: iconAlt || "Container icon" } : void 0
|
|
7681
7923
|
})
|
|
7682
7924
|
}
|
|
7683
7925
|
) }),
|
|
@@ -8175,13 +8417,12 @@ function ImageItemCard({
|
|
|
8175
8417
|
help: "A publicly accessible image URL. Best at small sizes (around 20px).",
|
|
8176
8418
|
htmlFor: `ctx-img-url-${index}`,
|
|
8177
8419
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8178
|
-
|
|
8420
|
+
ImageUrlInput,
|
|
8179
8421
|
{
|
|
8180
8422
|
id: `ctx-img-url-${index}`,
|
|
8181
|
-
type: "url",
|
|
8182
8423
|
value: element.image_url,
|
|
8183
8424
|
placeholder: "e.g. https://example.com/avatar.png",
|
|
8184
|
-
onChange: (
|
|
8425
|
+
onChange: (url) => onChange({ ...element, image_url: url })
|
|
8185
8426
|
}
|
|
8186
8427
|
)
|
|
8187
8428
|
}
|
|
@@ -8923,36 +9164,44 @@ function HeaderEditor({ block, onChange }) {
|
|
|
8923
9164
|
] });
|
|
8924
9165
|
}
|
|
8925
9166
|
function ImageEditor({ block, onChange }) {
|
|
8926
|
-
const
|
|
9167
|
+
const upload = useImageUpload();
|
|
9168
|
+
const [urlSource, setUrlSource] = React.useState(upload ? "upload" : "url");
|
|
9169
|
+
const isSlackFile = "slack_file" in block;
|
|
9170
|
+
const source = isSlackFile ? "slack_file" : upload ? urlSource : "url";
|
|
8927
9171
|
const titleText = block.title?.text ?? "";
|
|
8928
9172
|
const setSource = (next) => {
|
|
8929
9173
|
if (next === source) {
|
|
8930
9174
|
return;
|
|
8931
9175
|
}
|
|
8932
|
-
if (next
|
|
9176
|
+
if (next !== "slack_file") {
|
|
9177
|
+
setUrlSource(next);
|
|
9178
|
+
}
|
|
9179
|
+
if (next !== "slack_file" && isSlackFile) {
|
|
8933
9180
|
const { slack_file: _omit, ...rest } = block;
|
|
8934
9181
|
onChange({ image_url: "", ...rest });
|
|
8935
|
-
} else {
|
|
9182
|
+
} else if (next === "slack_file") {
|
|
8936
9183
|
const { image_url: _omit, ...rest } = block;
|
|
8937
9184
|
onChange({ slack_file: { id: "" }, ...rest });
|
|
8938
9185
|
}
|
|
8939
9186
|
};
|
|
9187
|
+
const sourceOptions = [
|
|
9188
|
+
...upload ? [["upload", "Upload image"]] : [],
|
|
9189
|
+
["url", "Public URL"],
|
|
9190
|
+
["slack_file", "Slack file"]
|
|
9191
|
+
];
|
|
8940
9192
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
8941
9193
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8942
9194
|
EditorField,
|
|
8943
9195
|
{
|
|
8944
9196
|
label: "Image source",
|
|
8945
|
-
help: "Where the image comes from: a public URL, or a file already uploaded to your Slack workspace.",
|
|
9197
|
+
help: upload ? "Where the image comes from: a file from your device, a public URL, or a file already uploaded to your Slack workspace." : "Where the image comes from: a public URL, or a file already uploaded to your Slack workspace.",
|
|
8946
9198
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8947
9199
|
RadioGroup,
|
|
8948
9200
|
{
|
|
8949
9201
|
value: source,
|
|
8950
9202
|
onValueChange: (v) => setSource(v),
|
|
8951
9203
|
className: "flex flex-row flex-wrap gap-3",
|
|
8952
|
-
children: [
|
|
8953
|
-
["url", "Public URL"],
|
|
8954
|
-
["slack_file", "Slack file"]
|
|
8955
|
-
].map(([value, label]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
9204
|
+
children: sourceOptions.map(([value, label]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
8956
9205
|
/* @__PURE__ */ jsxRuntime.jsx(RadioGroupItem, { value, id: `img-source-${value}` }),
|
|
8957
9206
|
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `img-source-${value}`, className: "text-xs", children: label })
|
|
8958
9207
|
] }, value))
|
|
@@ -8960,7 +9209,15 @@ function ImageEditor({ block, onChange }) {
|
|
|
8960
9209
|
)
|
|
8961
9210
|
}
|
|
8962
9211
|
),
|
|
8963
|
-
"slack_file" in block ? /* @__PURE__ */ jsxRuntime.jsx(SlackFileFields, { block, onChange }) :
|
|
9212
|
+
"slack_file" in block ? /* @__PURE__ */ jsxRuntime.jsx(SlackFileFields, { block, onChange }) : source === "upload" && upload ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9213
|
+
UploadDropZone,
|
|
9214
|
+
{
|
|
9215
|
+
upload,
|
|
9216
|
+
inputId: "img-upload",
|
|
9217
|
+
variant: "panel",
|
|
9218
|
+
onUploaded: (url) => onChange({ ...block, image_url: url })
|
|
9219
|
+
}
|
|
9220
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Image URL", help: "A publicly accessible image URL (PNG, JPG, GIF).", htmlFor: "img-url", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8964
9221
|
Input,
|
|
8965
9222
|
{
|
|
8966
9223
|
id: "img-url",
|
|
@@ -10143,13 +10400,12 @@ function ImageAccessoryFields({ image, onChange }) {
|
|
|
10143
10400
|
help: "A publicly accessible image URL (PNG, JPG, GIF).",
|
|
10144
10401
|
htmlFor: "section-acc-img-url",
|
|
10145
10402
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10146
|
-
|
|
10403
|
+
ImageUrlInput,
|
|
10147
10404
|
{
|
|
10148
10405
|
id: "section-acc-img-url",
|
|
10149
|
-
type: "url",
|
|
10150
10406
|
value: image.image_url ?? "",
|
|
10151
10407
|
placeholder: "e.g. https://example.com/thumb.png",
|
|
10152
|
-
onChange: (
|
|
10408
|
+
onChange: (url) => onChange({ ...image, image_url: url })
|
|
10153
10409
|
}
|
|
10154
10410
|
)
|
|
10155
10411
|
}
|
|
@@ -10512,10 +10768,24 @@ function BlockEditor({
|
|
|
10512
10768
|
const custom = useCustomBlockEditor(block);
|
|
10513
10769
|
const CustomForm = custom?.component;
|
|
10514
10770
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
10515
|
-
/* @__PURE__ */ jsxRuntime.
|
|
10516
|
-
"
|
|
10517
|
-
|
|
10518
|
-
|
|
10771
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
10772
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "text-sm font-semibold text-foreground", children: [
|
|
10773
|
+
"Edit ",
|
|
10774
|
+
custom ? custom.label : labelForBlockType(block.type)
|
|
10775
|
+
] }),
|
|
10776
|
+
onDone ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
10777
|
+
Button,
|
|
10778
|
+
{
|
|
10779
|
+
type: "button",
|
|
10780
|
+
variant: "ghost",
|
|
10781
|
+
size: "icon",
|
|
10782
|
+
"aria-label": "Close editor",
|
|
10783
|
+
className: "-my-1 -mr-1 h-7 w-7 text-muted-foreground",
|
|
10784
|
+
onClick: onDone,
|
|
10785
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, {})
|
|
10786
|
+
}
|
|
10787
|
+
) : null
|
|
10788
|
+
] }),
|
|
10519
10789
|
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,
|
|
10520
10790
|
CustomForm ? /* @__PURE__ */ jsxRuntime.jsx(CustomForm, { block, onChange }) : dispatch(block, onChange),
|
|
10521
10791
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -10677,15 +10947,23 @@ function BlockRow({
|
|
|
10677
10947
|
children: preview
|
|
10678
10948
|
}
|
|
10679
10949
|
) }),
|
|
10680
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10681
|
-
|
|
10950
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10951
|
+
PopoverContent,
|
|
10682
10952
|
{
|
|
10683
|
-
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
10953
|
+
className: "w-[min(32rem,calc(100vw-1.5rem))] sm:w-[32rem]",
|
|
10954
|
+
align: "start",
|
|
10955
|
+
onCloseAutoFocus: returnFocusUnlessMoved,
|
|
10956
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10957
|
+
BlockEditor,
|
|
10958
|
+
{
|
|
10959
|
+
block: builderBlock.block,
|
|
10960
|
+
errors,
|
|
10961
|
+
onChange: (next) => onUpdate(builderBlock.id, next),
|
|
10962
|
+
onDone: () => onOpenChange?.(false)
|
|
10963
|
+
}
|
|
10964
|
+
)
|
|
10687
10965
|
}
|
|
10688
|
-
)
|
|
10966
|
+
)
|
|
10689
10967
|
] });
|
|
10690
10968
|
const adornment = position && renderBlockAdornment?.(position);
|
|
10691
10969
|
const hoverChrome = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
@@ -10951,7 +11229,7 @@ function ContainerRow({
|
|
|
10951
11229
|
hasErrors ? "border-destructive/60" : "border-border"
|
|
10952
11230
|
),
|
|
10953
11231
|
children: [
|
|
10954
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: isOpen, onOpenChange: (open) => onOpenBlockChange?.(
|
|
11232
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: isOpen, onOpenChange: (open) => onOpenBlockChange?.(id, open), children: [
|
|
10955
11233
|
/* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10956
11234
|
"div",
|
|
10957
11235
|
{
|
|
@@ -10963,7 +11241,7 @@ function ContainerRow({
|
|
|
10963
11241
|
onKeyDown: (e) => {
|
|
10964
11242
|
if (e.key === "Enter" || e.key === " ") {
|
|
10965
11243
|
e.preventDefault();
|
|
10966
|
-
onOpenBlockChange?.(!isOpen
|
|
11244
|
+
onOpenBlockChange?.(id, !isOpen);
|
|
10967
11245
|
}
|
|
10968
11246
|
},
|
|
10969
11247
|
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",
|
|
@@ -10977,15 +11255,23 @@ function ContainerRow({
|
|
|
10977
11255
|
]
|
|
10978
11256
|
}
|
|
10979
11257
|
) }),
|
|
10980
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10981
|
-
|
|
11258
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11259
|
+
PopoverContent,
|
|
10982
11260
|
{
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
11261
|
+
className: "w-[min(32rem,calc(100vw-1.5rem))] sm:w-[32rem]",
|
|
11262
|
+
align: "start",
|
|
11263
|
+
onCloseAutoFocus: returnFocusUnlessMoved,
|
|
11264
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11265
|
+
BlockEditor,
|
|
11266
|
+
{
|
|
11267
|
+
block,
|
|
11268
|
+
errors,
|
|
11269
|
+
onChange: (next) => onUpdate(id, next),
|
|
11270
|
+
onDone: () => onOpenBlockChange?.(id, false)
|
|
11271
|
+
}
|
|
11272
|
+
)
|
|
10987
11273
|
}
|
|
10988
|
-
)
|
|
11274
|
+
)
|
|
10989
11275
|
] }),
|
|
10990
11276
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10991
11277
|
"div",
|
|
@@ -11014,7 +11300,7 @@ function ContainerRow({
|
|
|
11014
11300
|
previewTheme,
|
|
11015
11301
|
errors: errorsByBlockId?.get(child.id),
|
|
11016
11302
|
isOpen: openBlockId === child.id,
|
|
11017
|
-
onOpenChange: (open) => onOpenBlockChange?.(
|
|
11303
|
+
onOpenChange: (open) => onOpenBlockChange?.(child.id, open),
|
|
11018
11304
|
onUpdate,
|
|
11019
11305
|
onDuplicate,
|
|
11020
11306
|
onDelete,
|
|
@@ -11049,7 +11335,7 @@ function ContainerRow({
|
|
|
11049
11335
|
{
|
|
11050
11336
|
type: "button",
|
|
11051
11337
|
"aria-label": `Show ${errors.length} validation ${errors.length === 1 ? "issue" : "issues"}`,
|
|
11052
|
-
onClick: () => onOpenBlockChange?.(id),
|
|
11338
|
+
onClick: () => onOpenBlockChange?.(id, true),
|
|
11053
11339
|
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",
|
|
11054
11340
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "h-3.5 w-3.5" })
|
|
11055
11341
|
}
|
|
@@ -11068,7 +11354,7 @@ function ContainerRow({
|
|
|
11068
11354
|
/* @__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" }) })
|
|
11069
11355
|
] }) : null,
|
|
11070
11356
|
/* @__PURE__ */ jsxRuntime.jsx(BlockActionButtons, { actions: blockActions, position, variant: "toolbar" }),
|
|
11071
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Edit", onClick: () => onOpenBlockChange?.(id), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-3.5 w-3.5" }) }),
|
|
11357
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Edit", onClick: () => onOpenBlockChange?.(id, true), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-3.5 w-3.5" }) }),
|
|
11072
11358
|
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Duplicate", onClick: () => onDuplicate(id), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-3.5 w-3.5" }) }),
|
|
11073
11359
|
/* @__PURE__ */ jsxRuntime.jsx(ToolbarButton2, { label: "Delete", destructive: true, onClick: () => onDelete(id), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" }) })
|
|
11074
11360
|
]
|
|
@@ -11101,7 +11387,7 @@ function ContainerRow({
|
|
|
11101
11387
|
{
|
|
11102
11388
|
type: "button",
|
|
11103
11389
|
"aria-label": "Edit container",
|
|
11104
|
-
onClick: () => onOpenBlockChange?.(id),
|
|
11390
|
+
onClick: () => onOpenBlockChange?.(id, true),
|
|
11105
11391
|
className: "flex h-9 w-9 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
11106
11392
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-4 w-4" })
|
|
11107
11393
|
}
|
|
@@ -11179,10 +11465,14 @@ function Surface({
|
|
|
11179
11465
|
isPaletteDrag = false,
|
|
11180
11466
|
onOpenPalette,
|
|
11181
11467
|
blockActions,
|
|
11182
|
-
renderBlockAdornment
|
|
11468
|
+
renderBlockAdornment,
|
|
11469
|
+
onAddBlock,
|
|
11470
|
+
imageDropEnabled = true
|
|
11183
11471
|
}) {
|
|
11184
11472
|
const { setNodeRef, isOver } = core.useDroppable({ id: SURFACE_DROPPABLE_ID });
|
|
11185
11473
|
const isDark = previewTheme === "dark";
|
|
11474
|
+
const imageDrop = useCanvasImageDrop({ upload: useImageUpload(), enabled: imageDropEnabled, onAddBlock });
|
|
11475
|
+
const isDropTarget = isPaletteDrag || imageDrop.dragging;
|
|
11186
11476
|
const showEndDropZone = isPaletteDrag && isOver && blocks.length > 0;
|
|
11187
11477
|
const blocksList = /* @__PURE__ */ jsxRuntime.jsx(
|
|
11188
11478
|
"div",
|
|
@@ -11191,10 +11481,19 @@ function Surface({
|
|
|
11191
11481
|
className: cn(
|
|
11192
11482
|
"flex min-h-[180px] flex-col px-3 py-2 transition-colors sm:min-h-[240px] sm:px-5",
|
|
11193
11483
|
isDark ? "bg-[#1a1d21]" : "bg-white",
|
|
11194
|
-
|
|
11195
|
-
isPaletteDrag && isOver && (isDark ? "bg-[#2c3036]" : "bg-[#eaf0ff]")
|
|
11484
|
+
isDropTarget && (isDark ? "bg-[#22262c] outline-2 outline-primary/40 -outline-offset-2 outline-dashed" : "bg-[#f5f8ff] outline-2 outline-primary/40 -outline-offset-2 outline-dashed"),
|
|
11485
|
+
(isPaletteDrag && isOver || imageDrop.dragging) && (isDark ? "bg-[#2c3036]" : "bg-[#eaf0ff]")
|
|
11196
11486
|
),
|
|
11197
|
-
children: blocks.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
11487
|
+
children: blocks.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
11488
|
+
EmptyState,
|
|
11489
|
+
{
|
|
11490
|
+
isDark,
|
|
11491
|
+
isPaletteDrag,
|
|
11492
|
+
isOver,
|
|
11493
|
+
isFileDrag: imageDrop.dragging,
|
|
11494
|
+
onOpenPalette
|
|
11495
|
+
}
|
|
11496
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(sortable.SortableContext, { items: blocks.map((b) => b.id), strategy: sortable.verticalListSortingStrategy, children: [
|
|
11198
11497
|
blocks.map(
|
|
11199
11498
|
(block, idx) => block.block.type === "container" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
11200
11499
|
ContainerRow,
|
|
@@ -11224,7 +11523,7 @@ function Surface({
|
|
|
11224
11523
|
previewTheme,
|
|
11225
11524
|
errors: errorsByBlockId?.get(block.id),
|
|
11226
11525
|
isOpen: openBlockId === block.id,
|
|
11227
|
-
onOpenChange: (open) => onOpenBlockChange?.(
|
|
11526
|
+
onOpenChange: (open) => onOpenBlockChange?.(block.id, open),
|
|
11228
11527
|
onUpdate,
|
|
11229
11528
|
onDuplicate,
|
|
11230
11529
|
onDelete,
|
|
@@ -11239,7 +11538,7 @@ function Surface({
|
|
|
11239
11538
|
block.id
|
|
11240
11539
|
)
|
|
11241
11540
|
),
|
|
11242
|
-
showEndDropZone ? /* @__PURE__ */ jsxRuntime.jsx(DropIndicator2, {}) : null
|
|
11541
|
+
showEndDropZone || imageDrop.dragging ? /* @__PURE__ */ jsxRuntime.jsx(DropIndicator2, {}) : null
|
|
11243
11542
|
] })
|
|
11244
11543
|
}
|
|
11245
11544
|
);
|
|
@@ -11248,16 +11547,28 @@ function Surface({
|
|
|
11248
11547
|
{
|
|
11249
11548
|
"aria-label": "Block preview",
|
|
11250
11549
|
className: cn("flex min-w-0 flex-1 flex-col overflow-y-auto bg-muted p-3 sm:p-6"),
|
|
11251
|
-
|
|
11252
|
-
|
|
11253
|
-
|
|
11254
|
-
|
|
11255
|
-
|
|
11256
|
-
|
|
11257
|
-
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
|
|
11550
|
+
...imageDrop.handlers,
|
|
11551
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto w-full max-w-2xl", children: [
|
|
11552
|
+
imageDrop.handlers ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
11553
|
+
ImageDropStatus,
|
|
11554
|
+
{
|
|
11555
|
+
dragging: imageDrop.dragging,
|
|
11556
|
+
pending: imageDrop.pending,
|
|
11557
|
+
error: imageDrop.error,
|
|
11558
|
+
onDismissError: imageDrop.dismissError
|
|
11559
|
+
}
|
|
11560
|
+
) : null,
|
|
11561
|
+
previewSurface === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(ModalFrame, { isDark, children: blocksList }) : previewSurface === "app_home" ? /* @__PURE__ */ jsxRuntime.jsx(AppHomeFrame, { workspaceName, isDark, children: blocksList }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
11562
|
+
SlackMessageFrame,
|
|
11563
|
+
{
|
|
11564
|
+
workspaceName,
|
|
11565
|
+
authorName,
|
|
11566
|
+
authorIcon,
|
|
11567
|
+
isDark,
|
|
11568
|
+
children: blocksList
|
|
11569
|
+
}
|
|
11570
|
+
)
|
|
11571
|
+
] })
|
|
11261
11572
|
}
|
|
11262
11573
|
);
|
|
11263
11574
|
}
|
|
@@ -11386,9 +11697,10 @@ function EmptyState({
|
|
|
11386
11697
|
isDark,
|
|
11387
11698
|
isPaletteDrag,
|
|
11388
11699
|
isOver,
|
|
11700
|
+
isFileDrag: isFileDrag2 = false,
|
|
11389
11701
|
onOpenPalette
|
|
11390
11702
|
}) {
|
|
11391
|
-
const active = isPaletteDrag && isOver;
|
|
11703
|
+
const active = isPaletteDrag && isOver || isFileDrag2;
|
|
11392
11704
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11393
11705
|
"div",
|
|
11394
11706
|
{
|
|
@@ -11415,7 +11727,7 @@ function EmptyState({
|
|
|
11415
11727
|
"text-sm font-semibold transition-colors",
|
|
11416
11728
|
active ? "text-primary" : isDark ? "text-white" : "text-[#1d1c1d]"
|
|
11417
11729
|
),
|
|
11418
|
-
children: active ? "Drop to add block" : "Start adding blocks!"
|
|
11730
|
+
children: isFileDrag2 ? "Drop to add image" : active ? "Drop to add block" : "Start adding blocks!"
|
|
11419
11731
|
}
|
|
11420
11732
|
),
|
|
11421
11733
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs", children: active ? "Release to insert it here." : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
@@ -11439,6 +11751,40 @@ function EmptyState({
|
|
|
11439
11751
|
}
|
|
11440
11752
|
);
|
|
11441
11753
|
}
|
|
11754
|
+
function ImageDropStatus({
|
|
11755
|
+
dragging,
|
|
11756
|
+
pending,
|
|
11757
|
+
error,
|
|
11758
|
+
onDismissError
|
|
11759
|
+
}) {
|
|
11760
|
+
const progress = dragging ? "Drop images to add them at the end of the message." : pending > 0 ? `Uploading ${pending === 1 ? "1 image" : `${pending} images`}\u2026` : null;
|
|
11761
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11762
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", className: "empty:hidden", children: progress ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mb-2 flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
11763
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ImagePlus, { className: cn("h-3.5 w-3.5", pending > 0 && !dragging && "animate-pulse"), "aria-hidden": "true" }),
|
|
11764
|
+
progress
|
|
11765
|
+
] }) : null }),
|
|
11766
|
+
error ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11767
|
+
"div",
|
|
11768
|
+
{
|
|
11769
|
+
role: "alert",
|
|
11770
|
+
className: "mb-2 flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
|
|
11771
|
+
children: [
|
|
11772
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "flex-1", children: error }),
|
|
11773
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11774
|
+
"button",
|
|
11775
|
+
{
|
|
11776
|
+
type: "button",
|
|
11777
|
+
"aria-label": "Dismiss",
|
|
11778
|
+
onClick: onDismissError,
|
|
11779
|
+
className: "rounded p-0.5 hover:bg-destructive/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
11780
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" })
|
|
11781
|
+
}
|
|
11782
|
+
)
|
|
11783
|
+
]
|
|
11784
|
+
}
|
|
11785
|
+
) : null
|
|
11786
|
+
] });
|
|
11787
|
+
}
|
|
11442
11788
|
function DropIndicator2() {
|
|
11443
11789
|
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)]" }) });
|
|
11444
11790
|
}
|
|
@@ -12001,6 +12347,7 @@ function BlockKitchen(props) {
|
|
|
12001
12347
|
blockEditors,
|
|
12002
12348
|
customEmojis,
|
|
12003
12349
|
mentions,
|
|
12350
|
+
imageUpload,
|
|
12004
12351
|
loadChannels,
|
|
12005
12352
|
loadSendAsUserStatus,
|
|
12006
12353
|
onSend,
|
|
@@ -12131,6 +12478,9 @@ function BlockKitchen(props) {
|
|
|
12131
12478
|
setPaletteAdvanced(false);
|
|
12132
12479
|
}
|
|
12133
12480
|
const [openBlockId, setOpenBlockId] = React.useState(null);
|
|
12481
|
+
const setBlockOpen = React.useCallback((id, open) => {
|
|
12482
|
+
setOpenBlockId((current) => open ? id : current === id ? null : current);
|
|
12483
|
+
}, []);
|
|
12134
12484
|
const [uncontrolledPreviewTheme, setUncontrolledPreviewTheme] = React.useState(defaultPreviewTheme);
|
|
12135
12485
|
const isPreviewThemeControlled = controlledPreviewTheme !== void 0;
|
|
12136
12486
|
const previewTheme = controlledPreviewTheme ?? uncontrolledPreviewTheme;
|
|
@@ -12384,7 +12734,7 @@ function BlockKitchen(props) {
|
|
|
12384
12734
|
}
|
|
12385
12735
|
)
|
|
12386
12736
|
] }),
|
|
12387
|
-
/* @__PURE__ */ jsxRuntime.jsx(MentionsProvider, { mentions, children: /* @__PURE__ */ jsxRuntime.jsx(BlockEditorsProvider, { blockEditors, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12737
|
+
/* @__PURE__ */ jsxRuntime.jsx(MentionsProvider, { mentions, children: /* @__PURE__ */ jsxRuntime.jsx(ImageUploadProvider, { imageUpload, children: /* @__PURE__ */ jsxRuntime.jsx(BlockEditorsProvider, { blockEditors, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12388
12738
|
Surface,
|
|
12389
12739
|
{
|
|
12390
12740
|
blocks,
|
|
@@ -12396,7 +12746,7 @@ function BlockKitchen(props) {
|
|
|
12396
12746
|
previewSurface,
|
|
12397
12747
|
errorsByBlockId: validation.byBlockId,
|
|
12398
12748
|
openBlockId,
|
|
12399
|
-
onOpenBlockChange:
|
|
12749
|
+
onOpenBlockChange: setBlockOpen,
|
|
12400
12750
|
onUpdate: updateBlock,
|
|
12401
12751
|
onDuplicate: duplicateBlock,
|
|
12402
12752
|
onDelete: removeBlock,
|
|
@@ -12404,9 +12754,11 @@ function BlockKitchen(props) {
|
|
|
12404
12754
|
isPaletteDrag: activePaletteVariant !== null,
|
|
12405
12755
|
onOpenPalette: () => setPaletteOpen(true),
|
|
12406
12756
|
blockActions,
|
|
12407
|
-
renderBlockAdornment
|
|
12757
|
+
renderBlockAdornment,
|
|
12758
|
+
onAddBlock: addBlock,
|
|
12759
|
+
imageDropEnabled: !disabledBlockTypes?.includes("image")
|
|
12408
12760
|
}
|
|
12409
|
-
) }) })
|
|
12761
|
+
) }) }) })
|
|
12410
12762
|
] })
|
|
12411
12763
|
]
|
|
12412
12764
|
}
|