@nextsparkjs/core 0.1.0-beta.157 → 0.1.0-beta.159

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.
Files changed (33) hide show
  1. package/dist/components/dashboard/block-editor/batch-action-bar.d.ts +12 -0
  2. package/dist/components/dashboard/block-editor/batch-action-bar.d.ts.map +1 -0
  3. package/dist/components/dashboard/block-editor/batch-action-bar.js +99 -0
  4. package/dist/components/dashboard/block-editor/block-picker.d.ts +8 -3
  5. package/dist/components/dashboard/block-editor/block-picker.d.ts.map +1 -1
  6. package/dist/components/dashboard/block-editor/block-picker.js +5 -3
  7. package/dist/components/dashboard/block-editor/block-preview-canvas.d.ts +7 -3
  8. package/dist/components/dashboard/block-editor/block-preview-canvas.d.ts.map +1 -1
  9. package/dist/components/dashboard/block-editor/block-preview-canvas.js +17 -8
  10. package/dist/components/dashboard/block-editor/block-settings-panel.d.ts +2 -1
  11. package/dist/components/dashboard/block-editor/block-settings-panel.d.ts.map +1 -1
  12. package/dist/components/dashboard/block-editor/block-settings-panel.js +10 -1
  13. package/dist/components/dashboard/block-editor/builder-editor-view.d.ts.map +1 -1
  14. package/dist/components/dashboard/block-editor/builder-editor-view.js +190 -26
  15. package/dist/components/dashboard/block-editor/tree-view-node.d.ts +7 -2
  16. package/dist/components/dashboard/block-editor/tree-view-node.d.ts.map +1 -1
  17. package/dist/components/dashboard/block-editor/tree-view-node.js +16 -3
  18. package/dist/components/dashboard/block-editor/tree-view.d.ts +7 -2
  19. package/dist/components/dashboard/block-editor/tree-view.d.ts.map +1 -1
  20. package/dist/components/dashboard/block-editor/tree-view.js +7 -4
  21. package/dist/lib/blocks/clipboard.d.ts +8 -1
  22. package/dist/lib/blocks/clipboard.d.ts.map +1 -1
  23. package/dist/lib/blocks/clipboard.js +30 -8
  24. package/dist/messages/en/admin.json +20 -1
  25. package/dist/messages/en/index.d.ts +19 -0
  26. package/dist/messages/en/index.d.ts.map +1 -1
  27. package/dist/messages/es/admin.json +20 -1
  28. package/dist/messages/es/index.d.ts +19 -0
  29. package/dist/messages/es/index.d.ts.map +1 -1
  30. package/dist/styles/classes.json +3 -2
  31. package/dist/styles/ui.css +1 -1
  32. package/package.json +3 -2
  33. package/scripts/build/registry/post-build/page-generator.mjs +52 -4
