@drawnagency/primitives 0.1.61 → 0.1.63

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 (78) hide show
  1. package/dist/{chunk-UQ4OYRW7.js → chunk-2BHPWO7M.js} +54 -166
  2. package/dist/chunk-4E66N6UV.js +10 -0
  3. package/dist/chunk-5THS4K5D.js +123 -0
  4. package/dist/{chunk-TG43X7JO.js → chunk-75P6HWPN.js} +29 -5
  5. package/dist/{chunk-ODCJQOVO.js → chunk-7IMQVDDJ.js} +1 -1
  6. package/dist/{chunk-4OX3Z7SB.js → chunk-FECCYOPJ.js} +32 -671
  7. package/dist/{chunk-WLMJCNU7.js → chunk-I5737FJY.js} +0 -8
  8. package/dist/chunk-QYQ3DQHI.js +1201 -0
  9. package/dist/{chunk-BT7STGDW.js → chunk-TEYTLQVH.js} +0 -15
  10. package/dist/chunk-VMDKWUMT.js +652 -0
  11. package/dist/{chunk-AM5LZD6Q.js → chunk-ZYXLNJ5M.js} +6 -5
  12. package/dist/components/brandguide/ColorSwatchSettings.d.ts +1 -1
  13. package/dist/components/brandguide/ColorSwatchSettings.d.ts.map +1 -1
  14. package/dist/components/brandguide/Colors.d.ts +1 -1
  15. package/dist/components/brandguide/Colors.d.ts.map +1 -1
  16. package/dist/components/editor/index.js +4 -2
  17. package/dist/components/primitives/IconPicker.d.ts +1 -7
  18. package/dist/components/primitives/IconPicker.d.ts.map +1 -1
  19. package/dist/components/primitives/index.js +10 -7
  20. package/dist/components/sections/Colors/index.d.ts.map +1 -1
  21. package/dist/components/sections/Colors/schema.d.ts +19 -0
  22. package/dist/components/sections/Colors/schema.d.ts.map +1 -0
  23. package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts +20 -0
  24. package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts.map +1 -0
  25. package/dist/components/sections/DoDontMedia/index.d.ts +45 -0
  26. package/dist/components/sections/DoDontMedia/index.d.ts.map +1 -0
  27. package/dist/components/sections/IconList/DoDontToggle.d.ts +14 -0
  28. package/dist/components/sections/IconList/DoDontToggle.d.ts.map +1 -0
  29. package/dist/components/sections/IconList/IconList.d.ts.map +1 -1
  30. package/dist/components/sections/IconList/index.d.ts.map +1 -1
  31. package/dist/components/sections/Media/MediaBlock.d.ts +1 -3
  32. package/dist/components/sections/Media/MediaBlock.d.ts.map +1 -1
  33. package/dist/components/sections/Media/index.d.ts +0 -1
  34. package/dist/components/sections/Media/index.d.ts.map +1 -1
  35. package/dist/components/sections/all-sections.d.ts +54 -18
  36. package/dist/components/sections/all-sections.d.ts.map +1 -1
  37. package/dist/components/sections/brand-guide.d.ts +84 -0
  38. package/dist/components/sections/brand-guide.d.ts.map +1 -0
  39. package/dist/components/sections/brand-guide.js +21 -0
  40. package/dist/components/sections/core-sections.d.ts +93 -0
  41. package/dist/components/sections/core-sections.d.ts.map +1 -0
  42. package/dist/components/sections/register-schemas.js +108 -1155
  43. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  44. package/dist/components/shell/view-branch.d.ts +12 -0
  45. package/dist/components/shell/view-branch.d.ts.map +1 -0
  46. package/dist/index.js +29 -33
  47. package/dist/lib/index.js +4 -4
  48. package/dist/lib/loader.d.ts.map +1 -1
  49. package/dist/lib/migrate-sections-transform.d.ts.map +1 -1
  50. package/dist/lib/migrate-sections-transform.js +1 -1
  51. package/dist/lib/registry.d.ts +6 -1
  52. package/dist/lib/registry.d.ts.map +1 -1
  53. package/dist/media/index.js +1 -1
  54. package/dist/schemas/index.js +3 -7
  55. package/dist/schemas/shared.d.ts +0 -17
  56. package/dist/schemas/shared.d.ts.map +1 -1
  57. package/package.json +5 -1
  58. package/src/components/brandguide/ColorSwatchSettings.tsx +1 -1
  59. package/src/components/brandguide/Colors.tsx +1 -1
  60. package/src/components/primitives/IconPicker.tsx +27 -119
  61. package/src/components/sections/Colors/index.tsx +2 -1
  62. package/src/components/sections/Colors/schema.ts +24 -0
  63. package/src/components/sections/DoDontMedia/DoDontMediaBlock.tsx +35 -0
  64. package/src/components/sections/DoDontMedia/index.tsx +84 -0
  65. package/src/components/sections/IconList/DoDontToggle.tsx +76 -0
  66. package/src/components/sections/IconList/IconList.tsx +24 -14
  67. package/src/components/sections/IconList/index.tsx +1 -0
  68. package/src/components/sections/Media/MediaBlock.tsx +10 -11
  69. package/src/components/sections/Media/index.tsx +0 -15
  70. package/src/components/sections/all-sections.ts +7 -35
  71. package/src/components/sections/brand-guide.ts +13 -0
  72. package/src/components/sections/core-sections.ts +26 -0
  73. package/src/components/shell/EditorShell.tsx +7 -5
  74. package/src/components/shell/view-branch.ts +14 -0
  75. package/src/lib/loader.ts +10 -4
  76. package/src/lib/migrate-sections-transform.ts +33 -5
  77. package/src/lib/registry.ts +6 -1
  78. package/src/schemas/shared.ts +0 -18
