@nextbridgehq/payload-block-builder 0.1.4 → 0.1.6

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.
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env node
2
+ #!/usr/bin/env node
3
+
4
+ // src/bin/init.ts
5
+ import fs from "fs";
6
+ import path from "path";
7
+ var PAGE_CONTENT = `'use client'
8
+
9
+ import { BuilderShell } from '@nextbridgehq/payload-block-builder/client'
10
+
11
+ export default function BlockBuilderPage() {
12
+ return <BuilderShell />
13
+ }
14
+ `;
15
+ var LAYOUT_CONTENT = `import React from 'react'
16
+ import '@nextbridgehq/payload-block-builder/builder.css'
17
+
18
+ export const metadata = {
19
+ title: 'Block Builder',
20
+ }
21
+
22
+ export default function BlockBuilderLayout({ children }: { children: React.ReactNode }) {
23
+ return (
24
+ <html lang="en">
25
+ <body style={{ margin: 0, padding: 0, height: '100vh', overflow: 'hidden' }}>
26
+ {children}
27
+ </body>
28
+ </html>
29
+ )
30
+ }
31
+ `;
32
+ var CUSTOM_SCSS_IMPORTS = `@import '@nextbridgehq/payload-block-builder/block-data-field.css';
33
+ @import '@nextbridgehq/payload-block-builder/schema-builder-field.css';
34
+ `;
35
+ function findAppDir() {
36
+ const candidates = [
37
+ path.join(process.cwd(), "src", "app"),
38
+ path.join(process.cwd(), "app")
39
+ ];
40
+ for (const dir of candidates) {
41
+ if (fs.existsSync(dir)) return dir;
42
+ }
43
+ return null;
44
+ }
45
+ function findPayloadConfig() {
46
+ const candidates = [
47
+ path.join(process.cwd(), "src", "payload.config.ts"),
48
+ path.join(process.cwd(), "payload.config.ts")
49
+ ];
50
+ for (const c of candidates) {
51
+ if (fs.existsSync(c)) return c;
52
+ }
53
+ return null;
54
+ }
55
+ function detectDbAdapter(content) {
56
+ if (/postgresAdapter|db-postgres/.test(content)) return "postgres";
57
+ if (/sqliteAdapter|db-sqlite/.test(content)) return "sqlite";
58
+ return "other";
59
+ }
60
+ function findClosingBracket(content, openPos) {
61
+ let depth = 0;
62
+ for (let i = openPos; i < content.length; i++) {
63
+ if (content[i] === "[") depth++;
64
+ else if (content[i] === "]") {
65
+ depth--;
66
+ if (depth === 0) return i;
67
+ }
68
+ }
69
+ return -1;
70
+ }
71
+ function addImport(content) {
72
+ const newImport = `import { dynamicBlocksPlugin } from '@nextbridgehq/payload-block-builder'`;
73
+ const lastFromRegex = /^.*from\s+['"][^'"]+['"]\s*;?\s*$/gm;
74
+ let lastMatch = null;
75
+ let m;
76
+ while ((m = lastFromRegex.exec(content)) !== null) lastMatch = m;
77
+ if (!lastMatch) return newImport + "\n" + content;
78
+ const insertPos = lastMatch.index + lastMatch[0].length;
79
+ return content.slice(0, insertPos) + "\n" + newImport + content.slice(insertPos);
80
+ }
81
+ function insertIntoPluginsArray(content, collectionsArg) {
82
+ const pluginsMatch = /\bplugins\s*:\s*\[/.exec(content);
83
+ if (!pluginsMatch) return null;
84
+ const openPos = content.indexOf("[", pluginsMatch.index);
85
+ const closePos = findClosingBracket(content, openPos);
86
+ if (closePos === -1) return null;
87
+ const beforeClose = content.slice(0, closePos);
88
+ const prevNL = beforeClose.lastIndexOf("\n");
89
+ const closingIndent = beforeClose.slice(prevNL + 1).match(/^([ \t]*)/)?.[1] ?? " ";
90
+ const entryIndent = closingIndent + " ";
91
+ const newLine = `${entryIndent}dynamicBlocksPlugin({ collections: [${collectionsArg}] }),
92
+ `;
93
+ return content.slice(0, prevNL + 1) + newLine + content.slice(prevNL + 1);
94
+ }
95
+ function injectPluginsBlock(content, collectionsArg) {
96
+ const collMatch = /\bcollections\s*:\s*\[/.exec(content);
97
+ if (!collMatch) return null;
98
+ const collOpen = content.indexOf("[", collMatch.index);
99
+ const collClose = findClosingBracket(content, collOpen);
100
+ if (collClose === -1) return null;
101
+ const afterCollLine = content.indexOf("\n", collClose);
102
+ if (afterCollLine === -1) return null;
103
+ const beforeColl = content.slice(0, collMatch.index);
104
+ const collLineStart = beforeColl.lastIndexOf("\n") + 1;
105
+ const outerIndent = beforeColl.slice(collLineStart).match(/^([ \t]*)/)?.[1] ?? " ";
106
+ const entryIndent = outerIndent + " ";
107
+ const pluginsBlock = `${outerIndent}plugins: [
108
+ ${entryIndent}dynamicBlocksPlugin({ collections: [${collectionsArg}] }),
109
+ ${outerIndent}],`;
110
+ return content.slice(0, afterCollLine) + "\n" + pluginsBlock + content.slice(afterCollLine);
111
+ }
112
+ function modifyPayloadConfig(configPath, collectionsArg) {
113
+ let content = fs.readFileSync(configPath, "utf8");
114
+ if (content.includes("dynamicBlocksPlugin")) {
115
+ console.log(`Skipped: dynamicBlocksPlugin already present in ${configPath}`);
116
+ return;
117
+ }
118
+ content = addImport(content);
119
+ const noComments = content.replace(/\/\/[^\n]*/g, "");
120
+ const hasPluginsArray = /\bplugins\s*:\s*\[/.test(noComments);
121
+ const hasPluginsShorthand = /^\s*plugins\s*,/m.test(noComments);
122
+ if (hasPluginsShorthand && !hasPluginsArray) {
123
+ fs.writeFileSync(configPath, content, "utf8");
124
+ console.log(`Updated: ${configPath} (added import)`);
125
+ console.log(` Note: 'plugins' is imported from another file.`);
126
+ console.log(` Add dynamicBlocksPlugin({ collections: ['pages'] }) to that file manually.`);
127
+ return;
128
+ }
129
+ let result = null;
130
+ if (hasPluginsArray) {
131
+ result = insertIntoPluginsArray(content, collectionsArg);
132
+ } else {
133
+ result = injectPluginsBlock(content, collectionsArg);
134
+ }
135
+ if (result === null) {
136
+ fs.writeFileSync(configPath, content, "utf8");
137
+ console.log(`Updated: ${configPath} (added import only)`);
138
+ console.log(` Could not auto-detect plugins array. Add manually:`);
139
+ console.log(` plugins: [ dynamicBlocksPlugin({ collections: [${collectionsArg}] }) ]`);
140
+ return;
141
+ }
142
+ fs.writeFileSync(configPath, result, "utf8");
143
+ console.log(`Updated: ${configPath} (added dynamicBlocksPlugin)`);
144
+ }
145
+ function printNextSteps(dbAdapter) {
146
+ console.log("\n--- Next Steps ---");
147
+ console.log("1. Regenerate the Payload import map:");
148
+ console.log(" pnpm generate:importmap");
149
+ if (dbAdapter === "postgres") {
150
+ console.log("\n2. PostgreSQL detected. Start the dev server \u2014 Payload will auto-push schema:");
151
+ console.log(" pnpm dev");
152
+ console.log("\n Or if you prefer migrations:");
153
+ console.log(" pnpm payload migrate:create --name=add_block_builder");
154
+ console.log(" pnpm payload migrate");
155
+ } else if (dbAdapter === "sqlite") {
156
+ console.log("\n2. Start the dev server \u2014 Payload will auto-migrate SQLite:");
157
+ console.log(" pnpm dev");
158
+ } else {
159
+ console.log("\n2. Start the dev server:");
160
+ console.log(" pnpm dev");
161
+ }
162
+ console.log("\nThen visit: http://localhost:3000/block-builder");
163
+ console.log("------------------");
164
+ }
165
+ function main() {
166
+ const args = process.argv.slice(2);
167
+ const collectionsFlag = args.find((a) => a.startsWith("--collections="));
168
+ const collectionsValue = collectionsFlag ? collectionsFlag.replace("--collections=", "").split(",").map((s) => s.trim()) : ["pages"];
169
+ const collectionsArg = collectionsValue.map((c) => `'${c}'`).join(", ");
170
+ const appDir = findAppDir();
171
+ if (!appDir) {
172
+ console.error("Could not find app directory. Make sure you are in the root of a Next.js project.");
173
+ process.exit(1);
174
+ }
175
+ const builderDir = path.join(appDir, "block-builder");
176
+ if (!fs.existsSync(builderDir)) {
177
+ fs.mkdirSync(builderDir, { recursive: true });
178
+ }
179
+ const pagePath = path.join(builderDir, "page.tsx");
180
+ const layoutPath = path.join(builderDir, "layout.tsx");
181
+ if (fs.existsSync(pagePath)) {
182
+ console.log(`Skipped: ${pagePath} already exists`);
183
+ } else {
184
+ fs.writeFileSync(pagePath, PAGE_CONTENT);
185
+ console.log(`Created: ${pagePath}`);
186
+ }
187
+ if (fs.existsSync(layoutPath)) {
188
+ console.log(`Skipped: ${layoutPath} already exists`);
189
+ } else {
190
+ fs.writeFileSync(layoutPath, LAYOUT_CONTENT);
191
+ console.log(`Created: ${layoutPath}`);
192
+ }
193
+ const payloadRouteDir = path.join(appDir, "(payload)");
194
+ const customScssPath = path.join(payloadRouteDir, "custom.scss");
195
+ if (fs.existsSync(customScssPath)) {
196
+ const existing = fs.readFileSync(customScssPath, "utf8");
197
+ if (!existing.includes("@nextbridgehq/payload-block-builder")) {
198
+ fs.appendFileSync(customScssPath, "\n" + CUSTOM_SCSS_IMPORTS);
199
+ console.log(`Updated: ${customScssPath} (added admin field styles)`);
200
+ } else {
201
+ console.log(`Skipped: ${customScssPath} already has block-builder imports`);
202
+ }
203
+ }
204
+ const configPath = findPayloadConfig();
205
+ if (!configPath) {
206
+ console.log("\nNote: payload.config.ts not found. Add the plugin manually:");
207
+ console.log(` import { dynamicBlocksPlugin } from '@nextbridgehq/payload-block-builder'`);
208
+ console.log(` plugins: [ dynamicBlocksPlugin({ collections: [${collectionsArg}] }) ]`);
209
+ printNextSteps("other");
210
+ } else {
211
+ const dbAdapter = detectDbAdapter(fs.readFileSync(configPath, "utf8"));
212
+ modifyPayloadConfig(configPath, collectionsArg);
213
+ printNextSteps(dbAdapter);
214
+ }
215
+ }
216
+ main();
package/dist/client.cjs CHANGED
@@ -66,7 +66,7 @@ function MediaPicker({ label, required, value, onChange }) {
66
66
  closeRef.current = closeDrawer;
67
67
  const media = value && typeof value === "object" ? value : null;
68
68
  const mediaId = media?.id ?? (typeof value === "string" || typeof value === "number" ? value : null);
69
- return /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-field" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "bdf-label" }, label, required && /* @__PURE__ */ import_react.default.createElement("span", { className: "bdf-required" }, "*")), /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-upload-area" }, mediaId ? /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-upload-selected" }, media?.url ? /* @__PURE__ */ import_react.default.createElement("img", { src: media.url, alt: media.alt ?? "", className: "bdf-thumb" }) : /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-thumb-placeholder" }, "\xF0\u0178\u2013\xBC"), /* @__PURE__ */ import_react.default.createElement("span", { className: "bdf-upload-name" }, media?.filename ? String(media.filename) : `ID: ${String(mediaId)}`), /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-upload-actions" }, /* @__PURE__ */ import_react.default.createElement(ListDrawerToggler, { className: "bdf-upload-btn" }, "Change"), /* @__PURE__ */ import_react.default.createElement(
69
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-field" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "bdf-label" }, label, required && /* @__PURE__ */ import_react.default.createElement("span", { className: "bdf-required" }, "*")), /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-upload-area" }, mediaId ? /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-upload-selected" }, media?.url ? /* @__PURE__ */ import_react.default.createElement("img", { src: media.url, alt: media.alt ?? "", className: "bdf-thumb" }) : /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-thumb-placeholder" }, "[img]"), /* @__PURE__ */ import_react.default.createElement("span", { className: "bdf-upload-name" }, media?.filename ? String(media.filename) : `ID: ${String(mediaId)}`), /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-upload-actions" }, /* @__PURE__ */ import_react.default.createElement(ListDrawerToggler, { className: "bdf-upload-btn" }, "Change"), /* @__PURE__ */ import_react.default.createElement(
70
70
  "button",
