@tightknitai/block-kitchen 0.10.7 → 0.10.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/dist/helpers.d.cts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.cjs +168 -33
- 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 +169 -34
- package/dist/index.js.map +1 -1
- package/dist/{palette-QbOx7kAa.d.cts → palette-CvSGn2z6.d.cts} +13 -6
- package/dist/{palette-QbOx7kAa.d.ts → palette-CvSGn2z6.d.ts} +13 -6
- package/dist/palette.cjs +10 -2
- 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 +10 -2
- package/dist/palette.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -141,7 +141,7 @@ Given no height to work with — a plain `<div>` in ordinary document flow — i
|
|
|
141
141
|
| `customEmojis` | `CustomEmoji[]` | no | Workspace custom emoji (`{ name, url, alias }`) the preview resolves. Entries with a `url` render `:name:` as the workspace image; alias entries (`url: null`) fall back to their target emoji. Render-only — never serialized into the emitted Block Kit JSON. A caller-supplied `previewHooks.emoji` takes precedence. |
|
|
142
142
|
| `palette` | `PaletteSection[]` | no | The left-hand palette of draggable variants. Defaults to `defaultPalette`. Spread it to filter, reorder, or add your own pre-configured variants — see [Customizing the palette](#customizing-the-palette). |
|
|
143
143
|
| `disabledBlockTypes` | `SupportedBlockType[]` | no | Block types to hide from the palette without rebuilding it. Filters at the variant level — a section keeps any variants whose block types aren't disabled; sections that end up empty are dropped. Convenient when you want the default palette minus a few types (e.g. `['image', 'table']` for a text-only builder). |
|
|
144
|
-
| `paletteMode` | `'advanced' \| 'simple'` | no | How much of the palette the user meets first. `'advanced'` (default) renders the full sectioned palette with its search input. `'simple'` opens on a flat list of the variants flagged `basic` — in the built-in palette
|
|
144
|
+
| `paletteMode` | `'advanced' \| 'simple'` | no | How much of the palette the user meets first. `'advanced'` (default) renders the full sectioned palette with its search input. `'simple'` opens on a flat list of the variants flagged `basic` — in the built-in palette: **Header**, **Divider**, **Rich Text Section** and **Image** — with no search and an "Advanced" link at the top that swaps in the full palette. Nothing is removed; it's a smaller first screen. See [Simple vs advanced palette](#simple-vs-advanced-palette). |
|
|
145
145
|
| `defaultOpenSections` | `boolean \| string[]` | no | Which palette section headers are expanded on first paint. `true` (default) opens all sections; `false` collapses all (Slack-style); an array opens only sections whose `name` is in the list (e.g. `['Section', 'Actions']`). The palette also has a built-in search input that expands matching sections on demand. |
|
|
146
146
|
| `showPaletteSearch` | `boolean` | no | Whether the palette renders the quick-search input above the section list. Defaults to `true`. Set `false` for compact palettes (e.g. when you've passed a small custom `palette`) where scanning by eye is faster than typing. Simple mode has no search either way — it appears with the rest of the palette behind "Advanced". |
|
|
147
147
|
| `paletteSearchPlaceholder` | `string` | no | Placeholder text for the palette search input. Defaults to `'Search blocks…'`. Useful for localization. |
|
|
@@ -442,6 +442,8 @@ update against the target from `loadedMessage` / `onLoadedMessageChange`.
|
|
|
442
442
|
|
|
443
443
|
## Customizing the palette
|
|
444
444
|
|
|
445
|
+
On desktop the palette is a rail down the left-hand side, with a chevron handle on its outer border that hides and restores it — collapsed, the preview gets the full width, and the rail comes back with its open sections and search exactly as they were. Below the `md` breakpoint there's no rail: the toolbar's **Blocks** button opens the palette as a bottom sheet instead, and picking a block closes it.
|
|
446
|
+
|
|
445
447
|
The default palette ships with curated presets for every supported block type. To narrow what's available, or add your own pre-configured variants (e.g. a "Help footer" section), pass a `palette` array. Define it at module scope (or wrap in `useMemo`) so it stays referentially stable across renders.
|
|
446
448
|
|
|
447
449
|
```tsx
|
|
@@ -476,13 +478,13 @@ Variant `id`s must be unique across the array — the drag-drop lookup keys by i
|
|
|
476
478
|
|
|
477
479
|
### Simple vs advanced palette
|
|
478
480
|
|
|
479
|
-
By default the palette opens on everything it has: every section, plus the search input. For consumers whose users are writing ordinary messages rather than building interactive apps, `paletteMode="simple"` opens on a
|
|
481
|
+
By default the palette opens on everything it has: every section, plus the search input. For consumers whose users are writing ordinary messages rather than building interactive apps, `paletteMode="simple"` opens on a short starter list instead — no sections, no search — behind an **Advanced** link that swaps in the full palette (and back).
|
|
480
482
|
|
|
481
483
|
```tsx
|
|
482
484
|
<BlockKitchen paletteMode="simple" {...rest} />
|
|
483
485
|
```
|
|
484
486
|
|
|
485
|
-
Which variants the simple list holds is a property of the palette, not the flag: a variant opts in with `basic: true`. The built-in palette flags
|
|
487
|
+
Which variants the simple list holds is a property of the palette, not the flag: a variant opts in with `basic: true`. The built-in palette flags four — **Header**, **Divider**, **Rich Text Section** and **Image** — listed in palette order. A custom palette that wants its own starter blocks says so:
|
|
486
488
|
|
|
487
489
|
```tsx
|
|
488
490
|
const PALETTE: readonly PaletteSection[] = [
|
|
@@ -497,8 +499,12 @@ const PALETTE: readonly PaletteSection[] = [
|
|
|
497
499
|
];
|
|
498
500
|
```
|
|
499
501
|
|
|
502
|
+
The flat list has no section headings to lean on, so a variant whose label only reads in context can give simple mode a self-describing one with `basicLabel` — that's how the built-in image variant (**No title**, under **Image**) shows up as **Image** there.
|
|
503
|
+
|
|
500
504
|
A palette that flags none of its variants `basic` has no simple list to show, so it renders as `'advanced'` regardless — the link is withheld rather than leading to an empty rail.
|
|
501
505
|
|
|
506
|
+
The builder remembers which side of that switch the user is on, so the mobile sheet — which is torn down every time it closes — reopens on the full palette rather than sending them back through the **Advanced** link on every block.
|
|
507
|
+
|
|
502
508
|
## Templates (`TemplatePicker`)
|
|
503
509
|
|
|
504
510
|
`TemplatePicker` is a standalone, page-sized picker that renders `Template`s as a grid of cards with live block previews, grouped into category sections — modeled on Slack's own Block Kit Builder templates page. It's pure UI: it owns no dialog and no layout, so you decide whether it's a route, a modal, a slide-over, or a sidebar next to the builder.
|
package/dist/helpers.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SupportedBlock } from './palette-
|
|
2
|
-
export { a1 as SupportedBlockType } from './palette-
|
|
1
|
+
import { S as SupportedBlock } from './palette-CvSGn2z6.cjs';
|
|
2
|
+
export { a1 as SupportedBlockType } from './palette-CvSGn2z6.cjs';
|
|
3
3
|
import 'react';
|
|
4
4
|
import 'slack-web-api-client';
|
|
5
5
|
|
package/dist/helpers.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SupportedBlock } from './palette-
|
|
2
|
-
export { a1 as SupportedBlockType } from './palette-
|
|
1
|
+
import { S as SupportedBlock } from './palette-CvSGn2z6.js';
|
|
2
|
+
export { a1 as SupportedBlockType } from './palette-CvSGn2z6.js';
|
|
3
3
|
import 'react';
|
|
4
4
|
import 'slack-web-api-client';
|
|
5
5
|
|
package/dist/index.cjs
CHANGED
|
@@ -4,10 +4,10 @@ var core = require('@dnd-kit/core');
|
|
|
4
4
|
var sortable = require('@dnd-kit/sortable');
|
|
5
5
|
var lucideReact = require('lucide-react');
|
|
6
6
|
var React = require('react');
|
|
7
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
-
var DialogPrimitive = require('@radix-ui/react-dialog');
|
|
9
7
|
var clsx = require('clsx');
|
|
10
8
|
var tailwindMerge = require('tailwind-merge');
|
|
9
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
10
|
+
var DialogPrimitive = require('@radix-ui/react-dialog');
|
|
11
11
|
var TooltipPrimitive = require('@radix-ui/react-tooltip');
|
|
12
12
|
var slackBlockKitValidator = require('@tightknitai/slack-block-kit-validator');
|
|
13
13
|
var nanoid = require('nanoid');
|
|
@@ -53,6 +53,9 @@ var Link__default = /*#__PURE__*/_interopDefault(Link);
|
|
|
53
53
|
var StarterKit__default = /*#__PURE__*/_interopDefault(StarterKit);
|
|
54
54
|
|
|
55
55
|
// src/components/block-kitchen.tsx
|
|
56
|
+
function cn(...inputs) {
|
|
57
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
58
|
+
}
|
|
56
59
|
|
|
57
60
|
// src/lib/container-blocks.ts
|
|
58
61
|
var CONTAINER_CHILD_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -734,6 +737,7 @@ var defaultPalette = [
|
|
|
734
737
|
{
|
|
735
738
|
id: "structure_header",
|
|
736
739
|
label: "Header",
|
|
740
|
+
basic: true,
|
|
737
741
|
factory: () => ({
|
|
738
742
|
type: "header",
|
|
739
743
|
text: { type: "plain_text", text: "Heading text", emoji: true }
|
|
@@ -742,6 +746,7 @@ var defaultPalette = [
|
|
|
742
746
|
{
|
|
743
747
|
id: "structure_divider",
|
|
744
748
|
label: "Divider",
|
|
749
|
+
basic: true,
|
|
745
750
|
factory: () => ({ type: "divider" })
|
|
746
751
|
},
|
|
747
752
|
{
|
|
@@ -849,8 +854,9 @@ var defaultPalette = [
|
|
|
849
854
|
{
|
|
850
855
|
id: "rich_text_section",
|
|
851
856
|
label: "Rich Text Section",
|
|
852
|
-
// The
|
|
853
|
-
//
|
|
857
|
+
// The block a message is mostly made of, and so one of the handful
|
|
858
|
+
// simple mode offers — listed there without its section heading,
|
|
859
|
+
// hence the self-describing label.
|
|
854
860
|
basic: true,
|
|
855
861
|
factory: () => ({
|
|
856
862
|
type: "rich_text",
|
|
@@ -887,6 +893,11 @@ var defaultPalette = [
|
|
|
887
893
|
{
|
|
888
894
|
id: "image_no_title",
|
|
889
895
|
label: "No title",
|
|
896
|
+
// The plain image is the one an ordinary message reaches for, so it
|
|
897
|
+
// carries simple mode's image slot — under its own name there, with
|
|
898
|
+
// no "Image" heading overhead to lend "No title" its meaning.
|
|
899
|
+
basic: true,
|
|
900
|
+
basicLabel: "Image",
|
|
890
901
|
factory: () => ({
|
|
891
902
|
type: "image",
|
|
892
903
|
image_url: "https://placehold.co/600x300?text=Image",
|
|
@@ -1709,9 +1720,6 @@ function labelForBlockType(type) {
|
|
|
1709
1720
|
return "Container";
|
|
1710
1721
|
}
|
|
1711
1722
|
}
|
|
1712
|
-
function cn(...inputs) {
|
|
1713
|
-
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
1714
|
-
}
|
|
1715
1723
|
var Sheet = DialogPrimitive__namespace.Root;
|
|
1716
1724
|
var SheetOverlay = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1717
1725
|
DialogPrimitive__namespace.Overlay,
|
|
@@ -3812,14 +3820,14 @@ function isDefaultOpen(sectionName, config) {
|
|
|
3812
3820
|
return config.includes(sectionName);
|
|
3813
3821
|
}
|
|
3814
3822
|
var PALETTE_TITLE = "Message Elements";
|
|
3815
|
-
var ADVANCED_HELP = "Browse every Slack block type \u2014 sections, images, buttons, inputs, tables and more
|
|
3816
|
-
var BASIC_HELP = "Go back to the short list:
|
|
3823
|
+
var ADVANCED_HELP = "Browse every Slack block type \u2014 sections, images, buttons, inputs, tables and more.";
|
|
3824
|
+
var BASIC_HELP = "Go back to the short list: the few blocks an ordinary message is made of.";
|
|
3817
3825
|
function basicVariants(sections) {
|
|
3818
3826
|
const out = [];
|
|
3819
3827
|
for (const section of sections) {
|
|
3820
3828
|
for (const variant of section.variants) {
|
|
3821
3829
|
if (variant.basic) {
|
|
3822
|
-
out.push(variant);
|
|
3830
|
+
out.push(variant.basicLabel ? { ...variant, label: variant.basicLabel } : variant);
|
|
3823
3831
|
}
|
|
3824
3832
|
}
|
|
3825
3833
|
}
|
|
@@ -3848,10 +3856,12 @@ function Palette({
|
|
|
3848
3856
|
showSearch = true,
|
|
3849
3857
|
searchPlaceholder = "Search blocks\u2026",
|
|
3850
3858
|
mode = "advanced",
|
|
3859
|
+
defaultAdvanced = false,
|
|
3860
|
+
onAdvancedChange,
|
|
3851
3861
|
variant = "aside"
|
|
3852
3862
|
}) {
|
|
3853
3863
|
const [query, setQuery] = React.useState("");
|
|
3854
|
-
const [advancedOpen, setAdvancedOpen] = React.useState(
|
|
3864
|
+
const [advancedOpen, setAdvancedOpen] = React.useState(defaultAdvanced);
|
|
3855
3865
|
const [prevMode, setPrevMode] = React.useState(mode);
|
|
3856
3866
|
if (prevMode !== mode) {
|
|
3857
3867
|
setPrevMode(mode);
|
|
@@ -3873,7 +3883,7 @@ function Palette({
|
|
|
3873
3883
|
{
|
|
3874
3884
|
className: cn(
|
|
3875
3885
|
"flex min-h-0 flex-col overflow-x-hidden overflow-y-auto",
|
|
3876
|
-
isSheet ? "w-full flex-1 bg-background" : "w-
|
|
3886
|
+
isSheet ? "w-full flex-1 bg-background" : "w-56 shrink-0 border-r bg-muted/20"
|
|
3877
3887
|
),
|
|
3878
3888
|
children: [
|
|
3879
3889
|
offersSimple || searchVisible ? (
|
|
@@ -3906,7 +3916,9 @@ function Palette({
|
|
|
3906
3916
|
isSheet,
|
|
3907
3917
|
onToggle: () => {
|
|
3908
3918
|
setQuery("");
|
|
3909
|
-
|
|
3919
|
+
const next = !advancedOpen;
|
|
3920
|
+
setAdvancedOpen(next);
|
|
3921
|
+
onAdvancedChange?.(next);
|
|
3910
3922
|
}
|
|
3911
3923
|
}
|
|
3912
3924
|
)
|
|
@@ -4034,8 +4046,8 @@ function PaletteItem({
|
|
|
4034
4046
|
isDragging && "opacity-50"
|
|
4035
4047
|
),
|
|
4036
4048
|
children: [
|
|
4037
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "
|
|
4038
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "
|
|
4049
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: variant.label }),
|
|
4050
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground transition-colors group-hover:bg-primary/10 group-hover:text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" }) })
|
|
4039
4051
|
]
|
|
4040
4052
|
}
|
|
4041
4053
|
);
|
|
@@ -4045,7 +4057,7 @@ function PaletteItem({
|
|
|
4045
4057
|
{
|
|
4046
4058
|
ref: setNodeRef,
|
|
4047
4059
|
className: cn(
|
|
4048
|
-
"group flex items-center gap-2 rounded px-2 py-1
|
|
4060
|
+
"group flex items-center 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",
|
|
4049
4061
|
isDragging && "opacity-50"
|
|
4050
4062
|
),
|
|
4051
4063
|
children: [
|
|
@@ -4053,7 +4065,7 @@ function PaletteItem({
|
|
|
4053
4065
|
"div",
|
|
4054
4066
|
{
|
|
4055
4067
|
ref: setActivatorNodeRef,
|
|
4056
|
-
className: "-my-1
|
|
4068
|
+
className: "-my-1 flex min-w-0 flex-1 cursor-grab items-center gap-2 rounded py-1 active:cursor-grabbing focus-visible:outline-none",
|
|
4057
4069
|
...attributes,
|
|
4058
4070
|
...listeners,
|
|
4059
4071
|
children: [
|
|
@@ -6100,12 +6112,44 @@ function HeaderEditor({ block, onChange }) {
|
|
|
6100
6112
|
] });
|
|
6101
6113
|
}
|
|
6102
6114
|
function ImageEditor({ block, onChange }) {
|
|
6103
|
-
|
|
6104
|
-
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "This image references a Slack file. Not editable in the visual builder." });
|
|
6105
|
-
}
|
|
6115
|
+
const source = "slack_file" in block ? "slack_file" : "url";
|
|
6106
6116
|
const titleText = block.title?.text ?? "";
|
|
6117
|
+
const setSource = (next) => {
|
|
6118
|
+
if (next === source) {
|
|
6119
|
+
return;
|
|
6120
|
+
}
|
|
6121
|
+
if (next === "url") {
|
|
6122
|
+
const { slack_file: _omit, ...rest } = block;
|
|
6123
|
+
onChange({ image_url: "", ...rest });
|
|
6124
|
+
} else {
|
|
6125
|
+
const { image_url: _omit, ...rest } = block;
|
|
6126
|
+
onChange({ slack_file: { id: "" }, ...rest });
|
|
6127
|
+
}
|
|
6128
|
+
};
|
|
6107
6129
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
6108
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6130
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6131
|
+
EditorField,
|
|
6132
|
+
{
|
|
6133
|
+
label: "Image source",
|
|
6134
|
+
help: "Where the image comes from: a public URL, or a file already uploaded to your Slack workspace.",
|
|
6135
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6136
|
+
RadioGroup,
|
|
6137
|
+
{
|
|
6138
|
+
value: source,
|
|
6139
|
+
onValueChange: (v) => setSource(v),
|
|
6140
|
+
className: "flex flex-row flex-wrap gap-3",
|
|
6141
|
+
children: [
|
|
6142
|
+
["url", "Public URL"],
|
|
6143
|
+
["slack_file", "Slack file"]
|
|
6144
|
+
].map(([value, label]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
6145
|
+
/* @__PURE__ */ jsxRuntime.jsx(RadioGroupItem, { value, id: `img-source-${value}` }),
|
|
6146
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `img-source-${value}`, className: "text-xs", children: label })
|
|
6147
|
+
] }, value))
|
|
6148
|
+
}
|
|
6149
|
+
)
|
|
6150
|
+
}
|
|
6151
|
+
),
|
|
6152
|
+
"slack_file" in block ? /* @__PURE__ */ jsxRuntime.jsx(SlackFileFields, { block, onChange }) : /* @__PURE__ */ jsxRuntime.jsx(EditorField, { label: "Image URL", help: "A publicly accessible image URL (PNG, JPG, GIF).", htmlFor: "img-url", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6109
6153
|
Input,
|
|
6110
6154
|
{
|
|
6111
6155
|
id: "img-url",
|
|
@@ -6149,6 +6193,51 @@ function ImageEditor({ block, onChange }) {
|
|
|
6149
6193
|
) })
|
|
6150
6194
|
] });
|
|
6151
6195
|
}
|
|
6196
|
+
function SlackFileFields({
|
|
6197
|
+
block,
|
|
6198
|
+
onChange
|
|
6199
|
+
}) {
|
|
6200
|
+
const fileId = "id" in block.slack_file ? block.slack_file.id : "";
|
|
6201
|
+
const fileUrl = "url" in block.slack_file ? block.slack_file.url : "";
|
|
6202
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6203
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "References a file already uploaded to your Slack workspace. The preview can't render workspace files \u2014 switch the source to Public URL to see the image here." }),
|
|
6204
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6205
|
+
EditorField,
|
|
6206
|
+
{
|
|
6207
|
+
label: "File ID",
|
|
6208
|
+
help: "The Slack file's ID. Slack accepts an ID or a URL, not both, so filling this clears File URL.",
|
|
6209
|
+
htmlFor: "img-file-id",
|
|
6210
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6211
|
+
Input,
|
|
6212
|
+
{
|
|
6213
|
+
id: "img-file-id",
|
|
6214
|
+
value: fileId,
|
|
6215
|
+
placeholder: "e.g. F0123456789",
|
|
6216
|
+
onChange: (e) => onChange({ ...block, slack_file: { id: e.target.value } })
|
|
6217
|
+
}
|
|
6218
|
+
)
|
|
6219
|
+
}
|
|
6220
|
+
),
|
|
6221
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6222
|
+
EditorField,
|
|
6223
|
+
{
|
|
6224
|
+
label: "File URL",
|
|
6225
|
+
help: "The file's Slack-hosted URL. Filling this clears File ID.",
|
|
6226
|
+
htmlFor: "img-file-url",
|
|
6227
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6228
|
+
Input,
|
|
6229
|
+
{
|
|
6230
|
+
id: "img-file-url",
|
|
6231
|
+
type: "url",
|
|
6232
|
+
value: fileUrl,
|
|
6233
|
+
placeholder: "e.g. https://files.slack.com/files-pri/T0123-F0123/image.png",
|
|
6234
|
+
onChange: (e) => onChange({ ...block, slack_file: { url: e.target.value } })
|
|
6235
|
+
}
|
|
6236
|
+
)
|
|
6237
|
+
}
|
|
6238
|
+
)
|
|
6239
|
+
] });
|
|
6240
|
+
}
|
|
6152
6241
|
function InputEditor({ block, onChange }) {
|
|
6153
6242
|
const updateElement = (next) => {
|
|
6154
6243
|
onChange({ ...block, element: next });
|
|
@@ -10030,7 +10119,7 @@ function Toolbar2({
|
|
|
10030
10119
|
variant: "ghost",
|
|
10031
10120
|
size: "sm",
|
|
10032
10121
|
onClick: onOpenPalette,
|
|
10033
|
-
className: "md:hidden",
|
|
10122
|
+
className: "gap-1 md:hidden",
|
|
10034
10123
|
"aria-label": "Add a block",
|
|
10035
10124
|
children: [
|
|
10036
10125
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4" }),
|
|
@@ -10586,12 +10675,20 @@ function BlockKitchen(props) {
|
|
|
10586
10675
|
useNotifyOnChange(activeEditTarget, loadedMessageKey, loading?.onLoadedMessageChange);
|
|
10587
10676
|
const [issuesOpen, setIssuesOpen] = React.useState(false);
|
|
10588
10677
|
const [paletteOpen, setPaletteOpen] = React.useState(false);
|
|
10678
|
+
const [paletteCollapsed, setPaletteCollapsed] = React.useState(false);
|
|
10679
|
+
const [paletteAdvanced, setPaletteAdvanced] = React.useState(false);
|
|
10680
|
+
const [prevPaletteMode, setPrevPaletteMode] = React.useState(paletteMode);
|
|
10681
|
+
if (prevPaletteMode !== paletteMode) {
|
|
10682
|
+
setPrevPaletteMode(paletteMode);
|
|
10683
|
+
setPaletteAdvanced(false);
|
|
10684
|
+
}
|
|
10589
10685
|
const [openBlockId, setOpenBlockId] = React.useState(null);
|
|
10590
10686
|
const [uncontrolledPreviewTheme, setUncontrolledPreviewTheme] = React.useState(defaultPreviewTheme);
|
|
10591
10687
|
const isPreviewThemeControlled = controlledPreviewTheme !== void 0;
|
|
10592
10688
|
const previewTheme = controlledPreviewTheme ?? uncontrolledPreviewTheme;
|
|
10593
10689
|
const [previewSurface, setPreviewSurface] = React.useState(allowedSurfaces[0]);
|
|
10594
10690
|
const [activePaletteVariantId, setActivePaletteVariantId] = React.useState(null);
|
|
10691
|
+
const paletteSheetRef = React.useRef(null);
|
|
10595
10692
|
const isMobile = useIsMobile();
|
|
10596
10693
|
const mergedPreviewHooks = React.useMemo(() => {
|
|
10597
10694
|
if (!customEmojis || customEmojis.length === 0) {
|
|
@@ -10775,17 +10872,48 @@ function BlockKitchen(props) {
|
|
|
10775
10872
|
}
|
|
10776
10873
|
),
|
|
10777
10874
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 items-stretch", children: [
|
|
10778
|
-
/* @__PURE__ */ jsxRuntime.
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
|
|
10788
|
-
|
|
10875
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative hidden min-h-0 shrink-0 md:flex", children: [
|
|
10876
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { hidden: paletteCollapsed, className: cn("min-h-0", !paletteCollapsed && "flex"), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10877
|
+
Palette,
|
|
10878
|
+
{
|
|
10879
|
+
onAddBlock: (block) => addBlock(block),
|
|
10880
|
+
sections: paletteSections,
|
|
10881
|
+
mode: paletteMode,
|
|
10882
|
+
showSearch: showPaletteSearch,
|
|
10883
|
+
searchPlaceholder: paletteSearchPlaceholder,
|
|
10884
|
+
defaultOpenSections,
|
|
10885
|
+
defaultAdvanced: paletteAdvanced,
|
|
10886
|
+
onAdvancedChange: setPaletteAdvanced
|
|
10887
|
+
}
|
|
10888
|
+
) }),
|
|
10889
|
+
paletteCollapsed ? (
|
|
10890
|
+
// In a host that hands the builder no height of its own,
|
|
10891
|
+
// the rail is what the shell takes its height from (see
|
|
10892
|
+
// the shell's `max-h` note above) — so hiding it would
|
|
10893
|
+
// shrink the whole frame to the height of the message and
|
|
10894
|
+
// grow it back on the way out. This stands in for the rail
|
|
10895
|
+
// at no width. Inert to everything but layout.
|
|
10896
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, className: "w-0 shrink-0 md:h-[var(--bk-max-height,100svh)]" })
|
|
10897
|
+
) : null,
|
|
10898
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10899
|
+
"button",
|
|
10900
|
+
{
|
|
10901
|
+
type: "button",
|
|
10902
|
+
onClick: () => setPaletteCollapsed((v) => !v),
|
|
10903
|
+
"aria-expanded": !paletteCollapsed,
|
|
10904
|
+
"aria-label": paletteCollapsed ? "Show block palette" : "Hide block palette",
|
|
10905
|
+
title: paletteCollapsed ? "Show block palette" : "Hide block palette",
|
|
10906
|
+
className: cn(
|
|
10907
|
+
// A hairline outline in the rail's own border color, so
|
|
10908
|
+
// the handle reads as part of the edge it rides rather
|
|
10909
|
+
// than a chevron floating loose over the border line.
|
|
10910
|
+
"absolute top-1/2 z-10 flex h-10 w-4 -translate-y-1/2 cursor-pointer appearance-none items-center justify-center rounded-sm border bg-background p-0 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
10911
|
+
paletteCollapsed ? "left-0" : "right-0 translate-x-1/2"
|
|
10912
|
+
),
|
|
10913
|
+
children: paletteCollapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4", strokeWidth: 1.5 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-4 w-4", strokeWidth: 1.5 })
|
|
10914
|
+
}
|
|
10915
|
+
)
|
|
10916
|
+
] }),
|
|
10789
10917
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10790
10918
|
Surface,
|
|
10791
10919
|
{
|
|
@@ -10818,8 +10946,13 @@ function BlockKitchen(props) {
|
|
|
10818
10946
|
/* @__PURE__ */ jsxRuntime.jsx(Sheet, { open: paletteOpen && isMobile, onOpenChange: setPaletteOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10819
10947
|
SheetContent,
|
|
10820
10948
|
{
|
|
10949
|
+
ref: paletteSheetRef,
|
|
10821
10950
|
side: "bottom",
|
|
10822
10951
|
className: "bk-portal-content flex h-[85svh] max-h-[85svh] flex-col gap-3 p-0 sm:max-w-none",
|
|
10952
|
+
onOpenAutoFocus: (e) => {
|
|
10953
|
+
e.preventDefault();
|
|
10954
|
+
paletteSheetRef.current?.focus();
|
|
10955
|
+
},
|
|
10823
10956
|
children: [
|
|
10824
10957
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 px-4 pt-5", children: [
|
|
10825
10958
|
/* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { children: "Add a block" }),
|
|
@@ -10837,6 +10970,8 @@ function BlockKitchen(props) {
|
|
|
10837
10970
|
showSearch: showPaletteSearch,
|
|
10838
10971
|
searchPlaceholder: paletteSearchPlaceholder,
|
|
10839
10972
|
defaultOpenSections,
|
|
10973
|
+
defaultAdvanced: paletteAdvanced,
|
|
10974
|
+
onAdvancedChange: setPaletteAdvanced,
|
|
10840
10975
|
variant: "sheet"
|
|
10841
10976
|
}
|
|
10842
10977
|
) })
|