@@ -0,0 +1,12 @@
1
+ interface BatchActionBarProps {
2
+ selectedCount: number;
3
+ onCopy: () => void;
4
+ onDuplicate: () => void;
5
+ onDelete: () => void;
6
+ onClearSelection: () => void;
7
+ clipboardCount: number;
8
+ onPaste: () => void;
9
+ }
10
+ export declare function BatchActionBar({ selectedCount, onCopy, onDuplicate, onDelete, onClearSelection, clipboardCount, onPaste, }: BatchActionBarProps): import("react/jsx-runtime").JSX.Element;
11
+ export {};
12
+ //# sourceMappingURL=batch-action-bar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-action-bar.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/batch-action-bar.tsx"],"names":[],"mappings":"AAQA,UAAU,mBAAmB;IAC3B,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,gBAAgB,EAAE,MAAM,IAAI,CAAA;IAC5B,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,wBAAgB,cAAc,CAAC,EAC7B,aAAa,EACb,MAAM,EACN,WAAW,EACX,QAAQ,EACR,gBAAgB,EAChB,cAAc,EACd,OAAO,GACR,EAAE,mBAAmB,2CAgFrB"}
@@ -0,0 +1,99 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Copy, CopyPlus, Trash2, ClipboardPaste, X } from "lucide-react";
4
+ import { useTranslations } from "next-intl";
5
+ import { Button } from "../../ui/button.js";
6
+ import { cn } from "../../../lib/utils/index.js";
7
+ import { sel } from "../../../lib/test/index.js";
8
+ function BatchActionBar({
9
+ selectedCount,
10
+ onCopy,
11
+ onDuplicate,
12
+ onDelete,
13
+ onClearSelection,
14
+ clipboardCount,
15
+ onPaste
16
+ }) {
17
+ const t = useTranslations("admin.builder.multiSelect");
18
+ return /* @__PURE__ */ jsxs(
19
+ "div",
20
+ {
21
+ className: cn(
22
+ "absolute bottom-4 left-1/2 -translate-x-1/2 z-30",
23
+ "bg-primary text-primary-foreground rounded-full",
24
+ "px-4 py-2 shadow-lg",
25
+ "flex items-center gap-3",
26
+ "animate-in slide-in-from-bottom-4 fade-in duration-200"
27
+ ),
28
+ "data-cy": sel("blockEditor.batchActionBar.container"),
29
+ children: [
30
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium whitespace-nowrap", "data-cy": sel("blockEditor.batchActionBar.count"), children: t("selected", { count: selectedCount }) }),
31
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-primary-foreground/30" }),
32
+ /* @__PURE__ */ jsx(
33
+ Button,
34
+ {
35
+ variant: "ghost",
36
+ size: "icon",
37
+ className: "h-7 w-7 hover:bg-primary-foreground/20 text-primary-foreground",
38
+ onClick: onCopy,
39
+ title: t("copy"),
40
+ "data-cy": sel("blockEditor.batchActionBar.copy"),
41
+ children: /* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5" })
42
+ }
43
+ ),
44
+ clipboardCount > 0 && /* @__PURE__ */ jsx(
45
+ Button,
46
+ {
47
+ variant: "ghost",
48
+ size: "icon",
49
+ className: "h-7 w-7 hover:bg-primary-foreground/20 text-primary-foreground",
50
+ onClick: onPaste,
51
+ title: t("paste"),
52
+ "data-cy": sel("blockEditor.batchActionBar.paste"),
53
+ children: /* @__PURE__ */ jsx(ClipboardPaste, { className: "h-3.5 w-3.5" })
54
+ }
55
+ ),
56
+ /* @__PURE__ */ jsx(
57
+ Button,
58
+ {
59
+ variant: "ghost",
60
+ size: "icon",
61
+ className: "h-7 w-7 hover:bg-primary-foreground/20 text-primary-foreground",
62
+ onClick: onDuplicate,
63
+ title: t("duplicate"),
64
+ "data-cy": sel("blockEditor.batchActionBar.duplicate"),
65
+ children: /* @__PURE__ */ jsx(CopyPlus, { className: "h-3.5 w-3.5" })
66
+ }
67
+ ),
68
+ /* @__PURE__ */ jsx(
69
+ Button,
70
+ {
71
+ variant: "ghost",
72
+ size: "icon",
73
+ className: "h-7 w-7 hover:bg-destructive/80 text-primary-foreground",
74
+ onClick: onDelete,
75
+ title: t("delete"),
76
+ "data-cy": sel("blockEditor.batchActionBar.delete"),
77
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
78
+ }
79
+ ),
80
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-primary-foreground/30" }),
81
+ /* @__PURE__ */ jsx(
82
+ Button,
83
+ {
84
+ variant: "ghost",
85
+ size: "icon",
86
+ className: "h-7 w-7 hover:bg-primary-foreground/20 text-primary-foreground",
87
+ onClick: onClearSelection,
88
+ title: t("deselectAll"),
89
+ "data-cy": sel("blockEditor.batchActionBar.deselect"),
90
+ children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
91
+ }
92
+ )
93
+ ]
94
+ }
95
+ );
96
+ }
97
+ export {
98
+ BatchActionBar
99
+ };
@@ -12,14 +12,19 @@ interface BlockPickerProps {
12
12
  showPatternsTab?: boolean;
13
13
  pageBlocks: (BlockInstance | PatternReference)[];
14
14
  selectedBlockId: string | null;
15
- onSelectBlock: (id: string) => void;
15
+ selectedBlockIds?: Set<string>;
16
+ onSelectBlock: (id: string, event?: {
17
+ metaKey?: boolean;
18
+ shiftKey?: boolean;
19
+ ctrlKey?: boolean;
20
+ }) => void;
16
21
  onReorderBlocks: (blocks: (BlockInstance | PatternReference)[]) => void;
17
22
  onCopyBlock?: (id: string) => void;
18
23
  onDuplicateBlock?: (id: string) => void;
19
24
  onRemoveBlock?: (id: string) => void;
20
25
  onPasteBlock?: () => void;
21
- hasClipboardBlock?: boolean;
26
+ clipboardCount?: number;
22
27
  }
23
- export declare function BlockPicker({ blocks, onAddBlock, onAddPattern, entityConfig, entityFields, onEntityFieldChange, showFieldsTab, showPatternsTab, pageBlocks, selectedBlockId, onSelectBlock, onReorderBlocks, onCopyBlock, onDuplicateBlock, onRemoveBlock, onPasteBlock, hasClipboardBlock, }: BlockPickerProps): import("react/jsx-runtime").JSX.Element;
28
+ export declare function BlockPicker({ blocks, onAddBlock, onAddPattern, entityConfig, entityFields, onEntityFieldChange, showFieldsTab, showPatternsTab, pageBlocks, selectedBlockId, selectedBlockIds, onSelectBlock, onReorderBlocks, onCopyBlock, onDuplicateBlock, onRemoveBlock, onPasteBlock, clipboardCount, }: BlockPickerProps): import("react/jsx-runtime").JSX.Element;
24
29
  export {};
25
30
  //# sourceMappingURL=block-picker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"block-picker.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/block-picker.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AAuBxF,UAAU,gBAAgB;IACxB,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,YAAY,EAAE,kBAAkB,CAAA;IAChC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACrC,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAC5D,aAAa,EAAE,OAAO,CAAA;IACtB,eAAe,CAAC,EAAE,OAAO,CAAA;IAEzB,UAAU,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,CAAA;IAChD,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,eAAe,EAAE,CAAC,MAAM,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,KAAK,IAAI,CAAA;IACvE,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,eAAuB,EAEvB,UAAU,EACV,eAAe,EACf,aAAa,EACb,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,iBAAiB,GAClB,EAAE,gBAAgB,2CA8UlB"}
1
+ {"version":3,"file":"block-picker.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/block-picker.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AAuBxF,UAAU,gBAAgB;IACxB,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,YAAY,EAAE,kBAAkB,CAAA;IAChC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACrC,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAC5D,aAAa,EAAE,OAAO,CAAA;IACtB,eAAe,CAAC,EAAE,OAAO,CAAA;IAEzB,UAAU,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,CAAA;IAChD,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC9B,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAA;IACzG,eAAe,EAAE,CAAC,MAAM,EAAE,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,KAAK,IAAI,CAAA;IACvE,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,eAAuB,EAEvB,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,cAAkB,GACnB,EAAE,gBAAgB,2CAkVlB"}
@@ -37,13 +37,14 @@ function BlockPicker({
37
37
  // TreeView props
38
38
  pageBlocks,
39
39
  selectedBlockId,
40
+ selectedBlockIds,
40
41
  onSelectBlock,
41
42
  onReorderBlocks,
42
43
  onCopyBlock,
43
44
  onDuplicateBlock,
44
45
  onRemoveBlock,
45
46
  onPasteBlock,
46
- hasClipboardBlock
47
+ clipboardCount = 0
47
48
  }) {
48
49
  const t = useTranslations("admin.builder");
49
50
  const tPatterns = useTranslations("patterns");
@@ -325,7 +326,7 @@ function BlockPicker({
325
326
  ) : (
326
327
  // Layout Tab - Tree View
327
328
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
328
- hasClipboardBlock && onPasteBlock && /* @__PURE__ */ jsx("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ jsxs(
329
+ clipboardCount > 0 && onPasteBlock && /* @__PURE__ */ jsx("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ jsxs(
329
330
  "button",
330
331
  {
331
332
  className: "w-full flex items-center justify-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-primary/10 text-primary hover:bg-primary/20 transition-colors cursor-pointer",
@@ -333,7 +334,7 @@ function BlockPicker({
333
334
  "data-cy": sel("blockEditor.blockPicker.pasteBlock"),
334
335
  children: [
335
336
  /* @__PURE__ */ jsx(ClipboardPaste, { className: "h-4 w-4" }),
336
- t("layout.pasteBlock")
337
+ clipboardCount > 1 ? t("layout.pasteBlocks", { count: clipboardCount }) : t("layout.pasteBlock")
337
338
  ]
338
339
  }
339
340
  ) }),
@@ -342,6 +343,7 @@ function BlockPicker({
342
343
  {
343
344
  blocks: pageBlocks,
344
345
  selectedBlockId,
346
+ selectedBlockIds,
345
347
  onSelectBlock,
346
348
  onReorder: onReorderBlocks,
347
349
  onCopy: onCopyBlock,
@@ -1,14 +1,18 @@
1
1
  import type { BlockInstance } from '../../../types/blocks';
2
2
  interface BlockPreviewCanvasProps {
3
3
  blocks: BlockInstance[];
4
- selectedBlockId: string | null;
5
- onSelectBlock: (id: string) => void;
4
+ selectedBlockIds: Set<string>;
5
+ onSelectBlock: (id: string, event?: {
6
+ metaKey?: boolean;
7
+ shiftKey?: boolean;
8
+ ctrlKey?: boolean;
9
+ }) => void;
6
10
  onMoveUp?: (id: string) => void;
7
11
  onMoveDown?: (id: string) => void;
8
12
  onCopy?: (id: string) => void;
9
13
  onDuplicate?: (id: string) => void;
10
14
  onRemove?: (id: string) => void;
11
15
  }
12
- export declare function BlockPreviewCanvas({ blocks, selectedBlockId, onSelectBlock, onMoveUp, onMoveDown, onCopy, onDuplicate, onRemove, }: BlockPreviewCanvasProps): import("react/jsx-runtime").JSX.Element;
16
+ export declare function BlockPreviewCanvas({ blocks, selectedBlockIds, onSelectBlock, onMoveUp, onMoveDown, onCopy, onDuplicate, onRemove, }: BlockPreviewCanvasProps): import("react/jsx-runtime").JSX.Element;
13
17
  export {};
14
18
  //# sourceMappingURL=block-preview-canvas.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"block-preview-canvas.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/block-preview-canvas.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAkB1D,UAAU,uBAAuB;IAC/B,MAAM,EAAE,aAAa,EAAE,CAAA;IACvB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7B,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AAED,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,eAAe,EACf,aAAa,EACb,QAAQ,EACR,UAAU,EACV,MAAM,EACN,WAAW,EACX,QAAQ,GACT,EAAE,uBAAuB,2CA6CzB"}
1
+ {"version":3,"file":"block-preview-canvas.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/block-preview-canvas.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAkB1D,UAAU,uBAAuB;IAC/B,MAAM,EAAE,aAAa,EAAE,CAAA;IACvB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC7B,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAA;IACzG,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7B,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AAED,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,gBAAgB,EAChB,aAAa,EACb,QAAQ,EACR,UAAU,EACV,MAAM,EACN,WAAW,EACX,QAAQ,GACT,EAAE,uBAAuB,2CA+CzB"}
@@ -19,7 +19,7 @@ function BlockSkeleton() {
19
19
  }
20
20
  function BlockPreviewCanvas({
21
21
  blocks,
22
- selectedBlockId,
22
+ selectedBlockIds,
23
23
  onSelectBlock,
24
24
  onMoveUp,
25
25
  onMoveDown,
@@ -29,6 +29,7 @@ function BlockPreviewCanvas({
29
29
  }) {
30
30
  const t = useTranslations("admin.builder");
31
31
  const [hoveredBlockId, setHoveredBlockId] = useState(null);
32
+ const isMultiSelect = selectedBlockIds.size > 1;
32
33
  const handleHover = useCallback((id) => setHoveredBlockId(id), []);
33
34
  const handleLeave = useCallback(() => setHoveredBlockId(null), []);
34
35
  if (blocks.length === 0) {
@@ -48,7 +49,8 @@ function BlockPreviewCanvas({
48
49
  SelectableBlockPreview,
49
50
  {
50
51
  block,
51
- isSelected: selectedBlockId === block.id,
52
+ isSelected: selectedBlockIds.has(block.id),
53
+ isMultiSelect,
52
54
  isHovered: hoveredBlockId === block.id,
53
55
  onSelect: onSelectBlock,
54
56
  blockId: block.id,
@@ -69,6 +71,7 @@ const SelectableBlockPreview = memo(function SelectableBlockPreview2({
69
71
  block,
70
72
  blockId,
71
73
  isSelected,
74
+ isMultiSelect,
72
75
  isHovered,
73
76
  onSelect,
74
77
  onHover,
@@ -82,7 +85,9 @@ const SelectableBlockPreview = memo(function SelectableBlockPreview2({
82
85
  onRemove
83
86
  }) {
84
87
  const t = useTranslations("admin.builder");
85
- const handleSelect = useCallback(() => onSelect(blockId), [onSelect, blockId]);
88
+ const handleSelect = useCallback((e) => {
89
+ onSelect(blockId, { metaKey: e.metaKey, shiftKey: e.shiftKey, ctrlKey: e.ctrlKey });
90
+ }, [onSelect, blockId]);
86
91
  const handleHover = useCallback(() => onHover(blockId), [onHover, blockId]);
87
92
  const handleMoveUp = useCallback((e) => {
88
93
  e.stopPropagation();
@@ -138,7 +143,7 @@ const SelectableBlockPreview = memo(function SelectableBlockPreview2({
138
143
  {
139
144
  patternRef: block,
140
145
  isSelected,
141
- onSelect: handleSelect,
146
+ onSelect: () => onSelect(blockId),
142
147
  onRemove: handleRemove
143
148
  }
144
149
  )
@@ -172,14 +177,15 @@ const SelectableBlockPreview = memo(function SelectableBlockPreview2({
172
177
  "relative cursor-pointer transition-[border-color] duration-150 group @container",
173
178
  "border-2 border-transparent",
174
179
  "hover:border-primary/50",
175
- isSelected && "border-primary"
180
+ isSelected && !isMultiSelect && "border-primary",
181
+ isSelected && isMultiSelect && "border-primary/70 bg-primary/5"
176
182
  ),
177
183
  onClick: handleSelect,
178
184
  onMouseEnter: handleHover,
179
185
  onMouseLeave: onLeave,
180
186
  "data-cy": sel("blockEditor.previewCanvas.block", { id: block.id }),
181
187
  children: [
182
- onDuplicate && onRemove && /* @__PURE__ */ jsx(
188
+ onDuplicate && onRemove && !isMultiSelect && /* @__PURE__ */ jsx(
183
189
  FloatingBlockToolbar,
184
190
  {
185
191
  blockId: block.id,
@@ -193,9 +199,12 @@ const SelectableBlockPreview = memo(function SelectableBlockPreview2({
193
199
  isSelected && /* @__PURE__ */ jsx(
194
200
  "div",
195
201
  {
196
- className: "absolute top-2 right-2 z-20 bg-primary text-primary-foreground text-xs px-2 py-1 rounded shadow-md",
202
+ className: cn(
203
+ "absolute top-2 right-2 z-20 text-xs px-2 py-1 rounded shadow-md",
204
+ isMultiSelect ? "bg-primary/80 text-primary-foreground" : "bg-primary text-primary-foreground"
205
+ ),
197
206
  "data-cy": sel("blockEditor.previewCanvas.editingBadge", { id: block.id }),
198
- children: t("canvas.editingBadge")
207
+ children: isMultiSelect ? "\u2713" : t("canvas.editingBadge")
199
208
  }
200
209
  ),
201
210
  (onMoveUp || onMoveDown) && /* @__PURE__ */ jsxs("div", { className: cn(
@@ -2,10 +2,11 @@ import type { BlockInstance } from '../../../types/blocks';
2
2
  import type { PatternReference } from '../../../types/pattern-reference';
3
3
  interface BlockSettingsPanelProps {
4
4
  block: BlockInstance | PatternReference | undefined;
5
+ selectedCount?: number;
5
6
  onUpdateProps: (props: Record<string, unknown>) => void;
6
7
  onRemove: () => void;
7
8
  onClose?: () => void;
8
9
  }
9
- export declare function BlockSettingsPanel({ block, onUpdateProps, onRemove, onClose, }: BlockSettingsPanelProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function BlockSettingsPanel({ block, selectedCount, onUpdateProps, onRemove, onClose, }: BlockSettingsPanelProps): import("react/jsx-runtime").JSX.Element;
10
11
  export {};
11
12
  //# sourceMappingURL=block-settings-panel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"block-settings-panel.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/block-settings-panel.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAA6B,MAAM,uBAAuB,CAAA;AACrF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AAIxE,UAAU,uBAAuB;IAC/B,KAAK,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS,CAAA;IACnD,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IACvD,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAsBD,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,aAAa,EACb,QAAQ,EACR,OAAO,GACR,EAAE,uBAAuB,2CA8QzB"}
1
+ {"version":3,"file":"block-settings-panel.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/block-settings-panel.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAA6B,MAAM,uBAAuB,CAAA;AACrF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AAIxE,UAAU,uBAAuB;IAC/B,KAAK,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS,CAAA;IACnD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IACvD,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAsBD,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,aAAiB,EACjB,aAAa,EACb,QAAQ,EACR,OAAO,GACR,EAAE,uBAAuB,2CA6RzB"}
@@ -4,7 +4,7 @@ import { useMemo, useState } from "react";
4
4
  import { useTranslations } from "next-intl";
5
5
  import { Button } from "../../ui/button.js";
6
6
  import { Card, CardContent } from "../../ui/card.js";
7
- import { Trash2, FileText, Palette, Settings2, X, SlidersHorizontal, Layers, Lock } from "lucide-react";
7
+ import { Trash2, FileText, Palette, Settings2, X, SlidersHorizontal, Layers, Lock, CheckSquare } from "lucide-react";
8
8
  import Link from "next/link";
9
9
  import { cn } from "../../../lib/utils/index.js";
10
10
  import { sel } from "../../../lib/test/index.js";
@@ -25,11 +25,13 @@ function groupFieldsByTab(fields) {
25
25
  }
26
26
  function BlockSettingsPanel({
27
27
  block,
28
+ selectedCount = 0,
28
29
  onUpdateProps,
29
30
  onRemove,
30
31
  onClose
31
32
  }) {
32
33
  const t = useTranslations("admin.builder.settingsPanel");
34
+ const tMulti = useTranslations("admin.builder.multiSelect");
33
35
  const [activeTab, setActiveTab] = useState("content");
34
36
  const groupedFields = useMemo(() => {
35
37
  if (!block || isPatternReference(block)) return null;
@@ -37,6 +39,13 @@ function BlockSettingsPanel({
37
39
  if (!(blockConfig2 == null ? void 0 : blockConfig2.fieldDefinitions)) return null;
38
40
  return groupFieldsByTab(blockConfig2.fieldDefinitions);
39
41
  }, [block]);
42
+ if (selectedCount > 1) {
43
+ return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center p-8 bg-muted/10", "data-cy": sel("blockEditor.blockPropertiesPanel.multiSelect"), children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
44
+ /* @__PURE__ */ jsx("div", { className: "mx-auto mb-4 h-12 w-12 rounded-full bg-primary/10 flex items-center justify-center", children: /* @__PURE__ */ jsx(CheckSquare, { className: "h-6 w-6 text-primary" }) }),
45
+ /* @__PURE__ */ jsx("p", { className: "text-foreground font-medium", children: tMulti("selected", { count: selectedCount }) }),
46
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: tMulti("settingsHint") })
47
+ ] }) });
48
+ }
40
49
  if (!block) {
41
50
  return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center p-8 bg-muted/10", "data-cy": sel("blockEditor.blockPropertiesPanel.empty"), children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
42
51
  /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: t("empty.message") }),
@@ -1 +1 @@
1
- {"version":3,"file":"builder-editor-view.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/builder-editor-view.tsx"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AAwCxF,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,kBAAkB,CAAA;IAChC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAA;IACvB,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC9D;AAED,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,EAAE,sBAAsB,2CAiuB7I"}
1
+ {"version":3,"file":"builder-editor-view.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/builder-editor-view.tsx"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AAwCxF,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,kBAAkB,CAAA;IAChC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAA;IACvB,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC9D;AAED,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,EAAE,sBAAsB,2CA85B7I"}