71
71
  {
72
72
  type: "button",
@@ -74,7 +74,7 @@ function MediaPicker({ label, required, value, onChange }) {
74
74
  title: "Remove media",
75
75
  onClick: () => onChange(null)
76
76
  },
77
- "\xE2\u0153\u2022"
77
+ "x"
78
78
  ))) : /* @__PURE__ */ import_react.default.createElement(ListDrawerToggler, { className: "bdf-upload-btn" }, "Choose from Media Library")), /* @__PURE__ */ import_react.default.createElement(ListDrawer, { onSelect: handleSelect }));
79
79
  }
80
80
  function SchemaForm({ schema, value, onChange }) {
@@ -186,7 +186,7 @@ function FieldInput({ field, value, onChange }) {
186
186
  value: value ?? "",
187
187
  onChange: (e) => onChange(e.target.value)
188
188
  },
189
- /* @__PURE__ */ import_react.default.createElement("option", { value: "" }, "\xE2\u20AC\u201D select \xE2\u20AC\u201D"),
189
+ /* @__PURE__ */ import_react.default.createElement("option", { value: "" }, "-- select --"),
190
190
  (field.options ?? []).map((opt) => /* @__PURE__ */ import_react.default.createElement("option", { key: opt.value, value: opt.value }, opt.label))
191
191
  ));