@@ -1,14 +1,9 @@
1
1
  import {
2
- AddIcon,
3
- DeleteIcon,
4
- DragHandle,
5
- IconButton,
6
- SettingsIcon,
7
- usePages
8
- } from "./chunk-WLMJCNU7.js";
2
+ EditablePlainText
3
+ } from "./chunk-VMDKWUMT.js";
9
4
  import {
10
- getMediaProvider
11
- } from "./chunk-CBWK3KPV.js";
5
+ usePages
6
+ } from "./chunk-4E66N6UV.js";
12
7
  import {
13
8
  sanitizeHtml,
14
9
  toSectionId
@@ -20,119 +15,6 @@ import {
20
15
  defineSection
21
16
  } from "./chunk-VKAGMEKE.js";
22
17
 
23
- // src/components/primitives/EditablePlainText.tsx
24
- import {
25
- useRef as useRef2,
26
- useEffect as useEffect2,
27
- useCallback as useCallback2,
28
- createElement
29
- } from "react";
30
-
31
- // src/components/primitives/useEditablePlainText.ts
32
- import { useState, useEffect, useRef, useCallback } from "react";
33
- function useEditablePlainText({
34
- value: propValue,
35
- onChange,
36
- multiline = false
37
- }) {
38
- const [value, setValue] = useState(propValue);
39
- const lastPropValue = useRef(propValue);
40
- useEffect(() => {
41
- if (propValue !== lastPropValue.current) {
42
- setValue(propValue);
43
- lastPropValue.current = propValue;
44
- }
45
- }, [propValue]);
46
- const handleInput = useCallback((text) => {
47
- setValue(text);
48
- }, []);
49
- const handleBlur = useCallback(() => {
50
- if (value !== propValue) {
51
- onChange(value);
52
- lastPropValue.current = value;
53
- }
54
- }, [value, propValue, onChange]);
55
- return {
56
- value,
57
- handleInput,
58
- handleBlur,
59
- shouldPreventEnter: !multiline
60
- };
61
- }
62
-
63
- // src/components/primitives/EditablePlainText.tsx
64
- function EditablePlainText({
65
- tag,
66
- value,
67
- onChange,
68
- isEditMode,
69
- multiline = false,
70
- placeholder,
71
- className,
72
- ...htmlAttrs
73
- }) {
74
- const ref = useRef2(null);
75
- const {
76
- value: localValue,
77
- handleInput,
78
- handleBlur,
79
- shouldPreventEnter
80
- } = useEditablePlainText({ value, onChange, multiline });
81
- useEffect2(() => {
82
- if (ref.current && ref.current.textContent !== localValue) {
83
- ref.current.textContent = localValue;
84
- }
85
- }, [localValue]);
86
- const onInput = useCallback2(() => {
87
- if (ref.current) {
88
- handleInput(ref.current.textContent || "");
89
- }
90
- }, [handleInput]);
91
- const onKeyDown = useCallback2(
92
- (e) => {
93
- if (e.key === "Enter" && shouldPreventEnter) {
94
- e.preventDefault();
95
- }
96
- },
97
- [shouldPreventEnter]
98
- );
99
- const onPaste = useCallback2(
100
- (e) => {
101
- e.preventDefault();
102
- const text = e.clipboardData.getData("text/plain");
103
- const selection = window.getSelection();
104
- if (selection && selection.rangeCount > 0) {
105
- const range = selection.getRangeAt(0);
106
- range.deleteContents();
107
- range.insertNode(document.createTextNode(text));
108
- range.collapse(false);
109
- selection.removeAllRanges();
110
- selection.addRange(range);
111
- }
112
- if (ref.current) {
113
- handleInput(ref.current.textContent || "");
114
- }
115
- },
116
- [handleInput]
117
- );
118
- return createElement(
119
- tag,
120
- {
121
- ref,
122
- className: isEditMode && placeholder ? `editable-placeholder ${className ?? ""}` : className,
123
- contentEditable: isEditMode ? "true" : void 0,
124
- suppressContentEditableWarning: isEditMode || void 0,
125
- onInput: isEditMode ? onInput : void 0,
126
- onBlur: isEditMode ? handleBlur : void 0,
127
- onKeyDown: isEditMode ? onKeyDown : void 0,
128
- onPaste: isEditMode ? onPaste : void 0,
129
- "data-placeholder": isEditMode && placeholder ? placeholder : void 0,
130
- ...htmlAttrs
131
- },
132
- value
133
- );
134
- }
135
-
136
18
  // src/components/primitives/defineHeadingSection.tsx
137
19
  import { z } from "zod";
138
20
 
@@ -185,7 +67,7 @@ function defineHeadingSection(config) {
185
67
  }
186
68
 
187
69
  // src/components/primitives/LinkPopover.tsx
188
- import { useState as useState2 } from "react";
70
+ import { useState } from "react";
189
71
 
190
72
  // src/components/shared/Button.tsx
191
73
  import { forwardRef } from "react";
@@ -258,11 +140,11 @@ function LinkPopover({ editor, onClose }) {
258
140
  const { pages, getPageHeadings } = usePages();
259
141
  const existingAttrs = editor.getAttributes("link");
260
142
  const existingInternal = parseInternalHref(existingAttrs.href ?? "");
261
- const [mode, setMode] = useState2(existingInternal ? "internal" : "external");
262
- const [url, setUrl] = useState2(existingInternal ? "" : existingAttrs.href ?? "");
263
- const [pageId, setPageId] = useState2(existingInternal?.pageId ?? "");
264
- const [anchorId, setAnchorId] = useState2(existingInternal?.anchorSectionId ?? "");
265
- const [openInNewTab, setOpenInNewTab] = useState2(
143
+ const [mode, setMode] = useState(existingInternal ? "internal" : "external");
144
+ const [url, setUrl] = useState(existingInternal ? "" : existingAttrs.href ?? "");
145
+ const [pageId, setPageId] = useState(existingInternal?.pageId ?? "");
146
+ const [anchorId, setAnchorId] = useState(existingInternal?.anchorSectionId ?? "");
147
+ const [openInNewTab, setOpenInNewTab] = useState(
266
148
  existingAttrs.target === "_blank"
267
149
  );
268
150
  const hasLink = Boolean(existingAttrs.href);
@@ -413,12 +295,12 @@ function LinkPopover({ editor, onClose }) {
413
295
  }
414
296
 
415
297
  // src/components/primitives/EditableRichText.tsx
416
- import { useRef as useRef4, useCallback as useCallback4, useEffect as useEffect4 } from "react";
298
+ import { useRef as useRef2, useCallback as useCallback2, useEffect as useEffect2 } from "react";
417
299
  import { EditorContent } from "@tiptap/react";
418
300
  import { BubbleMenu } from "@tiptap/react/menus";
419
301
 
420
302
  // src/components/primitives/useEditableRichText.ts
421
- import { useState as useState3, useRef as useRef3, useCallback as useCallback3, useEffect as useEffect3 } from "react";
303
+ import { useState as useState2, useRef, useCallback, useEffect } from "react";
422
304
  import { Editor } from "@tiptap/core";
423
305
  import Placeholder from "@tiptap/extension-placeholder";
424
306
 
@@ -553,17 +435,17 @@ function useEditableRichText({
553
435
  preset,
554
436
  placeholder
555
437
  }) {
556
- const editorRef = useRef3(null);
557
- const [editor, setEditor] = useState3(null);
558
- const valueRef = useRef3(value);
559
- const onChangeRef = useRef3(onChange);
560
- useEffect3(() => {
438
+ const editorRef = useRef(null);
439
+ const [editor, setEditor] = useState2(null);
440
+ const valueRef = useRef(value);
441
+ const onChangeRef = useRef(onChange);
442
+ useEffect(() => {
561
443
  valueRef.current = value;
562
444
  }, [value]);
563
- useEffect3(() => {
445
+ useEffect(() => {
564
446
  onChangeRef.current = onChange;
565
447
  }, [onChange]);
566
- const activate = useCallback3(() => {
448
+ const activate = useCallback(() => {
567
449
  if (editorRef.current) return;
568
450
  const extensions = placeholder ? [...presets[preset], Placeholder.configure({ placeholder })] : presets[preset];
569
451
  const ed = new Editor({
@@ -585,7 +467,7 @@ function useEditableRichText({
585
467
  editorRef.current = ed;
586
468
  setEditor(ed);
587
469
  }, [preset, placeholder]);
588
- const deactivate = useCallback3(() => {
470
+ const deactivate = useCallback(() => {
589
471
  const ed = editorRef.current;
590
472
  if (!ed) return;
591
473
  const html = ed.getHTML();
@@ -596,7 +478,7 @@ function useEditableRichText({
596
478
  onChangeRef.current(html);
597
479
  }
598
480
  }, []);
599
- useEffect3(() => {
481
+ useEffect(() => {
600
482
  return () => {
601
483
  editorRef.current?.destroy();
602
484
  editorRef.current = null;
@@ -611,7 +493,7 @@ function useEditableRichText({
611
493
  }
612
494
 
613
495
  // src/components/primitives/RichTextToolbar.tsx
614
- import { useState as useState4 } from "react";
496
+ import { useState as useState3 } from "react";
615
497
  import { useEditorState } from "@tiptap/react";
616
498
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
617
499
  function ToolbarButton({ isActive, onClick, title, children }) {
@@ -638,7 +520,7 @@ function Separator() {
638
520
  return /* @__PURE__ */ jsx5("div", { className: "mx-1 h-5 w-px bg-base-contrast/20" });
639
521
  }
640
522
  function RichTextToolbar({ editor, preset }) {
641
- const [showLinkPopover, setShowLinkPopover] = useState4(false);
523
+ const [showLinkPopover, setShowLinkPopover] = useState3(false);
642
524
  const state = useEditorState({
643
525
  editor,
644
526
  selector: ({ editor: ed }) => ({
@@ -791,17 +673,17 @@ function EditableRichText({
791
673
  placeholder = DEFAULT_PLACEHOLDER
792
674
  }) {
793
675
  const { isEditorActive, editor, activate, deactivate } = useEditableRichText({ value, onChange, preset, placeholder });
794
- const wrapperRef = useRef4(null);
795
- const blurTimeoutRef = useRef4(null);
796
- const clickCoordsRef = useRef4(null);
797
- useEffect4(() => {
676
+ const wrapperRef = useRef2(null);
677
+ const blurTimeoutRef = useRef2(null);
678
+ const clickCoordsRef = useRef2(null);
679
+ useEffect2(() => {
798
680
  return () => {
799
681
  if (blurTimeoutRef.current) {
800
682
  clearTimeout(blurTimeoutRef.current);
801
683
  }
802
684
  };
803
685
  }, []);
804
- useEffect4(() => {
686
+ useEffect2(() => {
805
687
  if (!isEditorActive || !editor) return;
806
688
  requestAnimationFrame(() => {
807
689
  if (editor.isDestroyed) return;
@@ -825,19 +707,19 @@ function EditableRichText({
825
707
  }
826
708
  });
827
709
  }, [isEditorActive, editor]);
828
- const handleClick = useCallback4((e) => {
710
+ const handleClick = useCallback2((e) => {
829
711
  if (isEditMode && !isEditorActive) {
830
712
  clickCoordsRef.current = { left: e.clientX, top: e.clientY };
831
713
  activate();
832
714
  }
833
715
  }, [isEditMode, isEditorActive, activate]);
834
- const handleFocus = useCallback4(() => {
716
+ const handleFocus = useCallback2(() => {
835
717
  if (blurTimeoutRef.current) {
836
718
  clearTimeout(blurTimeoutRef.current);
837
719
  blurTimeoutRef.current = null;
838
720
  }
839
721
  }, []);
840
- const handleBlur = useCallback4(() => {
722
+ const handleBlur = useCallback2(() => {
841
723
  blurTimeoutRef.current = setTimeout(() => {
842
724
  if (wrapperRef.current && !wrapperRef.current.contains(document.activeElement)) {
843
725
  deactivate();
@@ -893,529 +775,8 @@ function EditableRichText({
893
775
  );
894
776
  }
895
777
 
896
- // src/components/primitives/ResolvedMedia.tsx
897
- import { ImageIcon } from "lucide-react";
898
-
899
- // src/hooks/useResolvedMedia.ts
900
- import { useMemo } from "react";
901
-
902
- // src/components/shell/MediaLibraryContext.tsx
903
- import { createContext, useContext } from "react";
904
- var MediaLibraryContext = createContext(null);
905
- function useMediaLibrary() {
906
- return useContext(MediaLibraryContext);
907
- }
908
-
909
- // src/hooks/useResolvedMedia.ts
910
- function useResolvedMedia(imageId) {
911
- const ctx = useMediaLibrary();
912
- return useMemo(() => {
913
- if (!imageId || !ctx) {
914
- return { src: void 0, srcset: void 0, poster: void 0, alt: "", kind: "image" };
915
- }
916
- const { manifest, pendingItems, pendingLocalUrls, siteConfig } = ctx;
917
- const sizes = siteConfig?.media?.sizes ?? [640, 1080, 1920];
918
- const manifestItem = manifest.images[imageId];
919
- const pendingItem = pendingItems.find((i) => i.id === imageId);
920
- const item = manifestItem ?? pendingItem;
921
- const alt = item?.alt ?? "";
922
- const kind = item?.kind ?? "image";
923
- const localUrl = pendingLocalUrls[imageId];
924
- if (localUrl) {
925
- return { src: localUrl, srcset: void 0, poster: void 0, alt, kind };
926
- }
927
- if (manifestItem) {
928
- const provider = getMediaProvider();
929
- const resolved = provider.resolve(manifestItem, sizes);
930
- if (resolved && resolved.tag === "img") {
931
- return {
932
- src: resolved.src,
933
- srcset: "srcSet" in resolved ? resolved.srcSet : void 0,
934
- poster: void 0,
935
- alt,
936
- kind
937
- };
938
- }
939
- if (resolved && resolved.tag === "video") {
940
- return { src: resolved.src, srcset: void 0, poster: resolved.poster, alt, kind };
941
- }
942
- }
943
- return { src: void 0, srcset: void 0, poster: void 0, alt, kind };
944
- }, [imageId, ctx]);
945
- }
946
-
947
- // src/components/primitives/ResolvedMedia.tsx
948
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
949
- function ResolvedMedia({
950
- imageId,
951
- src: propSrc,
952
- srcset: propSrcset,
953
- alt: propAlt,
954
- className,
955
- imgClassName,
956
- invertFrom
957
- }) {
958
- const resolved = useResolvedMedia(imageId);
959
- const src = propSrc || resolved.src;
960
- const srcset = propSrcset || resolved.srcset;
961
- const poster = resolved.poster;
962
- const alt = propAlt ?? resolved.alt;
963
- const kind = resolved.kind;
964
- const invertClass = invertFrom === "light" ? "invert dark:invert-0" : invertFrom === "dark" ? "dark:invert" : void 0;
965
- const mediaClass = cn("h-full w-full", imgClassName, invertClass);
966
- return /* @__PURE__ */ jsx7("div", { className, children: src ? kind === "video" ? /* @__PURE__ */ jsx7("video", { src, poster, muted: true, playsInline: true, loop: true, autoPlay: true, className: mediaClass }) : /* @__PURE__ */ jsx7("img", { src, srcSet: srcset, alt, className: mediaClass }) : /* @__PURE__ */ jsxs4("div", { className: "flex aspect-video h-full w-full flex-col items-center justify-center gap-1 rounded bg-base-accent text-base-contrast-light/50", children: [
967
- /* @__PURE__ */ jsx7(ImageIcon, { size: 24 }),
968
- /* @__PURE__ */ jsx7("span", { className: "text-sm", children: "No Image" })
969
- ] }) });
970
- }
971
-
972
- // src/components/primitives/ImageDropZone.tsx
973
- import { useState as useState5 } from "react";
974
- import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
975
- var ACCEPTED = /^(image|video)\//;
976
- function ImageDropZone({ onImageSelected, className, children }) {
977
- const mediaLibrary = useMediaLibrary();
978
- const [dragging, setDragging] = useState5(false);
979
- if (!mediaLibrary) return /* @__PURE__ */ jsx8(Fragment3, { children });
980
- const maxFileSize = mediaLibrary.siteConfig?.media.maxFileSize;
981
- const hasFiles = (e) => e.dataTransfer.types.includes("Files");
982
- const handleDragOver = (e) => {
983
- if (!hasFiles(e)) return;
984
- e.preventDefault();
985
- e.dataTransfer.dropEffect = "copy";
986
- setDragging(true);
987
- };
988
- const handleDragLeave = (e) => {
989
- if (!hasFiles(e)) return;
990
- const related = e.relatedTarget;
991
- if (related && e.currentTarget.contains(related)) return;
992
- setDragging(false);
993
- };
994
- const handleDrop = (e) => {
995
- if (!hasFiles(e)) return;
996
- e.preventDefault();
997
- e.stopPropagation();
998
- setDragging(false);
999
- const file = e.dataTransfer.files[0];
1000
- if (!file) return;
1001
- if (!ACCEPTED.test(file.type)) {
1002
- mediaLibrary.reportRejectedUploads([{ name: file.name, reason: "type" }]);
1003
- return;
1004
- }
1005
- if (maxFileSize && file.size > maxFileSize) {
1006
- mediaLibrary.reportRejectedUploads([{ name: file.name, reason: "size" }]);
1007
- return;
1008
- }
1009
- mediaLibrary.uploadFileWithCallback(file, onImageSelected);
1010
- };
1011
- return /* @__PURE__ */ jsxs5(
1012
- "div",
1013
- {
1014
- className: cn("relative", className),
1015
- onDragOver: handleDragOver,
1016
- onDragLeave: handleDragLeave,
1017
- onDrop: handleDrop,
1018
- children: [
1019
- children,
1020
- dragging && /* @__PURE__ */ jsx8("div", { className: "pointer-events-none absolute inset-0 z-10 rounded-md border-2 border-primary bg-primary/5" })
1021
- ]
1022
- }
1023
- );
1024
- }
1025
-
1026
- // src/components/sections/Media/MediaBlock.tsx
1027
- import { Check, X } from "lucide-react";
1028
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1029
- function MediaBlock({ refValue, options, link, dodont, isEditMode, onRefChange }) {
1030
- const mediaLibrary = useMediaLibrary();
1031
- const fit = refValue.objectFit ?? options.objectFit;
1032
- const fitClass = fit === "cover" ? "object-cover" : "object-contain";
1033
- const showBorder = refValue.border ?? options.border;
1034
- const captionStr = refValue.caption ? Array.isArray(refValue.caption) ? refValue.caption.join("\n") : refValue.caption : "";
1035
- const replace = onRefChange ? (imageId) => onRefChange({ ...refValue, imageId }) : void 0;
1036
- const resolved = /* @__PURE__ */ jsx9(
1037
- ResolvedMedia,
1038
- {
1039
- imageId: refValue.imageId || void 0,
1040
- className: "h-full w-full",
1041
- imgClassName: fitClass,
1042
- invertFrom: refValue.invertFrom
1043
- }
1044
- );
1045
- let media = isEditMode && replace ? /* @__PURE__ */ jsx9(ImageDropZone, { onImageSelected: replace, className: "h-full w-full", children: resolved }) : resolved;
1046
- if (!isEditMode && link && link.kind === "external" && link.href) {
1047
- media = /* @__PURE__ */ jsx9("a", { href: link.href, target: link.target, className: "group block", children: media });
1048
- }
1049
- const onImageClick = isEditMode && replace && mediaLibrary ? () => mediaLibrary.openSelectModal((imageId) => replace(imageId)) : void 0;
1050
- return /* @__PURE__ */ jsxs6("figure", { children: [
1051
- dodont && /* @__PURE__ */ jsx9("div", { className: "flex h-10 items-center justify-center pb-1", children: dodont === "do" ? /* @__PURE__ */ jsx9(Check, { size: 28, className: "text-green-600" }) : /* @__PURE__ */ jsx9(X, { size: 28, className: "text-red-600" }) }),
1052
- /* @__PURE__ */ jsx9(
1053
- "div",
1054
- {
1055
- "data-testid": "media-open-surface",
1056
- className: cn(
1057
- "overflow-hidden rounded-md",
1058
- showBorder && "border border-base-200",
1059
- options.square && "aspect-square",
1060
- onImageClick && "cursor-pointer"
1061
- ),
1062
- onClick: onImageClick,
1063
- onPointerDown: onImageClick ? (e) => e.stopPropagation() : void 0,
1064
- children: media
1065
- }
1066
- ),
1067
- options.showCaption && /* @__PURE__ */ jsx9("figcaption", { className: "mt-2 min-h-[1em] text-sm text-base-contrast-light", children: isEditMode && onRefChange ? /* @__PURE__ */ jsx9(
1068
- EditablePlainText,
1069
- {
1070
- tag: "span",
1071
- value: captionStr,
1072
- onChange: (caption) => onRefChange({ ...refValue, caption: caption || void 0 }),
1073
- isEditMode: true,
1074
- placeholder: "Caption",
1075
- className: "block min-h-[1em]"
1076
- }
1077
- ) : captionStr || " " })
1078
- ] });
1079
- }
1080
-
1081
- // src/components/primitives/EditableGrid.tsx
1082
- import { useRef as useRef6, useEffect as useEffect6, useState as useState7 } from "react";
1083
- import { ImageIcon as ImageIcon2 } from "lucide-react";
1084
-
1085
- // src/lib/container-grid.ts
1086
- var MAX_CONTAINER_COLUMNS = 6;
1087
- var containerGridClass = {
1088
- 1: "grid-cols-1",
1089
- 2: "grid-cols-1 @sm:grid-cols-2",
1090
- 3: "grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-3",
1091
- 4: "grid-cols-1 @xs:grid-cols-2 @lg:grid-cols-4",
1092
- 5: "grid-cols-1 @xs:grid-cols-2 @md:grid-cols-3 @xl:grid-cols-5",
1093
- 6: "grid-cols-1 @xs:grid-cols-2 @md:grid-cols-3 @2xl:grid-cols-6"
1094
- };
1095
- var colSpanClass = {
1096
- 1: { 1: "" },
1097
- 2: { 1: "", 2: "col-span-1 @sm:col-span-2" },
1098
- 3: { 1: "", 2: "col-span-1 @sm:col-span-2", 3: "col-span-1 @sm:col-span-2 @lg:col-span-3" },
1099
- 4: { 1: "", 2: "col-span-1 @xs:col-span-2", 3: "col-span-1 @xs:col-span-2 @lg:col-span-3", 4: "col-span-1 @xs:col-span-2 @lg:col-span-4" },
1100
- 5: { 1: "", 2: "col-span-1 @xs:col-span-2", 3: "col-span-1 @xs:col-span-2 @md:col-span-3", 4: "col-span-1 @xs:col-span-2 @md:col-span-3 @xl:col-span-4", 5: "col-span-1 @xs:col-span-2 @md:col-span-3 @xl:col-span-5" },
1101
- 6: { 1: "", 2: "col-span-1 @xs:col-span-2", 3: "col-span-1 @xs:col-span-2 @md:col-span-3", 4: "col-span-1 @xs:col-span-2 @md:col-span-3 @2xl:col-span-4", 5: "col-span-1 @xs:col-span-2 @md:col-span-3 @2xl:col-span-5", 6: "col-span-1 @xs:col-span-2 @md:col-span-3 @2xl:col-span-6" }
1102
- };
1103
- var spacerHiddenClass = {
1104
- 1: "hidden",
1105
- 2: "hidden @sm:block",
1106
- 3: "hidden @sm:block",
1107
- 4: "hidden @xs:block",
1108
- 5: "hidden @xs:block",
1109
- 6: "hidden @xs:block"
1110
- };
1111
-
1112
- // src/components/primitives/useEditableCollection.ts
1113
- import { useState as useState6, useCallback as useCallback5, useRef as useRef5, useEffect as useEffect5 } from "react";
1114
- var nextId = 0;
1115
- function uid() {
1116
- return typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `_id_${nextId++}_${Date.now()}`;
1117
- }
1118
- function wrapItems(items) {
1119
- return items.map((data) => ({ id: uid(), data }));
1120
- }
1121
- function useEditableCollection({
1122
- items,
1123
- onChange,
1124
- createItem
1125
- }) {
1126
- const [wrappedItems, setWrappedItems] = useState6(
1127
- () => wrapItems(items)
1128
- );
1129
- const prevItemsRef = useRef5(items);
1130
- useEffect5(() => {
1131
- if (items === prevItemsRef.current) return;
1132
- prevItemsRef.current = items;
1133
- setWrappedItems((prev) => {
1134
- return items.map((data, i) => {
1135
- if (i < prev.length) {
1136
- return { id: prev[i].id, data };
1137
- }
1138
- return { id: uid(), data };
1139
- });
1140
- });
1141
- }, [items]);
1142
- const onReorder = useCallback5(
1143
- (fromIndex, toIndex) => {
1144
- setWrappedItems((prev) => {
1145
- const next = [...prev];
1146
- const [moved] = next.splice(fromIndex, 1);
1147
- next.splice(toIndex, 0, moved);
1148
- onChange(next.map((w) => w.data));
1149
- return next;
1150
- });
1151
- },
1152
- [onChange]
1153
- );
1154
- const onAdd = useCallback5(() => {
1155
- const newItem = createItem();
1156
- setWrappedItems((prev) => {
1157
- const next = [...prev, { id: uid(), data: newItem }];
1158
- onChange(next.map((w) => w.data));
1159
- return next;
1160
- });
1161
- }, [createItem, onChange]);
1162
- const onInsert = useCallback5(
1163
- (index) => {
1164
- const newItem = createItem();
1165
- setWrappedItems((prev) => {
1166
- const next = [...prev];
1167
- next.splice(index, 0, { id: uid(), data: newItem });
1168
- onChange(next.map((w) => w.data));
1169
- return next;
1170
- });
1171
- },
1172
- [createItem, onChange]
1173
- );
1174
- const onRemove = useCallback5(
1175
- (id) => {
1176
- setWrappedItems((prev) => {
1177
- const next = prev.filter((w) => w.id !== id);
1178
- onChange(next.map((w) => w.data));
1179
- return next;
1180
- });
1181
- },
1182
- [onChange]
1183
- );
1184
- return { wrappedItems, onReorder, onAdd, onInsert, onRemove };
1185
- }
1186
-
1187
- // src/components/primitives/EditableGrid.tsx
1188
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1189
- function EditableGrid({
1190
- items,
1191
- columns,
1192
- onChange,
1193
- createItem,
1194
- isEditMode,
1195
- renderItem,
1196
- onItemSettings,
1197
- onItemImageClick,
1198
- chromeTopClass,
1199
- className
1200
- }) {
1201
- const { wrappedItems, onReorder, onAdd, onInsert, onRemove } = useEditableCollection({
1202
- items,
1203
- onChange,
1204
- createItem
1205
- });
1206
- const [dragState, setDragState] = useState7({ sourceId: null, closestEdge: null });
1207
- const [isDragging, setIsDragging] = useState7(false);
1208
- useEffect6(() => {
1209
- let cleanup;
1210
- let cancelled = false;
1211
- import("./adapter-HH47ZPGM.js").then(({ monitorForElements }) => {
1212
- if (cancelled) return;
1213
- cleanup = monitorForElements({
1214
- onDragStart: ({ source }) => {
1215
- if (source.data.dragType === "grid-cell") setIsDragging(true);
1216
- },
1217
- onDrop: ({ source }) => {
1218
- if (source.data.dragType === "grid-cell") setIsDragging(false);
1219
- }
1220
- });
1221
- });
1222
- return () => {
1223
- cancelled = true;
1224
- cleanup?.();
1225
- };
1226
- }, []);
1227
- if (!isEditMode) {
1228
- return /* @__PURE__ */ jsx10("div", { className: "@container", children: /* @__PURE__ */ jsx10("div", { className: cn("grid gap-4", containerGridClass[columns] || containerGridClass[1], className), children: wrappedItems.map((wrapped, index) => /* @__PURE__ */ jsx10("div", { children: renderItem(wrapped.data, { isEditMode: false, index }) }, wrapped.id)) }) });
1229
- }
1230
- return /* @__PURE__ */ jsx10("div", { className: "@container", children: /* @__PURE__ */ jsxs7("div", { className: cn("group/grid relative grid gap-4", containerGridClass[columns] || containerGridClass[1], className), children: [
1231
- wrappedItems.map((wrapped, index) => /* @__PURE__ */ jsx10(
1232
- GridCell,
1233
- {
1234
- id: wrapped.id,
1235
- index,
1236
- isLast: index === wrappedItems.length - 1,
1237
- isDragging,
1238
- onReorder,
1239
- onRemove,
1240
- onInsert,
1241
- onSettings: onItemSettings ? () => onItemSettings(index) : void 0,
1242
- onImageClick: onItemImageClick ? () => onItemImageClick(index) : void 0,
1243
- chromeTopClass,
1244
- dragState,
1245
- setDragState,
1246
- children: renderItem(wrapped.data, { isEditMode: true, index })
1247
- },
1248
- wrapped.id
1249
- )),
1250
- /* @__PURE__ */ jsx10(
1251
- IconButton,
1252
- {
1253
- icon: /* @__PURE__ */ jsx10(AddIcon, { size: 16 }),
1254
- label: "Add item",
1255
- size: "lg",
1256
- intent: "primary",
1257
- onClick: onAdd,
1258
- className: "absolute -bottom-6 left-1/2 z-20 -translate-x-1/2 rounded-full border border-base-200 bg-base opacity-0 transition-opacity group-hover/grid:opacity-100"
1259
- }
1260
- )
1261
- ] }) });
1262
- }
1263
- function GridCell({
1264
- id,
1265
- index,
1266
- isLast,
1267
- isDragging,
1268
- onReorder,
1269
- onRemove,
1270
- onInsert,
1271
- onSettings,
1272
- onImageClick,
1273
- chromeTopClass,
1274
- dragState,
1275
- setDragState,
1276
- children
1277
- }) {
1278
- const cellRef = useRef6(null);
1279
- const handleRef = useRef6(null);
1280
- useEffect6(() => {
1281
- const cell = cellRef.current;
1282
- const handle = handleRef.current;
1283
- if (!cell || !handle) return;
1284
- let cleanup;
1285
- let cancelled = false;
1286
- Promise.all([
1287
- import("./adapter-HH47ZPGM.js"),
1288
- import("./closest-edge-EBOXL3YW.js")
1289
- ]).then(([{ draggable, dropTargetForElements }, { attachClosestEdge, extractClosestEdge }]) => {
1290
- if (cancelled) return;
1291
- const cleanupDraggable = draggable({
1292
- element: handle,
1293
- getInitialData: () => ({ dragType: "grid-cell", id, index }),
1294
- onDragStart: () => setDragState({ sourceId: id, closestEdge: null }),
1295
- onDrop: () => setDragState({ sourceId: null, closestEdge: null })
1296
- });
1297
- const cleanupDropTarget = dropTargetForElements({
1298
- element: cell,
1299
- canDrop: ({ source }) => source.data.dragType === "grid-cell",
1300
- getData: ({ input, element }) => attachClosestEdge(
1301
- { id, index },
1302
- { input, element, allowedEdges: ["left", "right"] }
1303
- ),
1304
- onDragEnter: ({ self }) => {
1305
- const edge = extractClosestEdge(self.data);
1306
- if (edge) setDragState((prev) => ({ ...prev, closestEdge: { id, edge } }));
1307
- },
1308
- onDrag: ({ self }) => {
1309
- const edge = extractClosestEdge(self.data);
1310
- if (edge) setDragState((prev) => ({ ...prev, closestEdge: { id, edge } }));
1311
- },
1312
- onDragLeave: () => {
1313
- setDragState((prev) => prev.closestEdge?.id === id ? { ...prev, closestEdge: null } : prev);
1314
- },
1315
- onDrop: ({ source, self }) => {
1316
- const fromIndex = source.data.index;
1317
- const edge = extractClosestEdge(self.data);
1318
- let toIndex = index;
1319
- if (edge === "right") toIndex = index + 1;
1320
- if (fromIndex < toIndex) toIndex--;
1321
- if (fromIndex !== toIndex) {
1322
- onReorder(fromIndex, toIndex);
1323
- }
1324
- }
1325
- });
1326
- cleanup = () => {
1327
- cleanupDraggable();
1328
- cleanupDropTarget();
1329
- };
1330
- });
1331
- return () => {
1332
- cancelled = true;
1333
- cleanup?.();
1334
- };
1335
- }, [id, index, onReorder, setDragState]);
1336
- const isCellDragging = dragState.sourceId === id;
1337
- const showLeftEdge = dragState.closestEdge?.id === id && dragState.closestEdge.edge === "left" && dragState.sourceId !== id;
1338
- const showRightEdge = dragState.closestEdge?.id === id && dragState.closestEdge.edge === "right" && dragState.sourceId !== id;
1339
- return /* @__PURE__ */ jsxs7(
1340
- "div",
1341
- {
1342
- ref: cellRef,
1343
- className: cn(
1344
- "group/cell relative",
1345
- isCellDragging && "opacity-50"
1346
- ),
1347
- children: [
1348
- showLeftEdge && /* @__PURE__ */ jsx10("div", { className: "absolute top-0 bottom-0 left-0 z-10 w-0.5 -translate-x-2 bg-primary" }),
1349
- showRightEdge && /* @__PURE__ */ jsx10("div", { className: "absolute top-0 right-0 bottom-0 z-10 w-0.5 translate-x-2 bg-primary" }),
1350
- !isDragging && !isLast && /* @__PURE__ */ jsx10(
1351
- IconButton,
1352
- {
1353
- icon: /* @__PURE__ */ jsx10(AddIcon, { size: 12 }),
1354
- label: "Insert item",
1355
- size: "sm",
1356
- intent: "primary",
1357
- onClick: () => onInsert(index + 1),
1358
- className: "absolute top-1/2 -right-2 z-20 -translate-y-1/2 translate-x-1/2 rounded-full border border-base-200 bg-base opacity-0 group-hover/cell:opacity-100"
1359
- }
1360
- ),
1361
- /* @__PURE__ */ jsx10(
1362
- IconButton,
1363
- {
1364
- ref: handleRef,
1365
- icon: /* @__PURE__ */ jsx10(DragHandle, { size: 16 }),
1366
- label: "Drag to reorder",
1367
- className: cn("absolute left-1.5 z-10 cursor-grab bg-base/80 opacity-0 shadow-sm group-hover/cell:opacity-100 no-hover:opacity-100", chromeTopClass || "top-1.5"),
1368
- tabIndex: -1
1369
- }
1370
- ),
1371
- /* @__PURE__ */ jsxs7("div", { className: cn("absolute right-1.5 z-10 flex items-center gap-1 opacity-0 group-hover/cell:opacity-100 no-hover:opacity-100", chromeTopClass || "top-1.5"), children: [
1372
- onImageClick && /* @__PURE__ */ jsx10(
1373
- IconButton,
1374
- {
1375
- icon: /* @__PURE__ */ jsx10(ImageIcon2, { size: 16 }),
1376
- label: "Change image",
1377
- onClick: onImageClick,
1378
- className: "bg-base/80 shadow-sm"
1379
- }
1380
- ),
1381
- onSettings && /* @__PURE__ */ jsx10(
1382
- IconButton,
1383
- {
1384
- icon: /* @__PURE__ */ jsx10(SettingsIcon, { size: 16 }),
1385
- label: "Item settings",
1386
- onClick: onSettings,
1387
- className: "bg-base/80 shadow-sm"
1388
- }
1389
- ),
1390
- /* @__PURE__ */ jsx10(
1391
- IconButton,
1392
- {
1393
- icon: /* @__PURE__ */ jsx10(DeleteIcon, { size: 16 }),
1394
- label: "Delete item",
1395
- intent: "destructive",
1396
- onClick: () => onRemove(id),
1397
- className: "bg-base/80 shadow-sm"
1398
- }
1399
- )
1400
- ] }),
1401
- children
1402
- ]
1403
- }
1404
- );
1405
- }
1406
-
1407
778
  export {
1408
- EditablePlainText,
1409
779
  defineHeadingSection,
1410
780
  LinkPopover,
1411
- EditableRichText,
1412
- ResolvedMedia,
1413
- ImageDropZone,
1414
- MediaBlock,
1415
- MAX_CONTAINER_COLUMNS,
1416
- containerGridClass,
1417
- colSpanClass,
1418
- spacerHiddenClass,
1419
- useEditableCollection,
1420
- EditableGrid
781
+ EditableRichText
1421
782
  };