192
192
  case "multiselect": {
@@ -261,7 +261,7 @@ function FieldInput({ field, value, onChange }) {
261
261
  className: "bdf-remove-btn",
262
262
  onClick: () => onChange(rows.filter((_, j) => j !== i))
263
263
  },
264
- "\xE2\u0153\u2022 Remove row"
264
+ "x Remove row"
265
265
  ))), /* @__PURE__ */ import_react.default.createElement(
266
266
  "button",
267
267
  {
@@ -317,7 +317,7 @@ function BlockDataField({ path }) {
317
317
  return /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-empty" }, "Select a ", /* @__PURE__ */ import_react.default.createElement("strong", null, "Block Version"), " above to configure block data fields.");
318
318
  }
319
319
  if (loading) {
320
- return /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-loading" }, "Loading schema\xE2\u20AC\xA6");
320
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-loading" }, "Loading schema...");
321
321
  }
322
322
  if (error) {
323
323
  return /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-error" }, "Failed to load schema: ", error);
@@ -410,7 +410,7 @@ function OptionsEditor({ options, onChange, readOnly }) {
410
410
  title: "Remove option",
411
411
  onClick: () => removeOption(i)
412
412
  },
413
- "\xE2\u0153\u2022"
413
+ "x"
414
414
  ))), !readOnly && /* @__PURE__ */ import_react2.default.createElement(
415
415
  "button",
416
416
  {
@@ -596,7 +596,7 @@ function FieldRow({
596
596
  transform: expanded ? "rotate(90deg)" : "rotate(0deg)"
597
597
  }
598
598
  },
599
- "\xE2\u2013\xB6"
599
+ ">"
600
600
  ),
601
601
  /* @__PURE__ */ import_react4.default.createElement("span", { className: `sbf-row__label${!field.name ? " sbf-row__label--empty" : ""}` }, field.name || "unnamed field"),
602
602
  field.required && /* @__PURE__ */ import_react4.default.createElement("span", { style: { color: "var(--theme-error-500, #ef4444)", fontSize: 16, lineHeight: 1, flexShrink: 0 } }, "*"),
@@ -614,8 +614,8 @@ function FieldRow({
614
614
  style: { display: "flex", gap: 2, flexShrink: 0, alignItems: "center" },
615
615
  onClick: (e) => e.stopPropagation()
616
616
  },
617
- onMoveUp && /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", className: "sbf-icon-btn", onClick: onMoveUp, title: "Move up" }, "\xE2\u2020\u2018"),
618
- onMoveDown && /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", className: "sbf-icon-btn", onClick: onMoveDown, title: "Move down" }, "\xE2\u2020\u201C"),
617
+ onMoveUp && /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", className: "sbf-icon-btn", onClick: onMoveUp, title: "Move up" }, "^"),
618
+ onMoveDown && /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", className: "sbf-icon-btn", onClick: onMoveDown, title: "Move down" }, "v"),
619
619
  /* @__PURE__ */ import_react4.default.createElement(
620
620
  "button",
621
621
  {
@@ -624,7 +624,7 @@ function FieldRow({
624
624
  onClick: onRemove,
625
625
  title: "Remove field"
626
626
  },
627
- "\xE2\u0153\u2022"
627
+ "x"
628
628
  )
629
629
  )
630
630
  ), expanded && /* @__PURE__ */ import_react4.default.createElement("div", { className: "sbf-row__content" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "sbf-grid-2" }, /* @__PURE__ */ import_react4.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react4.default.createElement(FieldLabel, { required: true }, "Field Name"), /* @__PURE__ */ import_react4.default.createElement(
@@ -759,7 +759,7 @@ function FieldRow({
759
759
  onClick: () => setShowAdmin((p) => !p)
760
760
  },
761
761
  "Admin & UI settings",
762
- /* @__PURE__ */ import_react4.default.createElement("span", { className: "sbf-section__toggle-icon" }, "\xE2\u2013\xB6")
762
+ /* @__PURE__ */ import_react4.default.createElement("span", { className: "sbf-section__toggle-icon" }, ">")
763
763
  ), showAdmin && /* @__PURE__ */ import_react4.default.createElement("div", { className: "sbf-section__body" }, /* @__PURE__ */ import_react4.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react4.default.createElement(FieldLabel, null, "Description"), /* @__PURE__ */ import_react4.default.createElement(
764
764
  "input",
765
765
  {
@@ -818,7 +818,7 @@ function FieldRow({
818
818
  " rule",
819
819
  field.conditions.length !== 1 ? "s" : ""
820
820
  ),
821
- /* @__PURE__ */ import_react4.default.createElement("span", { className: "sbf-section__toggle-icon" }, "\xE2\u2013\xB6")
821
+ /* @__PURE__ */ import_react4.default.createElement("span", { className: "sbf-section__toggle-icon" }, ">")
822
822
  ), showConditions && /* @__PURE__ */ import_react4.default.createElement("div", { className: "sbf-section__body" }, /* @__PURE__ */ import_react4.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react4.default.createElement(FieldLabel, null, "Condition Mode"), /* @__PURE__ */ import_react4.default.createElement(
823
823
  "select",
824
824
  {
@@ -828,8 +828,8 @@ function FieldRow({
828
828
  onChange: (e) => set("conditionMode", e.target.value),
829
829
  style: { width: "auto", minWidth: 240 }
830
830
  },
831
- /* @__PURE__ */ import_react4.default.createElement("option", { value: "AND" }, "AND \xE2\u20AC\u201D all conditions must match"),
832
- /* @__PURE__ */ import_react4.default.createElement("option", { value: "OR" }, "OR \xE2\u20AC\u201D any condition must match")
831
+ /* @__PURE__ */ import_react4.default.createElement("option", { value: "AND" }, "AND - all conditions must match"),
832
+ /* @__PURE__ */ import_react4.default.createElement("option", { value: "OR" }, "OR - any condition must match")
833
833
  )), (field.conditions ?? []).map((cond, ci) => /* @__PURE__ */ import_react4.default.createElement("div", { key: ci, className: "sbf-conditions-grid" }, /* @__PURE__ */ import_react4.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react4.default.createElement(FieldLabel, null, "Field"), /* @__PURE__ */ import_react4.default.createElement(
834
834
  "input",
835
835
  {
@@ -881,7 +881,7 @@ function FieldRow({
881
881
  set("conditions", (field.conditions ?? []).filter((_, k) => k !== ci));
882
882
  }
883
883
  },
884
- "\xE2\u0153\u2022"
884
+ "x"
885
885
  ))), !readOnly && /* @__PURE__ */ import_react4.default.createElement(
886
886
  "button",
887
887
  {
@@ -1186,7 +1186,7 @@ function normalizeSlug(slug) {
1186
1186
  function mapToSaveRequest(block) {
1187
1187
  const fields = block.fields.filter((f) => {
1188
1188
  if (UNSUPPORTED.has(f.type)) {
1189
- console.warn(`[block-builder] Field type "${f.type}" is not supported in this project \xE2\u20AC\u201D skipping field "${f.name}"`);
1189
+ console.warn(`[block-builder] Field type "${f.type}" is not supported in this project \xE2\u20AC" skipping field "${f.name}"`);
1190
1190
  return false;
1191
1191
  }
1192
1192
  return true;
@@ -1411,16 +1411,16 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1411
1411
  function formatDate(iso) {
1412
1412
  return new Date(iso).toLocaleDateString(void 0, { month: "short", day: "numeric" });
1413
1413
  }
1414
- return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-topbar" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-topbar__brand" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-topbar__title" }, "Block Builder"), isDirty && !isReadOnly && /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-topbar__dirty" }, "\xE2\u2014\x8F unsaved")), /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-topbar__selectors" }, blockDefs.length > 0 && /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-block-picker", ref: blockPickerRef }, /* @__PURE__ */ import_react7.default.createElement(
1414
+ return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-topbar" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-topbar__brand" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-topbar__title" }, "Block Builder"), isDirty && !isReadOnly && /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-topbar__dirty" }, "* unsaved")), /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-topbar__selectors" }, blockDefs.length > 0 && /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-block-picker", ref: blockPickerRef }, /* @__PURE__ */ import_react7.default.createElement(
1415
1415
  "button",
1416
1416
  {
1417
1417
  type: "button",
1418
1418
  className: "bb-block-picker__trigger",
1419
1419
  onClick: () => setBlockPickerOpen((o) => !o)
1420
1420
  },
1421
- /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-block-picker__icon" }, "\xE2\xAC\xA1"),
1421
+ /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-block-picker__icon" }, "B"),
1422
1422
  /* @__PURE__ */ import_react7.default.createElement("span", null, activeBlockDef?.name ?? activeSlug ?? "Select a block"),
1423
- /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-version-selector__chevron" }, "\xE2\u2013\xBE")
1423
+ /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-version-selector__chevron" }, "v")
1424
1424
  ), blockPickerOpen && /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-block-picker__dropdown" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-version-dropdown__header" }, "Block Definitions"), blockDefs.map((b) => /* @__PURE__ */ import_react7.default.createElement(
1425
1425
  "button",
1426
1426
  {
@@ -1444,7 +1444,7 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1444
1444
  /* @__PURE__ */ import_react7.default.createElement("span", { className: `bb-version-selector__dot${selectedVersion?.isCurrent ? " bb-version-selector__dot--current" : " bb-version-selector__dot--old"}` }),
1445
1445
  /* @__PURE__ */ import_react7.default.createElement("span", null, selectedVersion?.label ?? `v${selectedVersion?.versionNumber ?? "?"}`),
1446
1446
  selectedVersion?.isCurrent && /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-version-selector__badge" }, "current"),
1447
- /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-version-selector__chevron" }, "\xE2\u2013\xBE")
1447
+ /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-version-selector__chevron" }, "v")
1448
1448
  ), versionDropdownOpen && /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-version-dropdown" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-version-dropdown__header" }, "Version History"), versions.map((v) => /* @__PURE__ */ import_react7.default.createElement(
1449
1449
  "button",
1450
1450
  {
@@ -1458,7 +1458,7 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1458
1458
  },
1459
1459
  /* @__PURE__ */ import_react7.default.createElement("span", { className: `bb-version-selector__dot${v.isCurrent ? " bb-version-selector__dot--current" : " bb-version-selector__dot--old"}` }),
1460
1460
  /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-version-dropdown__label" }, v.label, v.isCurrent && /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-version-selector__badge" }, "current")),
1461
- /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-version-dropdown__meta" }, v.changelog ? `${v.changelog.slice(0, 32)}${v.changelog.length > 32 ? "\xE2\u20AC\xA6" : ""}` : formatDate(v.createdAt))
1461
+ /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-version-dropdown__meta" }, v.changelog ? `${v.changelog.slice(0, 32)}${v.changelog.length > 32 ? "..." : ""}` : formatDate(v.createdAt))
1462
1462
  ))))), /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-topbar__actions" }, /* @__PURE__ */ import_react7.default.createElement(
1463
1463
  "button",
1464
1464
  {
@@ -1492,7 +1492,7 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1492
1492
  disabled: notification?.status === "publishing" || !activeBlock,
1493
1493
  className: "bb-btn bb-btn--warning"
1494
1494
  },
1495
- notification?.status === "publishing" ? "Restoring\xE2\u20AC\xA6" : "Restore as new version"
1495
+ notification?.status === "publishing" ? "Restoring..." : "Restore as new version"
1496
1496
  )) : /* @__PURE__ */ import_react7.default.createElement(
1497
1497
  "button",
1498
1498
  {
@@ -1501,8 +1501,8 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1501
1501
  disabled: notification?.status === "publishing" || !activeBlock,
1502
1502
  className: "bb-btn bb-btn--primary"
1503
1503
  },
1504
- notification?.status === "publishing" ? "Publishing\xE2\u20AC\xA6" : "Publish to Payload"
1505
- ))), notification?.status === "publishing" && /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify bb-notify--publishing" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__spinner" }), /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ import_react7.default.createElement("p", { className: "bb-notify__title" }, isReadOnly ? "Restoring version\xE2\u20AC\xA6" : "Publishing to Payload\xE2\u20AC\xA6"), /* @__PURE__ */ import_react7.default.createElement("p", { className: "bb-notify__sub" }, "Validating schema and saving block definition.")))), notification?.status === "success" && /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify bb-notify--success" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-notify__icon" }, "\xE2\u0153\u201C"), /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ import_react7.default.createElement("p", { className: "bb-notify__title" }, notification.msg), /* @__PURE__ */ import_react7.default.createElement("p", { className: "bb-notify__sub" }, "The block definition and version have been saved.")), /* @__PURE__ */ import_react7.default.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, "\xE2\u0153\u2022"))), notification?.status === "error" && /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify bb-notify--error" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-notify__icon" }, "\xE2\u0153\u2022"), /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ import_react7.default.createElement("p", { className: "bb-notify__title" }, notification.title), /* @__PURE__ */ import_react7.default.createElement("p", { className: "bb-notify__sub" }, "Fix the following errors before publishing:"), /* @__PURE__ */ import_react7.default.createElement("ul", { className: "bb-notify__error-list" }, notification.errors.map((e, i) => /* @__PURE__ */ import_react7.default.createElement("li", { key: i }, e)))), /* @__PURE__ */ import_react7.default.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, "\xE2\u0153\u2022"))));
1504
+ notification?.status === "publishing" ? "Publishing..." : "Publish to Payload"
1505
+ ))), notification?.status === "publishing" && /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify bb-notify--publishing" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__spinner" }), /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ import_react7.default.createElement("p", { className: "bb-notify__title" }, isReadOnly ? "Restoring version..." : "Publishing to Payload..."), /* @__PURE__ */ import_react7.default.createElement("p", { className: "bb-notify__sub" }, "Validating schema and saving block definition.")))), notification?.status === "success" && /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify bb-notify--success" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-notify__icon" }, "OK"), /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ import_react7.default.createElement("p", { className: "bb-notify__title" }, notification.msg), /* @__PURE__ */ import_react7.default.createElement("p", { className: "bb-notify__sub" }, "The block definition and version have been saved.")), /* @__PURE__ */ import_react7.default.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, "x"))), notification?.status === "error" && /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify bb-notify--error" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "bb-notify__icon" }, "!"), /* @__PURE__ */ import_react7.default.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ import_react7.default.createElement("p", { className: "bb-notify__title" }, notification.title), /* @__PURE__ */ import_react7.default.createElement("p", { className: "bb-notify__sub" }, "Fix the following errors before publishing:"), /* @__PURE__ */ import_react7.default.createElement("ul", { className: "bb-notify__error-list" }, notification.errors.map((e, i) => /* @__PURE__ */ import_react7.default.createElement("li", { key: i }, e)))), /* @__PURE__ */ import_react7.default.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, "x"))));
1506
1506
  }
1507
1507
 
1508
1508
  // src/block-builder/components/canvas/BlockList.tsx
@@ -1539,7 +1539,7 @@ function BlockList() {
1539
1539
  className: "bb-block-action",
1540
1540
  title: "Duplicate"
1541
1541
  },
1542
- "\xE2\xA7\u2030"
1542
+ "="
1543
1543
  ),
1544
1544
  /* @__PURE__ */ import_react8.default.createElement(
1545
1545
  "button",
@@ -1549,7 +1549,7 @@ function BlockList() {
1549
1549
  className: "bb-block-action bb-block-action--danger",
1550
1550
  title: "Delete"
1551
1551
  },
1552
- "\xE2\u0153\u2022"
1552
+ "x"
1553
1553
  )
1554
1554
  )
1555
1555
  );
@@ -1567,23 +1567,23 @@ var import_react9 = __toESM(require("react"), 1);
1567
1567
  var import_sortable = require("@dnd-kit/sortable");
1568
1568
  var import_utilities = require("@dnd-kit/utilities");
1569
1569
  var ICON_MAP = {
1570
- text: "\xF0\u0178\u201C\x9D",
1571
- textarea: "\xF0\u0178\u201C\u201E",
1572
- richText: "\xF0\u0178\u201C\xB0",
1573
- number: "\xF0\u0178\u201D\xA2",
1574
- checkbox: "\xE2\u02DC\u2018",
1575
- select: "\xE2\u2013\xBE",
1576
- radio: "\xE2\u2014\u2030",
1577
- date: "\xF0\u0178\u201C\u2026",
1578
- upload: "\xF0\u0178\u201C\u017D",
1579
- email: "\xE2\u0153\u2030",
1580
- code: "\xE2\u20AC\xB9\xE2\u20AC\xBA",
1581
- point: "\xE2\u2014\u017D",
1582
- relationship: "\xE2\u2021\u0152",
1583
- array: "\xE2\u2013\xA4",
1584
- group: "\xE2\u2013\xA3",
1585
- json: "{}",
1586
- ui: "\xE2\u2014\u02C6"
1570
+ text: "T",
1571
+ textarea: "Tx",
1572
+ richText: "RT",
1573
+ number: "#",
1574
+ checkbox: "[x]",
1575
+ select: "v",
1576
+ radio: "(o)",
1577
+ date: "D",
1578
+ upload: "^",
1579
+ email: "@",
1580
+ code: "<>",
1581
+ point: "P",
1582
+ relationship: "->>",
1583
+ array: "[]",
1584
+ group: "{ }",
1585
+ json: "{ }",
1586
+ ui: "UI"
1587
1587
  };
1588
1588
  function SortableFieldCard({ field, blockId, index }) {
1589
1589
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = (0, import_sortable.useSortable)({
@@ -1612,7 +1612,7 @@ function SortableFieldCard({ field, blockId, index }) {
1612
1612
  className: `bb-field-card${isActive ? " bb-field-card--active" : ""}`,
1613
1613
  onClick: () => setActiveField(isActive ? null : field.id)
1614
1614
  },
1615
- /* @__PURE__ */ import_react9.default.createElement("span", { className: "bb-field-card__icon" }, ICON_MAP[field.type] ?? "\xE2\u2014\xBB"),
1615
+ /* @__PURE__ */ import_react9.default.createElement("span", { className: "bb-field-card__icon" }, ICON_MAP[field.type] ?? "?"),
1616
1616
  /* @__PURE__ */ import_react9.default.createElement("div", { className: "bb-field-card__body" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "bb-field-card__name" }, field.name || /* @__PURE__ */ import_react9.default.createElement("span", { className: "bb-field-card__name--empty" }, "unnamed")), /* @__PURE__ */ import_react9.default.createElement("div", { className: "bb-field-card__type" }, field.type, field.required && /* @__PURE__ */ import_react9.default.createElement("span", { className: "bb-field-card__required" }, "*"))),
1617
1617
  /* @__PURE__ */ import_react9.default.createElement("span", { className: "bb-field-card__index" }, "#", index + 1),
1618
1618
  /* @__PURE__ */ import_react9.default.createElement(
@@ -1627,7 +1627,7 @@ function SortableFieldCard({ field, blockId, index }) {
1627
1627
  className: "bb-field-card__delete",
1628
1628
  title: "Remove field"
1629
1629
  },
1630
- "\xE2\u0153\u2022"
1630
+ "x"
1631
1631
  )
1632
1632
  )
1633
1633
  );
@@ -1656,7 +1656,7 @@ function BuilderCanvas() {
1656
1656
  if (!block) {
1657
1657
  return /* @__PURE__ */ import_react10.default.createElement("div", { className: "bb-canvas", style: { display: "flex", alignItems: "center", justifyContent: "center" } }, /* @__PURE__ */ import_react10.default.createElement("span", { className: "bb-canvas__no-block" }, "Select or create a block from the left panel."));
1658
1658
  }
1659
- return /* @__PURE__ */ import_react10.default.createElement("div", { className: `bb-canvas${isReadOnly ? " bb-canvas--readonly" : ""}` }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "bb-canvas__inner" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "bb-canvas__header" }, block.slug, " \xE2\u20AC\u201D ", block.fields.length, " field", block.fields.length !== 1 ? "s" : ""), block.fields.length === 0 ? /* @__PURE__ */ import_react10.default.createElement("div", { className: "bb-canvas__empty" }, "Add fields from the palette on the left") : /* @__PURE__ */ import_react10.default.createElement(
1659
+ return /* @__PURE__ */ import_react10.default.createElement("div", { className: `bb-canvas${isReadOnly ? " bb-canvas--readonly" : ""}` }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "bb-canvas__inner" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "bb-canvas__header" }, block.slug, " - ", block.fields.length, " field", block.fields.length !== 1 ? "s" : ""), block.fields.length === 0 ? /* @__PURE__ */ import_react10.default.createElement("div", { className: "bb-canvas__empty" }, "Add fields from the palette on the left") : /* @__PURE__ */ import_react10.default.createElement(
1660
1660
  import_core.DndContext,
1661
1661
  {
1662
1662
  sensors,
@@ -1737,7 +1737,7 @@ function BlockConfig() {
1737
1737
  type: "text",
1738
1738
  value: block.imageURL ?? "",
1739
1739
  onChange: (e) => updateBlock(block.id, { imageURL: e.target.value || void 0 }),
1740
- placeholder: "https://\xE2\u20AC\xA6",
1740
+ placeholder: "https://...",
1741
1741
  className: "bb-input"
1742
1742
  }
1743
1743
  )), /* @__PURE__ */ import_react11.default.createElement("div", { className: "bb-stat-box" }, /* @__PURE__ */ import_react11.default.createElement("strong", null, block.fields.length), " field", block.fields.length !== 1 ? "s" : "", " defined"));
@@ -1902,7 +1902,7 @@ function FieldConfig() {
1902
1902
  className: "bb-option-delete",
1903
1903
  title: "Remove option"
1904
1904
  },
1905
- "\xE2\u0153\u2022"
1905
+ "x"
1906
1906
  ))), /* @__PURE__ */ import_react12.default.createElement(
1907
1907
  "button",
1908
1908
  {
@@ -2000,7 +2000,7 @@ function FieldPalette() {
2000
2000
  type: "text",
2001
2001
  value: search,
2002
2002
  onChange: (e) => setSearch(e.target.value),
2003
- placeholder: "Search\xE2\u20AC\xA6",
2003
+ placeholder: "Search...",
2004
2004
  className: "bb-palette__search"
2005
2005
  }
2006
2006
  )), /* @__PURE__ */ import_react14.default.createElement("div", { className: "bb-sidebar__body" }, search.trim() ? /* @__PURE__ */ import_react14.default.createElement("div", { className: "bb-palette__items" }, filtered.map((item) => /* @__PURE__ */ import_react14.default.createElement(
@@ -2275,7 +2275,7 @@ function CodePreview() {
2275
2275
  gap: "0.25rem"
2276
2276
  }
2277
2277
  },
2278
- copied ? "\xE2\u0153\u201C Copied" : "\xE2\xA7\u2030 Copy"
2278
+ copied ? "Copied" : "Copy"
2279
2279
  )
2280
2280
  ), /* @__PURE__ */ import_react15.default.createElement("div", { style: { flex: 1, overflow: "auto", display: "flex" } }, /* @__PURE__ */ import_react15.default.createElement(
2281
2281
  "div",
@@ -2413,7 +2413,7 @@ function BuilderShell({ loadSlug }) {
2413
2413
  onRestoreVersion: handleRestoreVersion,
2414
2414
  onAfterPublish: handleAfterPublish
2415
2415
  }
2416
- ), loading && /* @__PURE__ */ import_react16.default.createElement("div", { className: "bb-loading-bar" }, "Loading\xE2\u20AC\xA6"), loadError && /* @__PURE__ */ import_react16.default.createElement("div", { className: "bb-error-bar" }, "Error: ", loadError), isReadOnly && !loading && /* @__PURE__ */ import_react16.default.createElement("div", { className: "bb-readonly-banner" }, /* @__PURE__ */ import_react16.default.createElement("span", { className: "bb-readonly-banner__icon" }, "\xF0\u0178\u2018\x81"), /* @__PURE__ */ import_react16.default.createElement("span", null, "You are viewing a previous version \xE2\u20AC\u201D read only.", /* @__PURE__ */ import_react16.default.createElement(
2416
+ ), loading && /* @__PURE__ */ import_react16.default.createElement("div", { className: "bb-loading-bar" }, "Loading..."), loadError && /* @__PURE__ */ import_react16.default.createElement("div", { className: "bb-error-bar" }, "Error: ", loadError), isReadOnly && !loading && /* @__PURE__ */ import_react16.default.createElement("div", { className: "bb-readonly-banner" }, /* @__PURE__ */ import_react16.default.createElement("span", { className: "bb-readonly-banner__icon" }, "[i]"), /* @__PURE__ */ import_react16.default.createElement("span", null, "You are viewing a previous version - read only.", /* @__PURE__ */ import_react16.default.createElement(
2417
2417
  "button",
2418
2418
  {
2419
2419
  type: "button",
@@ -2428,13 +2428,13 @@ function BuilderShell({ loadSlug }) {
2428
2428
  onClick: () => setShowCodePreview((p) => !p),
2429
2429
  className: `bb-footer__toggle${showCodePreview ? " bb-footer__toggle--open" : ""}`
2430
2430
  },
2431
- showCodePreview ? "\xE2\u2013\xBC" : "\xE2\u2013\xB6",
2431
+ showCodePreview ? "v" : ">",
2432
2432
  " Code Preview"
2433
2433
  ), showCodePreview && /* @__PURE__ */ import_react16.default.createElement("div", { className: "bb-footer__content" }, /* @__PURE__ */ import_react16.default.createElement(CodePreview, null))), /* @__PURE__ */ import_react16.default.createElement("nav", { className: "bb-mobile-nav", "aria-label": "Panel navigation" }, [
2434
- { id: "blocks", icon: "\xE2\xAC\xA1", label: "Blocks" },
2435
- { id: "canvas", icon: "\xE2\u2013\xA6", label: "Canvas" },
2436
- { id: "palette", icon: "\xEF\xBC\u2039", label: "Fields" },
2437
- { id: "config", icon: "\xE2\u0161\u2122", label: "Config" }
2434
+ { id: "blocks", icon: "B", label: "Blocks" },
2435
+ { id: "canvas", icon: "[]", label: "Canvas" },
2436
+ { id: "palette", icon: "+", label: "Fields" },
2437
+ { id: "config", icon: "*", label: "Config" }
2438
2438
  ].map(({ id, icon, label }) => /* @__PURE__ */ import_react16.default.createElement(
2439
2439
  "button",
2440
2440
  {
package/dist/client.js CHANGED
@@ -28,7 +28,7 @@ function MediaPicker({ label, required, value, onChange }) {
28
28
  closeRef.current = closeDrawer;
29
29
  const media = value && typeof value === "object" ? value : null;
30
30
  const mediaId = media?.id ?? (typeof value === "string" || typeof value === "number" ? value : null);
31
- return /* @__PURE__ */ React.createElement("div", { className: "bdf-field" }, /* @__PURE__ */ React.createElement("label", { className: "bdf-label" }, label, required && /* @__PURE__ */ React.createElement("span", { className: "bdf-required" }, "*")), /* @__PURE__ */ React.createElement("div", { className: "bdf-upload-area" }, mediaId ? /* @__PURE__ */ React.createElement("div", { className: "bdf-upload-selected" }, media?.url ? /* @__PURE__ */ React.createElement("img", { src: media.url, alt: media.alt ?? "", className: "bdf-thumb" }) : /* @__PURE__ */ React.createElement("div", { className: "bdf-thumb-placeholder" }, "\xF0\u0178\u2013\xBC"), /* @__PURE__ */ React.createElement("span", { className: "bdf-upload-name" }, media?.filename ? String(media.filename) : `ID: ${String(mediaId)}`), /* @__PURE__ */ React.createElement("div", { className: "bdf-upload-actions" }, /* @__PURE__ */ React.createElement(ListDrawerToggler, { className: "bdf-upload-btn" }, "Change"), /* @__PURE__ */ React.createElement(
31
+ return /* @__PURE__ */ React.createElement("div", { className: "bdf-field" }, /* @__PURE__ */ React.createElement("label", { className: "bdf-label" }, label, required && /* @__PURE__ */ React.createElement("span", { className: "bdf-required" }, "*")), /* @__PURE__ */ React.createElement("div", { className: "bdf-upload-area" }, mediaId ? /* @__PURE__ */ React.createElement("div", { className: "bdf-upload-selected" }, media?.url ? /* @__PURE__ */ React.createElement("img", { src: media.url, alt: media.alt ?? "", className: "bdf-thumb" }) : /* @__PURE__ */ React.createElement("div", { className: "bdf-thumb-placeholder" }, "[img]"), /* @__PURE__ */ React.createElement("span", { className: "bdf-upload-name" }, media?.filename ? String(media.filename) : `ID: ${String(mediaId)}`), /* @__PURE__ */ React.createElement("div", { className: "bdf-upload-actions" }, /* @__PURE__ */ React.createElement(ListDrawerToggler, { className: "bdf-upload-btn" }, "Change"), /* @__PURE__ */ React.createElement(
32
32
  "button",
33
33
  {
34
34
  type: "button",
@@ -36,7 +36,7 @@ function MediaPicker({ label, required, value, onChange }) {
36
36
  title: "Remove media",
37
37
  onClick: () => onChange(null)
38
38
  },
39
- "\xE2\u0153\u2022"
39
+ "x"
40
40
  ))) : /* @__PURE__ */ React.createElement(ListDrawerToggler, { className: "bdf-upload-btn" }, "Choose from Media Library")), /* @__PURE__ */ React.createElement(ListDrawer, { onSelect: handleSelect }));
41
41
  }
42
42
  function SchemaForm({ schema, value, onChange }) {
@@ -148,7 +148,7 @@ function FieldInput({ field, value, onChange }) {
148
148
  value: value ?? "",
149
149
  onChange: (e) => onChange(e.target.value)
150
150
  },
151
- /* @__PURE__ */ React.createElement("option", { value: "" }, "\xE2\u20AC\u201D select \xE2\u20AC\u201D"),
151
+ /* @__PURE__ */ React.createElement("option", { value: "" }, "-- select --"),
152
152
  (field.options ?? []).map((opt) => /* @__PURE__ */ React.createElement("option", { key: opt.value, value: opt.value }, opt.label))
153
153
  ));
154
154
  case "multiselect": {
@@ -223,7 +223,7 @@ function FieldInput({ field, value, onChange }) {
223
223
  className: "bdf-remove-btn",
224
224
  onClick: () => onChange(rows.filter((_, j) => j !== i))
225
225
  },
226
- "\xE2\u0153\u2022 Remove row"
226
+ "x Remove row"
227
227
  ))), /* @__PURE__ */ React.createElement(
228
228
  "button",
229
229
  {
@@ -279,7 +279,7 @@ function BlockDataField({ path }) {
279
279
  return /* @__PURE__ */ React.createElement("div", { className: "bdf-empty" }, "Select a ", /* @__PURE__ */ React.createElement("strong", null, "Block Version"), " above to configure block data fields.");
280
280
  }
281
281
  if (loading) {
282
- return /* @__PURE__ */ React.createElement("div", { className: "bdf-loading" }, "Loading schema\xE2\u20AC\xA6");
282
+ return /* @__PURE__ */ React.createElement("div", { className: "bdf-loading" }, "Loading schema...");
283
283
  }
284
284
  if (error) {
285
285
  return /* @__PURE__ */ React.createElement("div", { className: "bdf-error" }, "Failed to load schema: ", error);
@@ -372,7 +372,7 @@ function OptionsEditor({ options, onChange, readOnly }) {
372
372
  title: "Remove option",
373
373
  onClick: () => removeOption(i)
374
374
  },
375
- "\xE2\u0153\u2022"
375
+ "x"
376
376
  ))), !readOnly && /* @__PURE__ */ React2.createElement(
377
377
  "button",
378
378
  {
@@ -558,7 +558,7 @@ function FieldRow({
558
558
  transform: expanded ? "rotate(90deg)" : "rotate(0deg)"
559
559
  }
560
560
  },
561
- "\xE2\u2013\xB6"
561
+ ">"
562
562
  ),
563
563
  /* @__PURE__ */ React4.createElement("span", { className: `sbf-row__label${!field.name ? " sbf-row__label--empty" : ""}` }, field.name || "unnamed field"),
564
564
  field.required && /* @__PURE__ */ React4.createElement("span", { style: { color: "var(--theme-error-500, #ef4444)", fontSize: 16, lineHeight: 1, flexShrink: 0 } }, "*"),
@@ -576,8 +576,8 @@ function FieldRow({
576
576
  style: { display: "flex", gap: 2, flexShrink: 0, alignItems: "center" },
577
577
  onClick: (e) => e.stopPropagation()
578
578
  },
579
- onMoveUp && /* @__PURE__ */ React4.createElement("button", { type: "button", className: "sbf-icon-btn", onClick: onMoveUp, title: "Move up" }, "\xE2\u2020\u2018"),
580
- onMoveDown && /* @__PURE__ */ React4.createElement("button", { type: "button", className: "sbf-icon-btn", onClick: onMoveDown, title: "Move down" }, "\xE2\u2020\u201C"),
579
+ onMoveUp && /* @__PURE__ */ React4.createElement("button", { type: "button", className: "sbf-icon-btn", onClick: onMoveUp, title: "Move up" }, "^"),
580
+ onMoveDown && /* @__PURE__ */ React4.createElement("button", { type: "button", className: "sbf-icon-btn", onClick: onMoveDown, title: "Move down" }, "v"),
581
581
  /* @__PURE__ */ React4.createElement(
582
582
  "button",
583
583
  {
@@ -586,7 +586,7 @@ function FieldRow({
586
586
  onClick: onRemove,
587
587
  title: "Remove field"
588
588
  },
589
- "\xE2\u0153\u2022"
589
+ "x"
590
590
  )
591
591
  )
592
592
  ), expanded && /* @__PURE__ */ React4.createElement("div", { className: "sbf-row__content" }, /* @__PURE__ */ React4.createElement("div", { className: "sbf-grid-2" }, /* @__PURE__ */ React4.createElement(FieldWrap, null, /* @__PURE__ */ React4.createElement(FieldLabel, { required: true }, "Field Name"), /* @__PURE__ */ React4.createElement(
@@ -721,7 +721,7 @@ function FieldRow({
721
721
  onClick: () => setShowAdmin((p) => !p)
722
722
  },
723
723
  "Admin & UI settings",
724
- /* @__PURE__ */ React4.createElement("span", { className: "sbf-section__toggle-icon" }, "\xE2\u2013\xB6")
724
+ /* @__PURE__ */ React4.createElement("span", { className: "sbf-section__toggle-icon" }, ">")
725
725
  ), showAdmin && /* @__PURE__ */ React4.createElement("div", { className: "sbf-section__body" }, /* @__PURE__ */ React4.createElement(FieldWrap, null, /* @__PURE__ */ React4.createElement(FieldLabel, null, "Description"), /* @__PURE__ */ React4.createElement(
726
726
  "input",
727
727
  {
@@ -780,7 +780,7 @@ function FieldRow({
780
780
  " rule",
781
781
  field.conditions.length !== 1 ? "s" : ""
782
782
  ),
783
- /* @__PURE__ */ React4.createElement("span", { className: "sbf-section__toggle-icon" }, "\xE2\u2013\xB6")
783
+ /* @__PURE__ */ React4.createElement("span", { className: "sbf-section__toggle-icon" }, ">")
784
784
  ), showConditions && /* @__PURE__ */ React4.createElement("div", { className: "sbf-section__body" }, /* @__PURE__ */ React4.createElement(FieldWrap, null, /* @__PURE__ */ React4.createElement(FieldLabel, null, "Condition Mode"), /* @__PURE__ */ React4.createElement(
785
785
  "select",
786
786
  {
@@ -790,8 +790,8 @@ function FieldRow({
790
790
  onChange: (e) => set("conditionMode", e.target.value),
791
791
  style: { width: "auto", minWidth: 240 }
792
792
  },
793
- /* @__PURE__ */ React4.createElement("option", { value: "AND" }, "AND \xE2\u20AC\u201D all conditions must match"),
794
- /* @__PURE__ */ React4.createElement("option", { value: "OR" }, "OR \xE2\u20AC\u201D any condition must match")
793
+ /* @__PURE__ */ React4.createElement("option", { value: "AND" }, "AND - all conditions must match"),
794
+ /* @__PURE__ */ React4.createElement("option", { value: "OR" }, "OR - any condition must match")
795
795
  )), (field.conditions ?? []).map((cond, ci) => /* @__PURE__ */ React4.createElement("div", { key: ci, className: "sbf-conditions-grid" }, /* @__PURE__ */ React4.createElement(FieldWrap, null, /* @__PURE__ */ React4.createElement(FieldLabel, null, "Field"), /* @__PURE__ */ React4.createElement(
796
796
  "input",
797
797
  {
@@ -843,7 +843,7 @@ function FieldRow({
843
843
  set("conditions", (field.conditions ?? []).filter((_, k) => k !== ci));
844
844
  }
845
845
  },
846
- "\xE2\u0153\u2022"
846
+ "x"
847
847
  ))), !readOnly && /* @__PURE__ */ React4.createElement(
848
848
  "button",
849
849
  {
@@ -1148,7 +1148,7 @@ function normalizeSlug(slug) {
1148
1148
  function mapToSaveRequest(block) {
1149
1149
  const fields = block.fields.filter((f) => {
1150
1150
  if (UNSUPPORTED.has(f.type)) {
1151
- console.warn(`[block-builder] Field type "${f.type}" is not supported in this project \xE2\u20AC\u201D skipping field "${f.name}"`);
1151
+ console.warn(`[block-builder] Field type "${f.type}" is not supported in this project \xE2\u20AC" skipping field "${f.name}"`);
1152
1152
  return false;
1153
1153
  }
1154
1154
  return true;
@@ -1373,16 +1373,16 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1373
1373
  function formatDate(iso) {
1374
1374
  return new Date(iso).toLocaleDateString(void 0, { month: "short", day: "numeric" });
1375
1375
  }
1376
- return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement("div", { className: "bb-topbar" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-topbar__brand" }, /* @__PURE__ */ React7.createElement("span", { className: "bb-topbar__title" }, "Block Builder"), isDirty && !isReadOnly && /* @__PURE__ */ React7.createElement("span", { className: "bb-topbar__dirty" }, "\xE2\u2014\x8F unsaved")), /* @__PURE__ */ React7.createElement("div", { className: "bb-topbar__selectors" }, blockDefs.length > 0 && /* @__PURE__ */ React7.createElement("div", { className: "bb-block-picker", ref: blockPickerRef }, /* @__PURE__ */ React7.createElement(
1376
+ return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement("div", { className: "bb-topbar" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-topbar__brand" }, /* @__PURE__ */ React7.createElement("span", { className: "bb-topbar__title" }, "Block Builder"), isDirty && !isReadOnly && /* @__PURE__ */ React7.createElement("span", { className: "bb-topbar__dirty" }, "* unsaved")), /* @__PURE__ */ React7.createElement("div", { className: "bb-topbar__selectors" }, blockDefs.length > 0 && /* @__PURE__ */ React7.createElement("div", { className: "bb-block-picker", ref: blockPickerRef }, /* @__PURE__ */ React7.createElement(
1377
1377
  "button",
1378
1378
  {
1379
1379
  type: "button",
1380
1380
  className: "bb-block-picker__trigger",
1381
1381
  onClick: () => setBlockPickerOpen((o) => !o)
1382
1382
  },
1383
- /* @__PURE__ */ React7.createElement("span", { className: "bb-block-picker__icon" }, "\xE2\xAC\xA1"),
1383
+ /* @__PURE__ */ React7.createElement("span", { className: "bb-block-picker__icon" }, "B"),
1384
1384
  /* @__PURE__ */ React7.createElement("span", null, activeBlockDef?.name ?? activeSlug ?? "Select a block"),
1385
- /* @__PURE__ */ React7.createElement("span", { className: "bb-version-selector__chevron" }, "\xE2\u2013\xBE")
1385
+ /* @__PURE__ */ React7.createElement("span", { className: "bb-version-selector__chevron" }, "v")
1386
1386
  ), blockPickerOpen && /* @__PURE__ */ React7.createElement("div", { className: "bb-block-picker__dropdown" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-version-dropdown__header" }, "Block Definitions"), blockDefs.map((b) => /* @__PURE__ */ React7.createElement(
1387
1387
  "button",
1388
1388
  {
@@ -1406,7 +1406,7 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1406
1406
  /* @__PURE__ */ React7.createElement("span", { className: `bb-version-selector__dot${selectedVersion?.isCurrent ? " bb-version-selector__dot--current" : " bb-version-selector__dot--old"}` }),
1407
1407
  /* @__PURE__ */ React7.createElement("span", null, selectedVersion?.label ?? `v${selectedVersion?.versionNumber ?? "?"}`),
1408
1408
  selectedVersion?.isCurrent && /* @__PURE__ */ React7.createElement("span", { className: "bb-version-selector__badge" }, "current"),
1409
- /* @__PURE__ */ React7.createElement("span", { className: "bb-version-selector__chevron" }, "\xE2\u2013\xBE")
1409
+ /* @__PURE__ */ React7.createElement("span", { className: "bb-version-selector__chevron" }, "v")
1410
1410
  ), versionDropdownOpen && /* @__PURE__ */ React7.createElement("div", { className: "bb-version-dropdown" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-version-dropdown__header" }, "Version History"), versions.map((v) => /* @__PURE__ */ React7.createElement(
1411
1411
  "button",
1412
1412
  {
@@ -1420,7 +1420,7 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1420
1420
  },
1421
1421
  /* @__PURE__ */ React7.createElement("span", { className: `bb-version-selector__dot${v.isCurrent ? " bb-version-selector__dot--current" : " bb-version-selector__dot--old"}` }),
1422
1422
  /* @__PURE__ */ React7.createElement("span", { className: "bb-version-dropdown__label" }, v.label, v.isCurrent && /* @__PURE__ */ React7.createElement("span", { className: "bb-version-selector__badge" }, "current")),
1423
- /* @__PURE__ */ React7.createElement("span", { className: "bb-version-dropdown__meta" }, v.changelog ? `${v.changelog.slice(0, 32)}${v.changelog.length > 32 ? "\xE2\u20AC\xA6" : ""}` : formatDate(v.createdAt))
1423
+ /* @__PURE__ */ React7.createElement("span", { className: "bb-version-dropdown__meta" }, v.changelog ? `${v.changelog.slice(0, 32)}${v.changelog.length > 32 ? "..." : ""}` : formatDate(v.createdAt))
1424
1424
  ))))), /* @__PURE__ */ React7.createElement("div", { className: "bb-topbar__actions" }, /* @__PURE__ */ React7.createElement(
1425
1425
  "button",
1426
1426
  {
@@ -1454,7 +1454,7 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1454
1454
  disabled: notification?.status === "publishing" || !activeBlock,
1455
1455
  className: "bb-btn bb-btn--warning"
1456
1456
  },
1457
- notification?.status === "publishing" ? "Restoring\xE2\u20AC\xA6" : "Restore as new version"
1457
+ notification?.status === "publishing" ? "Restoring..." : "Restore as new version"
1458
1458
  )) : /* @__PURE__ */ React7.createElement(
1459
1459
  "button",
1460
1460
  {
@@ -1463,8 +1463,8 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1463
1463
  disabled: notification?.status === "publishing" || !activeBlock,
1464
1464
  className: "bb-btn bb-btn--primary"
1465
1465
  },
1466
- notification?.status === "publishing" ? "Publishing\xE2\u20AC\xA6" : "Publish to Payload"
1467
- ))), notification?.status === "publishing" && /* @__PURE__ */ React7.createElement("div", { className: "bb-notify bb-notify--publishing" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__spinner" }), /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__title" }, isReadOnly ? "Restoring version\xE2\u20AC\xA6" : "Publishing to Payload\xE2\u20AC\xA6"), /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__sub" }, "Validating schema and saving block definition.")))), notification?.status === "success" && /* @__PURE__ */ React7.createElement("div", { className: "bb-notify bb-notify--success" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ React7.createElement("span", { className: "bb-notify__icon" }, "\xE2\u0153\u201C"), /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__title" }, notification.msg), /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__sub" }, "The block definition and version have been saved.")), /* @__PURE__ */ React7.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, "\xE2\u0153\u2022"))), notification?.status === "error" && /* @__PURE__ */ React7.createElement("div", { className: "bb-notify bb-notify--error" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ React7.createElement("span", { className: "bb-notify__icon" }, "\xE2\u0153\u2022"), /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__title" }, notification.title), /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__sub" }, "Fix the following errors before publishing:"), /* @__PURE__ */ React7.createElement("ul", { className: "bb-notify__error-list" }, notification.errors.map((e, i) => /* @__PURE__ */ React7.createElement("li", { key: i }, e)))), /* @__PURE__ */ React7.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, "\xE2\u0153\u2022"))));
1466
+ notification?.status === "publishing" ? "Publishing..." : "Publish to Payload"
1467
+ ))), notification?.status === "publishing" && /* @__PURE__ */ React7.createElement("div", { className: "bb-notify bb-notify--publishing" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__spinner" }), /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__title" }, isReadOnly ? "Restoring version..." : "Publishing to Payload..."), /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__sub" }, "Validating schema and saving block definition.")))), notification?.status === "success" && /* @__PURE__ */ React7.createElement("div", { className: "bb-notify bb-notify--success" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ React7.createElement("span", { className: "bb-notify__icon" }, "OK"), /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__title" }, notification.msg), /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__sub" }, "The block definition and version have been saved.")), /* @__PURE__ */ React7.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, "x"))), notification?.status === "error" && /* @__PURE__ */ React7.createElement("div", { className: "bb-notify bb-notify--error" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ React7.createElement("span", { className: "bb-notify__icon" }, "!"), /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__title" }, notification.title), /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__sub" }, "Fix the following errors before publishing:"), /* @__PURE__ */ React7.createElement("ul", { className: "bb-notify__error-list" }, notification.errors.map((e, i) => /* @__PURE__ */ React7.createElement("li", { key: i }, e)))), /* @__PURE__ */ React7.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, "x"))));
1468
1468
  }
1469
1469
 
1470
1470
  // src/block-builder/components/canvas/BlockList.tsx
@@ -1501,7 +1501,7 @@ function BlockList() {
1501
1501
  className: "bb-block-action",
1502
1502
  title: "Duplicate"
1503
1503
  },
1504
- "\xE2\xA7\u2030"
1504
+ "="
1505
1505
  ),
1506
1506
  /* @__PURE__ */ React8.createElement(
1507
1507
  "button",
@@ -1511,7 +1511,7 @@ function BlockList() {
1511
1511
  className: "bb-block-action bb-block-action--danger",
1512
1512
  title: "Delete"
1513
1513
  },
1514
- "\xE2\u0153\u2022"
1514
+ "x"
1515
1515
  )
1516
1516
  )
1517
1517
  );
@@ -1540,23 +1540,23 @@ import React9 from "react";
1540
1540
  import { useSortable } from "@dnd-kit/sortable";
1541
1541
  import { CSS } from "@dnd-kit/utilities";
1542
1542
  var ICON_MAP = {
1543
- text: "\xF0\u0178\u201C\x9D",
1544
- textarea: "\xF0\u0178\u201C\u201E",
1545
- richText: "\xF0\u0178\u201C\xB0",
1546
- number: "\xF0\u0178\u201D\xA2",
1547
- checkbox: "\xE2\u02DC\u2018",
1548
- select: "\xE2\u2013\xBE",
1549
- radio: "\xE2\u2014\u2030",
1550
- date: "\xF0\u0178\u201C\u2026",
1551
- upload: "\xF0\u0178\u201C\u017D",
1552
- email: "\xE2\u0153\u2030",
1553
- code: "\xE2\u20AC\xB9\xE2\u20AC\xBA",
1554
- point: "\xE2\u2014\u017D",
1555
- relationship: "\xE2\u2021\u0152",
1556
- array: "\xE2\u2013\xA4",
1557
- group: "\xE2\u2013\xA3",
1558
- json: "{}",
1559
- ui: "\xE2\u2014\u02C6"
1543
+ text: "T",
1544
+ textarea: "Tx",
1545
+ richText: "RT",
1546
+ number: "#",
1547
+ checkbox: "[x]",
1548
+ select: "v",
1549
+ radio: "(o)",
1550
+ date: "D",
1551
+ upload: "^",
1552
+ email: "@",
1553
+ code: "<>",
1554
+ point: "P",
1555
+ relationship: "->>",
1556
+ array: "[]",
1557
+ group: "{ }",
1558
+ json: "{ }",
1559
+ ui: "UI"
1560
1560
  };
1561
1561
  function SortableFieldCard({ field, blockId, index }) {
1562
1562
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
@@ -1585,7 +1585,7 @@ function SortableFieldCard({ field, blockId, index }) {
1585
1585
  className: `bb-field-card${isActive ? " bb-field-card--active" : ""}`,
1586
1586
  onClick: () => setActiveField(isActive ? null : field.id)
1587
1587
  },
1588
- /* @__PURE__ */ React9.createElement("span", { className: "bb-field-card__icon" }, ICON_MAP[field.type] ?? "\xE2\u2014\xBB"),
1588
+ /* @__PURE__ */ React9.createElement("span", { className: "bb-field-card__icon" }, ICON_MAP[field.type] ?? "?"),
1589
1589
  /* @__PURE__ */ React9.createElement("div", { className: "bb-field-card__body" }, /* @__PURE__ */ React9.createElement("div", { className: "bb-field-card__name" }, field.name || /* @__PURE__ */ React9.createElement("span", { className: "bb-field-card__name--empty" }, "unnamed")), /* @__PURE__ */ React9.createElement("div", { className: "bb-field-card__type" }, field.type, field.required && /* @__PURE__ */ React9.createElement("span", { className: "bb-field-card__required" }, "*"))),
1590
1590
  /* @__PURE__ */ React9.createElement("span", { className: "bb-field-card__index" }, "#", index + 1),
1591
1591
  /* @__PURE__ */ React9.createElement(
@@ -1600,7 +1600,7 @@ function SortableFieldCard({ field, blockId, index }) {
1600
1600
  className: "bb-field-card__delete",
1601
1601
  title: "Remove field"
1602
1602
  },
1603
- "\xE2\u0153\u2022"
1603
+ "x"
1604
1604
  )
1605
1605
  )
1606
1606
  );
@@ -1629,7 +1629,7 @@ function BuilderCanvas() {
1629
1629
  if (!block) {
1630
1630
  return /* @__PURE__ */ React10.createElement("div", { className: "bb-canvas", style: { display: "flex", alignItems: "center", justifyContent: "center" } }, /* @__PURE__ */ React10.createElement("span", { className: "bb-canvas__no-block" }, "Select or create a block from the left panel."));
1631
1631
  }
1632
- return /* @__PURE__ */ React10.createElement("div", { className: `bb-canvas${isReadOnly ? " bb-canvas--readonly" : ""}` }, /* @__PURE__ */ React10.createElement("div", { className: "bb-canvas__inner" }, /* @__PURE__ */ React10.createElement("div", { className: "bb-canvas__header" }, block.slug, " \xE2\u20AC\u201D ", block.fields.length, " field", block.fields.length !== 1 ? "s" : ""), block.fields.length === 0 ? /* @__PURE__ */ React10.createElement("div", { className: "bb-canvas__empty" }, "Add fields from the palette on the left") : /* @__PURE__ */ React10.createElement(
1632
+ return /* @__PURE__ */ React10.createElement("div", { className: `bb-canvas${isReadOnly ? " bb-canvas--readonly" : ""}` }, /* @__PURE__ */ React10.createElement("div", { className: "bb-canvas__inner" }, /* @__PURE__ */ React10.createElement("div", { className: "bb-canvas__header" }, block.slug, " - ", block.fields.length, " field", block.fields.length !== 1 ? "s" : ""), block.fields.length === 0 ? /* @__PURE__ */ React10.createElement("div", { className: "bb-canvas__empty" }, "Add fields from the palette on the left") : /* @__PURE__ */ React10.createElement(
1633
1633
  DndContext,
1634
1634
  {
1635
1635
  sensors,
@@ -1710,7 +1710,7 @@ function BlockConfig() {
1710
1710
  type: "text",
1711
1711
  value: block.imageURL ?? "",
1712
1712
  onChange: (e) => updateBlock(block.id, { imageURL: e.target.value || void 0 }),
1713
- placeholder: "https://\xE2\u20AC\xA6",
1713
+ placeholder: "https://...",
1714
1714
  className: "bb-input"
1715
1715
  }
1716
1716
  )), /* @__PURE__ */ React11.createElement("div", { className: "bb-stat-box" }, /* @__PURE__ */ React11.createElement("strong", null, block.fields.length), " field", block.fields.length !== 1 ? "s" : "", " defined"));
@@ -1875,7 +1875,7 @@ function FieldConfig() {
1875
1875
  className: "bb-option-delete",
1876
1876
  title: "Remove option"
1877
1877
  },
1878
- "\xE2\u0153\u2022"
1878
+ "x"
1879
1879
  ))), /* @__PURE__ */ React12.createElement(
1880
1880
  "button",
1881
1881
  {
@@ -1987,7 +1987,7 @@ function FieldPalette() {
1987
1987
  type: "text",
1988
1988
  value: search,
1989
1989
  onChange: (e) => setSearch(e.target.value),
1990
- placeholder: "Search\xE2\u20AC\xA6",
1990
+ placeholder: "Search...",
1991
1991
  className: "bb-palette__search"
1992
1992
  }
1993
1993
  )), /* @__PURE__ */ React14.createElement("div", { className: "bb-sidebar__body" }, search.trim() ? /* @__PURE__ */ React14.createElement("div", { className: "bb-palette__items" }, filtered.map((item) => /* @__PURE__ */ React14.createElement(
@@ -2262,7 +2262,7 @@ function CodePreview() {
2262
2262
  gap: "0.25rem"
2263
2263
  }
2264
2264
  },
2265
- copied ? "\xE2\u0153\u201C Copied" : "\xE2\xA7\u2030 Copy"
2265
+ copied ? "Copied" : "Copy"
2266
2266
  )
2267
2267
  ), /* @__PURE__ */ React15.createElement("div", { style: { flex: 1, overflow: "auto", display: "flex" } }, /* @__PURE__ */ React15.createElement(
2268
2268
  "div",
@@ -2400,7 +2400,7 @@ function BuilderShell({ loadSlug }) {
2400
2400
  onRestoreVersion: handleRestoreVersion,
2401
2401
  onAfterPublish: handleAfterPublish
2402
2402
  }
2403
- ), loading && /* @__PURE__ */ React16.createElement("div", { className: "bb-loading-bar" }, "Loading\xE2\u20AC\xA6"), loadError && /* @__PURE__ */ React16.createElement("div", { className: "bb-error-bar" }, "Error: ", loadError), isReadOnly && !loading && /* @__PURE__ */ React16.createElement("div", { className: "bb-readonly-banner" }, /* @__PURE__ */ React16.createElement("span", { className: "bb-readonly-banner__icon" }, "\xF0\u0178\u2018\x81"), /* @__PURE__ */ React16.createElement("span", null, "You are viewing a previous version \xE2\u20AC\u201D read only.", /* @__PURE__ */ React16.createElement(
2403
+ ), loading && /* @__PURE__ */ React16.createElement("div", { className: "bb-loading-bar" }, "Loading..."), loadError && /* @__PURE__ */ React16.createElement("div", { className: "bb-error-bar" }, "Error: ", loadError), isReadOnly && !loading && /* @__PURE__ */ React16.createElement("div", { className: "bb-readonly-banner" }, /* @__PURE__ */ React16.createElement("span", { className: "bb-readonly-banner__icon" }, "[i]"), /* @__PURE__ */ React16.createElement("span", null, "You are viewing a previous version - read only.", /* @__PURE__ */ React16.createElement(
2404
2404
  "button",
2405
2405
  {
2406
2406
  type: "button",
@@ -2415,13 +2415,13 @@ function BuilderShell({ loadSlug }) {
2415
2415
  onClick: () => setShowCodePreview((p) => !p),
2416
2416
  className: `bb-footer__toggle${showCodePreview ? " bb-footer__toggle--open" : ""}`
2417
2417
  },
2418
- showCodePreview ? "\xE2\u2013\xBC" : "\xE2\u2013\xB6",
2418
+ showCodePreview ? "v" : ">",
2419
2419
  " Code Preview"
2420
2420
  ), showCodePreview && /* @__PURE__ */ React16.createElement("div", { className: "bb-footer__content" }, /* @__PURE__ */ React16.createElement(CodePreview, null))), /* @__PURE__ */ React16.createElement("nav", { className: "bb-mobile-nav", "aria-label": "Panel navigation" }, [
2421
- { id: "blocks", icon: "\xE2\xAC\xA1", label: "Blocks" },
2422
- { id: "canvas", icon: "\xE2\u2013\xA6", label: "Canvas" },
2423
- { id: "palette", icon: "\xEF\xBC\u2039", label: "Fields" },
2424
- { id: "config", icon: "\xE2\u0161\u2122", label: "Config" }
2421
+ { id: "blocks", icon: "B", label: "Blocks" },
2422
+ { id: "canvas", icon: "[]", label: "Canvas" },
2423
+ { id: "palette", icon: "+", label: "Fields" },
2424
+ { id: "config", icon: "*", label: "Config" }
2425
2425
  ].map(({ id, icon, label }) => /* @__PURE__ */ React16.createElement(
2426
2426
  "button",
2427
2427
  {
package/dist/index.cjs CHANGED
@@ -120,7 +120,7 @@ var BlockDefinitionVersions = {
120
120
  name: "label",
121
121
  type: "text",
122
122
  required: false,
123
- admin: { description: 'Optional display name, e.g. "v2 \xE2\u20AC\u201D added hero image".' }
123
+ admin: { description: 'Optional display name, e.g. "v2 - added hero image".' }
124
124
  },
125
125
  {
126
126
  name: "schema",
@@ -744,13 +744,13 @@ function validateValidationRules(v, path, errors) {
744
744
  }
745
745
  }
746
746
  if (typeof v.minLength === "number" && typeof v.maxLength === "number" && v.minLength > v.maxLength) {
747
- errors.push(`${path}: "minLength" (${v.minLength}) must be \xE2\u2030\xA4 "maxLength" (${v.maxLength}).`);
747
+ errors.push(`${path}: "minLength" (${v.minLength}) must be <= "maxLength" (${v.maxLength}).`);
748
748
  }
749
749
  if (typeof v.min === "number" && typeof v.max === "number" && v.min > v.max) {
750
- errors.push(`${path}: "min" (${v.min}) must be \xE2\u2030\xA4 "max" (${v.max}).`);
750
+ errors.push(`${path}: "min" (${v.min}) must be <= "max" (${v.max}).`);
751
751
  }
752
752
  if (typeof v.minRows === "number" && typeof v.maxRows === "number" && v.minRows > v.maxRows) {
753
- errors.push(`${path}: "minRows" (${v.minRows}) must be \xE2\u2030\xA4 "maxRows" (${v.maxRows}).`);
753
+ errors.push(`${path}: "minRows" (${v.minRows}) must be <= "maxRows" (${v.maxRows}).`);
754
754
  }
755
755
  if (v.regex !== void 0) {
756
756
  if (typeof v.regex !== "string") {
@@ -864,7 +864,7 @@ function validateField(field, path, errors, warnings) {
864
864
  errors.push(`${path}: "max" must be a number.`);
865
865
  }
866
866
  if (typeof f.min === "number" && typeof f.max === "number" && f.min > f.max) {
867
- errors.push(`${path}: "min" (${f.min}) must be \xE2\u2030\xA4 "max" (${f.max}).`);
867
+ errors.push(`${path}: "min" (${f.min}) must be <= "max" (${f.max}).`);
868
868
  }
869
869
  }
870
870
  if (type === "text" || type === "textarea") {
@@ -915,7 +915,7 @@ function validateField(field, path, errors, warnings) {
915
915
  errors.push(`${path}: "maxBlocks" must be a number.`);
916
916
  }
917
917
  if (typeof f.minBlocks === "number" && typeof f.maxBlocks === "number" && f.minBlocks > f.maxBlocks) {
918
- errors.push(`${path}: "minBlocks" (${f.minBlocks}) must be \xE2\u2030\xA4 "maxBlocks" (${f.maxBlocks}).`);
918
+ errors.push(`${path}: "minBlocks" (${f.minBlocks}) must be <= "maxBlocks" (${f.maxBlocks}).`);
919
919
  }
920
920
  }
921
921
  }
package/dist/index.js CHANGED
@@ -92,7 +92,7 @@ var BlockDefinitionVersions = {
92
92
  name: "label",
93
93
  type: "text",
94
94
  required: false,
95
- admin: { description: 'Optional display name, e.g. "v2 \xE2\u20AC\u201D added hero image".' }
95
+ admin: { description: 'Optional display name, e.g. "v2 - added hero image".' }
96
96
  },
97
97
  {
98
98
  name: "schema",
@@ -716,13 +716,13 @@ function validateValidationRules(v, path, errors) {
716
716
  }
717
717
  }
718
718
  if (typeof v.minLength === "number" && typeof v.maxLength === "number" && v.minLength > v.maxLength) {
719
- errors.push(`${path}: "minLength" (${v.minLength}) must be \xE2\u2030\xA4 "maxLength" (${v.maxLength}).`);
719
+ errors.push(`${path}: "minLength" (${v.minLength}) must be <= "maxLength" (${v.maxLength}).`);
720
720
  }
721
721
  if (typeof v.min === "number" && typeof v.max === "number" && v.min > v.max) {
722
- errors.push(`${path}: "min" (${v.min}) must be \xE2\u2030\xA4 "max" (${v.max}).`);
722
+ errors.push(`${path}: "min" (${v.min}) must be <= "max" (${v.max}).`);
723
723
  }
724
724
  if (typeof v.minRows === "number" && typeof v.maxRows === "number" && v.minRows > v.maxRows) {
725
- errors.push(`${path}: "minRows" (${v.minRows}) must be \xE2\u2030\xA4 "maxRows" (${v.maxRows}).`);
725
+ errors.push(`${path}: "minRows" (${v.minRows}) must be <= "maxRows" (${v.maxRows}).`);
726
726
  }
727
727
  if (v.regex !== void 0) {
728
728
  if (typeof v.regex !== "string") {
@@ -836,7 +836,7 @@ function validateField(field, path, errors, warnings) {
836
836
  errors.push(`${path}: "max" must be a number.`);
837
837
  }
838
838
  if (typeof f.min === "number" && typeof f.max === "number" && f.min > f.max) {
839
- errors.push(`${path}: "min" (${f.min}) must be \xE2\u2030\xA4 "max" (${f.max}).`);
839
+ errors.push(`${path}: "min" (${f.min}) must be <= "max" (${f.max}).`);
840
840
  }
841
841
  }
842
842
  if (type === "text" || type === "textarea") {
@@ -887,7 +887,7 @@ function validateField(field, path, errors, warnings) {
887
887
  errors.push(`${path}: "maxBlocks" must be a number.`);
888
888
  }
889
889
  if (typeof f.minBlocks === "number" && typeof f.maxBlocks === "number" && f.minBlocks > f.maxBlocks) {
890
- errors.push(`${path}: "minBlocks" (${f.minBlocks}) must be \xE2\u2030\xA4 "maxBlocks" (${f.maxBlocks}).`);
890
+ errors.push(`${path}: "minBlocks" (${f.minBlocks}) must be <= "maxBlocks" (${f.maxBlocks}).`);
891
891
  }
892
892
  }
893
893
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextbridgehq/payload-block-builder",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Block Builder for Payload CMS",
5
5
  "keywords": ["payload", "payload-plugin", "cms", "block-builder", "dynamic-blocks"],
6
6
  "homepage": "https://github.com/nextbridgehq/block-builder",
@@ -31,6 +31,9 @@
31
31
  "./block-data-field.css": "./src/components/BlockDataField/BlockDataField.css",
32
32
  "./schema-builder-field.css": "./src/components/SchemaBuilderField/SchemaBuilderField.css"
33
33
  },
34
+ "bin": {
35
+ "payload-block-builder": "./dist/bin/init.js"
36
+ },
34
37
  "files": [
35
38
  "dist",
36
39
  "src/**/*.css"