@ckc-net/puck-extended 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { useRender } from "@base-ui/react/use-render";
4
4
  import { cva } from "class-variance-authority";
5
5
  import { clsx } from "clsx";
6
6
  import { twMerge } from "tailwind-merge";
7
- import { AlignCenterIcon, AlignJustifyIcon, AlignLeftIcon, AlignRightIcon, BaselineIcon, BoldIcon, BoxIcon, CaseLowerIcon, CaseSensitiveIcon, CaseUpperIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronsUpDownIcon, CircleAlertIcon, CircleCheckIcon, DatabaseIcon, FileIcon, FileTextIcon, GripVerticalIcon, InfoIcon, ItalicIcon, LightbulbIcon, LinkIcon, Loader2Icon, LoaderCircleIcon, LockIcon, MinusIcon, MoreHorizontalIcon, PlusIcon, SearchIcon, StrikethroughIcon, Trash2Icon, TriangleAlertIcon, UnderlineIcon, UploadIcon, XIcon } from "lucide-react";
7
+ import { AlignCenterIcon, AlignJustifyIcon, AlignLeftIcon, AlignRightIcon, BaselineIcon, BoldIcon, BoxIcon, CaseLowerIcon, CaseSensitiveIcon, CaseUpperIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronsUpDownIcon, CircleAlertIcon, CircleCheckIcon, DatabaseIcon, FileIcon, FileTextIcon, GripVerticalIcon, InfoIcon, ItalicIcon, LightbulbIcon, LinkIcon, Loader2Icon, LoaderCircleIcon, LockIcon, MinusIcon, MoreHorizontalIcon, PlusIcon, SearchIcon, SparklesIcon, StrikethroughIcon, Trash2Icon, TriangleAlertIcon, UnderlineIcon, UploadIcon, XIcon } from "lucide-react";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { Tooltip as Tooltip$1 } from "@base-ui/react/tooltip";
10
10
  import { Checkbox as Checkbox$1 } from "@base-ui/react/checkbox";
@@ -23,7 +23,7 @@ import { flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-tabl
23
23
  import { Color } from "@tiptap/extension-color";
24
24
  import { TextStyle } from "@tiptap/extension-text-style";
25
25
  import { HexColorPicker } from "react-colorful";
26
- import { Menu as Menu$1 } from "@base-ui/react/menu";
26
+ import { Menu as MenuPrimitive } from "@base-ui/react/menu";
27
27
  import { Separator as Separator$1 } from "@base-ui/react/separator";
28
28
  import { Switch as Switch$1 } from "@base-ui/react/switch";
29
29
  import { Toast } from "@base-ui/react/toast";
@@ -225,7 +225,7 @@ function TooltipPositioner({ className, side = "top", ...rest }) {
225
225
  ...rest
226
226
  }) });
227
227
  }
228
- function TooltipPopup({ className, animationPreset = "scale", transitionPreset = "outQuint", reduceMotion = false, showArrow = false, side = "top", sideOffset = 4, align = "center", alignOffset = 0, ...rest }) {
228
+ function TooltipPopup({ className, animationPreset = "fade", transitionPreset = "outQuint", reduceMotion = false, showArrow = false, side = "top", sideOffset = 4, align = "center", alignOffset = 0, ...rest }) {
229
229
  const cssAnimationConfig = useMemo(() => {
230
230
  if (reduceMotion) return "none";
231
231
  if (animationPreset) return cssAnimationPresets[animationPreset];
@@ -267,21 +267,25 @@ function TooltipPopup({ className, animationPreset = "scale", transitionPreset =
267
267
 
268
268
  //#endregion
269
269
  //#region src/components/Fields/Label/index.tsx
270
- const Label$1 = ({ label, readOnly, tooltip }) => /* @__PURE__ */ jsxs(Label$2, {
270
+ const Label$1 = ({ label, readOnly, tooltip, action }) => /* @__PURE__ */ jsxs(Label$2, {
271
271
  readOnly,
272
- children: [label, tooltip && /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
273
- delay: 200,
274
- children: /* @__PURE__ */ jsx(Button, {
275
- variant: "secondary",
276
- className: "!text-xs !rounded-full !p-0 !size-5 flex items-center justify-center",
277
- children: "?"
278
- })
279
- }), /* @__PURE__ */ jsx(TooltipPopup, {
280
- side: "top",
281
- align: "end",
282
- className: "max-w-64 text-xs",
283
- children: tooltip
284
- })] })]
272
+ children: [label, (action || tooltip) && /* @__PURE__ */ jsxs("div", {
273
+ className: "flex items-center gap-x-1.5",
274
+ children: [action, tooltip && /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
275
+ delay: 200,
276
+ render: /* @__PURE__ */ jsx("span", {}),
277
+ children: /* @__PURE__ */ jsx(Button, {
278
+ variant: "secondary",
279
+ className: "!text-xs !rounded-full !p-0 !size-5 flex items-center justify-center",
280
+ children: "?"
281
+ })
282
+ }), /* @__PURE__ */ jsx(TooltipPopup, {
283
+ side: "top",
284
+ align: "end",
285
+ className: "max-w-64 text-xs",
286
+ children: tooltip
287
+ })] })]
288
+ })]
285
289
  });
286
290
  var Label_default = Label$1;
287
291
 
@@ -1081,7 +1085,7 @@ const createPuckOverridesPlugin = () => {
1081
1085
  fields: FieldGroups_default,
1082
1086
  fieldLabel: ({ children, label, field, tooltip }) => /* @__PURE__ */ jsxs(Fragment, { children: [label && /* @__PURE__ */ jsx(Label_default, {
1083
1087
  label,
1084
- tooltip
1088
+ tooltip: tooltip ?? field?.tooltip
1085
1089
  }), children] }),
1086
1090
  fieldTypes: {
1087
1091
  checkbox: Checkbox_default,
@@ -2422,7 +2426,7 @@ const MediaUploadZone = ({ onUploadSuccess, acceptedTypes = "image/*,video/*,app
2422
2426
  return new Promise((resolve, reject) => {
2423
2427
  try {
2424
2428
  const { uploadUrl, langId } = getEditorConfig();
2425
- const csrfToken = document.querySelector("meta[name=\"csrf-token\"]");
2429
+ const csrfToken = getCsrfToken();
2426
2430
  const formData = new FormData();
2427
2431
  formData.append("file", file);
2428
2432
  if (langId) formData.append("lang_id", langId);
@@ -2441,7 +2445,7 @@ const MediaUploadZone = ({ onUploadSuccess, acceptedTypes = "image/*,video/*,app
2441
2445
  reject(/* @__PURE__ */ new Error("Error during upload"));
2442
2446
  });
2443
2447
  xhr.open("POST", uploadUrl);
2444
- if (csrfToken) xhr.setRequestHeader("X-CSRF-TOKEN", csrfToken.content);
2448
+ if (csrfToken) xhr.setRequestHeader("X-CSRF-TOKEN", csrfToken);
2445
2449
  xhr.send(formData);
2446
2450
  } catch (error) {
2447
2451
  reject(error);
@@ -2815,43 +2819,49 @@ const useMediaUrl = (value) => {
2815
2819
 
2816
2820
  //#endregion
2817
2821
  //#region src/components/ui/menu.tsx
2818
- const MenuCreateHandle = Menu$1.createHandle;
2819
- const Menu = Menu$1.Root;
2820
- const MenuPortal = Menu$1.Portal;
2821
- function MenuTrigger(props) {
2822
- return /* @__PURE__ */ jsx(Menu$1.Trigger, {
2822
+ const MenuCreateHandle = MenuPrimitive.createHandle;
2823
+ const Menu = MenuPrimitive.Root;
2824
+ const MenuPortal = MenuPrimitive.Portal;
2825
+ function MenuTrigger({ className, children, ...props }) {
2826
+ return /* @__PURE__ */ jsx(MenuPrimitive.Trigger, {
2827
+ className,
2823
2828
  "data-slot": "menu-trigger",
2824
- ...props
2829
+ ...props,
2830
+ children
2825
2831
  });
2826
2832
  }
2827
- function MenuPopup({ children, className, sideOffset = 4, align = "center", alignOffset, side = "bottom", ...props }) {
2828
- return /* @__PURE__ */ jsx(Menu$1.Portal, { children: /* @__PURE__ */ jsx(Menu$1.Positioner, {
2829
- align,
2830
- alignOffset,
2831
- className: "z-50",
2832
- "data-slot": "menu-positioner",
2833
- side,
2834
- sideOffset,
2835
- children: /* @__PURE__ */ jsx(Menu$1.Popup, {
2836
- className: cn("relative flex not-[class*='w-']:min-w-32 origin-(--transform-origin) rounded-lg border bg-popover not-dark:bg-clip-padding shadow-lg/5 outline-none before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] focus:outline-none dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", className),
2837
- "data-slot": "menu-popup",
2838
- ...props,
2839
- children: /* @__PURE__ */ jsx("div", {
2840
- className: "max-h-(--available-height) w-full overflow-y-auto p-1",
2841
- children
2833
+ function MenuPopup({ children, className, sideOffset = 4, align = "center", alignOffset, side = "bottom", anchor, portalProps, ...props }) {
2834
+ return /* @__PURE__ */ jsx(MenuPortal, {
2835
+ ...portalProps,
2836
+ children: /* @__PURE__ */ jsx(MenuPrimitive.Positioner, {
2837
+ align,
2838
+ alignOffset,
2839
+ anchor,
2840
+ className: "z-50",
2841
+ "data-slot": "menu-positioner",
2842
+ side,
2843
+ sideOffset,
2844
+ children: /* @__PURE__ */ jsx(MenuPrimitive.Popup, {
2845
+ className: cn("relative flex not-[class*='w-']:min-w-32 origin-(--transform-origin) rounded-lg border bg-popover not-dark:bg-clip-padding shadow-lg/5 outline-none before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] focus:outline-none dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", className),
2846
+ "data-slot": "menu-popup",
2847
+ ...props,
2848
+ children: /* @__PURE__ */ jsx("div", {
2849
+ className: "max-h-(--available-height) w-full overflow-y-auto p-1",
2850
+ children
2851
+ })
2842
2852
  })
2843
2853
  })
2844
- }) });
2854
+ });
2845
2855
  }
2846
2856
  function MenuGroup(props) {
2847
- return /* @__PURE__ */ jsx(Menu$1.Group, {
2857
+ return /* @__PURE__ */ jsx(MenuPrimitive.Group, {
2848
2858
  "data-slot": "menu-group",
2849
2859
  ...props
2850
2860
  });
2851
2861
  }
2852
2862
  function MenuItem({ className, inset, variant = "default", ...props }) {
2853
- return /* @__PURE__ */ jsx(Menu$1.Item, {
2854
- className: cn("[&>svg]:-mx-0.5 flex min-h-8 cursor-default select-none items-center gap-2 rounded-sm px-2 py-1 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-inset:ps-8 data-[variant=destructive]:text-destructive-foreground data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&>svg:not([class*='opacity-'])]:opacity-80 [&>svg:not([class*='size-'])]:size-4.5 sm:[&>svg:not([class*='size-'])]:size-4 [&>svg]:pointer-events-none [&>svg]:shrink-0", className),
2863
+ return /* @__PURE__ */ jsx(MenuPrimitive.Item, {
2864
+ className: cn("flex min-h-8 cursor-default select-none items-center gap-2 rounded-sm px-2 py-1 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-inset:ps-8 data-[variant=destructive]:text-destructive-foreground data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&>svg:not([class*='opacity-'])]:opacity-80 [&>svg:not([class*='size-'])]:size-4.5 sm:[&>svg:not([class*='size-'])]:size-4 [&>svg]:pointer-events-none [&>svg]:-mx-0.5 [&>svg]:shrink-0", className),
2855
2865
  "data-inset": inset,
2856
2866
  "data-slot": "menu-item",
2857
2867
  "data-variant": variant,
@@ -2859,21 +2869,22 @@ function MenuItem({ className, inset, variant = "default", ...props }) {
2859
2869
  });
2860
2870
  }
2861
2871
  function MenuCheckboxItem({ className, children, checked, variant = "default", ...props }) {
2862
- return /* @__PURE__ */ jsx(Menu$1.CheckboxItem, {
2872
+ return /* @__PURE__ */ jsx(MenuPrimitive.CheckboxItem, {
2863
2873
  checked,
2864
- className: cn("grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default items-center gap-2 rounded-sm py-1 ps-2 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", variant === "switch" ? "grid-cols-[1fr_auto] gap-4 pe-1.5" : "grid-cols-[1rem_1fr] pe-4", className),
2874
+ className: cn("grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default items-center gap-2 rounded-sm py-1 ps-2 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", variant === "switch" ? "grid-cols-[1fr_auto] gap-4 pe-1.5" : "grid-cols-[.75rem_1fr] pe-4", className),
2865
2875
  "data-slot": "menu-checkbox-item",
2866
2876
  ...props,
2867
2877
  children: variant === "switch" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
2868
2878
  className: "col-start-1",
2869
2879
  children
2870
- }), /* @__PURE__ */ jsx(Menu$1.CheckboxItemIndicator, {
2871
- className: "inset-shadow-[0_1px_--theme(--color-black/6%)] inline-flex h-[calc(var(--thumb-size)+2px)] w-[calc(var(--thumb-size)*2-2px)] shrink-0 items-center rounded-full p-px outline-none transition-[background-color,box-shadow] duration-200 [--thumb-size:--spacing(4)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-checked:bg-primary data-unchecked:bg-input data-disabled:opacity-64 sm:[--thumb-size:--spacing(3)]",
2880
+ }), /* @__PURE__ */ jsx(MenuPrimitive.CheckboxItemIndicator, {
2881
+ className: "inset-shadow-[0_1px_--theme(--color-black/4%)] inline-flex h-[calc(var(--thumb-size)+2px)] w-[calc(var(--thumb-size)*2-2px)] shrink-0 items-center rounded-full p-px outline-none transition-[background-color,box-shadow] duration-200 [--thumb-size:--spacing(4)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-checked:bg-primary data-unchecked:bg-input data-disabled:opacity-64 sm:[--thumb-size:--spacing(3)]",
2872
2882
  keepMounted: true,
2873
2883
  children: /* @__PURE__ */ jsx("span", { className: "pointer-events-none block aspect-square h-full in-[[data-slot=menu-checkbox-item][data-checked]]:origin-[var(--thumb-size)_50%] origin-left in-[[data-slot=menu-checkbox-item][data-checked]]:translate-x-[calc(var(--thumb-size)-4px)] in-[[data-slot=menu-checkbox-item]:active]:not-data-disabled:scale-x-110 in-[[data-slot=menu-checkbox-item]:active]:rounded-[var(--thumb-size)/calc(var(--thumb-size)*1.10)] rounded-(--thumb-size) bg-background shadow-sm/5 will-change-transform [transition:translate_.15s,border-radius_.15s,scale_.1s_.1s,transform-origin_.15s]" })
2874
- })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Menu$1.CheckboxItemIndicator, {
2875
- className: "col-start-1",
2884
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MenuPrimitive.CheckboxItemIndicator, {
2885
+ className: "col-start-1 -ms-0.5",
2876
2886
  children: /* @__PURE__ */ jsx("svg", {
2887
+ "aria-hidden": "true",
2877
2888
  fill: "none",
2878
2889
  height: "24",
2879
2890
  stroke: "currentColor",
@@ -2892,19 +2903,20 @@ function MenuCheckboxItem({ className, children, checked, variant = "default", .
2892
2903
  });
2893
2904
  }
2894
2905
  function MenuRadioGroup(props) {
2895
- return /* @__PURE__ */ jsx(Menu$1.RadioGroup, {
2906
+ return /* @__PURE__ */ jsx(MenuPrimitive.RadioGroup, {
2896
2907
  "data-slot": "menu-radio-group",
2897
2908
  ...props
2898
2909
  });
2899
2910
  }
2900
2911
  function MenuRadioItem({ className, children, ...props }) {
2901
- return /* @__PURE__ */ jsxs(Menu$1.RadioItem, {
2902
- className: cn("grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[1rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", className),
2912
+ return /* @__PURE__ */ jsxs(MenuPrimitive.RadioItem, {
2913
+ className: cn("grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[.75rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", className),
2903
2914
  "data-slot": "menu-radio-item",
2904
2915
  ...props,
2905
- children: [/* @__PURE__ */ jsx(Menu$1.RadioItemIndicator, {
2906
- className: "col-start-1",
2916
+ children: [/* @__PURE__ */ jsx(MenuPrimitive.RadioItemIndicator, {
2917
+ className: "col-start-1 -ms-0.5",
2907
2918
  children: /* @__PURE__ */ jsx("svg", {
2919
+ "aria-hidden": "true",
2908
2920
  fill: "none",
2909
2921
  height: "24",
2910
2922
  stroke: "currentColor",
@@ -2923,7 +2935,7 @@ function MenuRadioItem({ className, children, ...props }) {
2923
2935
  });
2924
2936
  }
2925
2937
  function MenuGroupLabel({ className, inset, ...props }) {
2926
- return /* @__PURE__ */ jsx(Menu$1.GroupLabel, {
2938
+ return /* @__PURE__ */ jsx(MenuPrimitive.GroupLabel, {
2927
2939
  className: cn("px-2 py-1.5 font-medium text-muted-foreground text-xs data-inset:ps-9 sm:data-inset:ps-8", className),
2928
2940
  "data-inset": inset,
2929
2941
  "data-slot": "menu-label",
@@ -2931,32 +2943,25 @@ function MenuGroupLabel({ className, inset, ...props }) {
2931
2943
  });
2932
2944
  }
2933
2945
  function MenuSeparator({ className, ...props }) {
2934
- return /* @__PURE__ */ jsx(Menu$1.Separator, {
2946
+ return /* @__PURE__ */ jsx(MenuPrimitive.Separator, {
2935
2947
  className: cn("mx-2 my-1 h-px bg-border", className),
2936
2948
  "data-slot": "menu-separator",
2937
2949
  ...props
2938
2950
  });
2939
2951
  }
2940
- function MenuShortcut({ className, ...props }) {
2941
- return /* @__PURE__ */ jsx("kbd", {
2942
- className: cn("ms-auto font-medium font-sans text-muted-foreground/72 text-xs tracking-widest", className),
2943
- "data-slot": "menu-shortcut",
2944
- ...props
2945
- });
2946
- }
2947
2952
  function MenuSub(props) {
2948
- return /* @__PURE__ */ jsx(Menu$1.SubmenuRoot, {
2953
+ return /* @__PURE__ */ jsx(MenuPrimitive.SubmenuRoot, {
2949
2954
  "data-slot": "menu-sub",
2950
2955
  ...props
2951
2956
  });
2952
2957
  }
2953
2958
  function MenuSubTrigger({ className, inset, children, ...props }) {
2954
- return /* @__PURE__ */ jsxs(Menu$1.SubmenuTrigger, {
2955
- className: cn("flex min-h-8 items-center gap-2 rounded-sm px-2 py-1 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-popup-open:bg-accent data-inset:ps-8 data-highlighted:text-accent-foreground data-popup-open:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none", className),
2959
+ return /* @__PURE__ */ jsxs(MenuPrimitive.SubmenuTrigger, {
2960
+ className: cn("flex min-h-8 items-center gap-2 rounded-sm px-2 py-1 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-popup-open:bg-accent data-inset:ps-8 data-highlighted:text-accent-foreground data-popup-open:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&>svg:not(:last-child)]:-mx-0.5 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none", className),
2956
2961
  "data-inset": inset,
2957
2962
  "data-slot": "menu-sub-trigger",
2958
2963
  ...props,
2959
- children: [children, /* @__PURE__ */ jsx(ChevronRightIcon, { className: "-me-0.5 ms-auto opacity-80" })]
2964
+ children: [children, /* @__PURE__ */ jsx(ChevronRightIcon, { className: "ms-auto -me-0.5 opacity-80" })]
2960
2965
  });
2961
2966
  }
2962
2967
  function MenuSubPopup({ className, sideOffset = 0, alignOffset, align = "start", ...props }) {
@@ -4598,6 +4603,20 @@ const typographyFieldNames = [
4598
4603
  "fontWeight"
4599
4604
  ];
4600
4605
 
4606
+ //#endregion
4607
+ //#region src/utils/csrf.ts
4608
+ /**
4609
+ * Récupère le jeton CSRF à partir d'une balise meta dans le DOM.
4610
+ * Standard Laravel : <meta name="csrf-token" content="...">
4611
+ *
4612
+ * @returns Le jeton CSRF sous forme de chaîne, ou null s'il n'est pas trouvé ou si l'exécution n'est pas côté client.
4613
+ */
4614
+ function getCsrfToken() {
4615
+ if (typeof document === "undefined") return null;
4616
+ const meta = document.querySelector("meta[name=\"csrf-token\"]");
4617
+ return meta ? meta.getAttribute("content") : null;
4618
+ }
4619
+
4601
4620
  //#endregion
4602
4621
  //#region src/hooks/useOptimizedImage.tsx
4603
4622
  const BREAKPOINTS = [
@@ -4695,5 +4714,383 @@ function useOptimizedImage(src) {
4695
4714
  }
4696
4715
 
4697
4716
  //#endregion
4698
- export { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, ActionBar_default as ActionBar, AnchoredToastProvider, Badge, Button, Checkbox, ColorPicker, ColorPickerContent, Dialog, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPopup, DialogTitle, DialogTrigger, DrawerItem_default as DrawerItem, Checkbox_default as FieldCheckbox, FieldGroups_default as FieldGroups, Input_default as FieldInput, NumberUnit_default as FieldNumberUnit, Radio_default as FieldRadio, Select_default as FieldSelect, Textarea_default as FieldTextarea, Frame, FrameDescription, FrameFooter, FrameHeader, FramePanel, FrameTitle, GRAY_COLORS, Input, InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, InputGroupTextarea, Label_default as Label, MediaPicker, Menu, MenuCheckboxItem, MenuCreateHandle, MenuGroup, MenuGroupLabel, MenuItem, MenuPopup, MenuPortal, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuShortcut, MenuSub, MenuSubPopup, MenuSubTrigger, MenuTrigger, PREDEFINED_COLORS, PagePicker, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PickerModal, Popover, PopoverClose, PopoverPopup as PopoverContent, PopoverPopup, PopoverCreateHandle, PopoverDescription, PopoverTitle, PopoverTrigger, RadioGroup, RadioGroupItem, RichTextMenuColorPicker, RichTextMenuLink, ScrollArea, ScrollBar, Select, SelectGroup, SelectGroupLabel, SelectItem, SelectPopup, SelectSeparator, SelectTrigger, SelectValue, Separator, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsPanel as TabsContent, TabsPanel, TabsList, TabsTab, TabsTab as TabsTrigger, Textarea, ToastProvider, Tooltip, TooltipPopup, TooltipProvider, TooltipTrigger, anchoredToastManager, animationDefaultProps, animationField, animationToAttributes, badgeVariants, buttonVariants, plugin_default as createPuckOverridesPlugin, createTemplateBlock, customClassesDefaultProps, customClassesField, customClassesToClasses, displayDefaultProps, displayField, displayToClasses, fontWeightDefaultProps, fontWeightField, fontWeightToClasses, getMediaUrl, lineHeightDefaultProps, lineHeightField, lineHeightToClasses, marginDefaultProps, marginField, marginToClasses, paddingDefaultProps, paddingField, paddingToClasses, pageField, positionDefaultProps, positionField, positionToClasses, richTextMenuColorPickerExtension, sizeDefaultProps, sizeField, sizeToClasses, spacingDefaultProps, spacingFieldNames, spacingFields, spacingOptions, spacingToClasses, textAlignDefaultProps, textAlignField, textAlignToClasses, textColorDefaultProps, textColorField, textColorToClasses, textDecorationDefaultProps, textDecorationField, textDecorationToClasses, textSizeDefaultProps, textSizeField, textSizeToClasses, textTransformDefaultProps, textTransformField, textTransformToClasses, toastManager, typographyDefaultProps, typographyFieldNames, typographyFields, typographyToClasses, useMediaUrl, useOptimizedImage, usePageUrl };
4717
+ //#region src/plugins/redactor-assistant/utils/constants.ts
4718
+ const QUICK_ACTIONS = [
4719
+ {
4720
+ label: "Improve",
4721
+ task: "rewrite",
4722
+ instructions: "Improve this text to make it clearer and more engaging."
4723
+ },
4724
+ {
4725
+ label: "Shorten",
4726
+ task: "rewrite",
4727
+ instructions: "Shorten this text while keeping the essential ideas."
4728
+ },
4729
+ {
4730
+ label: "Lengthen",
4731
+ task: "rewrite",
4732
+ instructions: "Expand this text with more details."
4733
+ },
4734
+ {
4735
+ label: "Pro tone",
4736
+ task: "rewrite",
4737
+ instructions: "Rewrite this text with a professional and formal tone."
4738
+ },
4739
+ {
4740
+ label: "SEO",
4741
+ task: "seo",
4742
+ instructions: "Optimize this text for search engines."
4743
+ },
4744
+ {
4745
+ label: "Summarize",
4746
+ task: "summarize",
4747
+ instructions: "Summarize this text in a few concise sentences, capturing the key points."
4748
+ }
4749
+ ];
4750
+
4751
+ //#endregion
4752
+ //#region src/plugins/redactor-assistant/components/RedactorMenuButton.tsx
4753
+ function RedactorMenuButton({ onAction, onGenerate, loading = false }) {
4754
+ return /* @__PURE__ */ jsxs(Menu, { children: [/* @__PURE__ */ jsx(MenuTrigger, {
4755
+ openOnHover: true,
4756
+ render: /* @__PURE__ */ jsx(Button, {
4757
+ size: "icon-sm",
4758
+ title: "AI writing assistance",
4759
+ disabled: loading,
4760
+ children: /* @__PURE__ */ jsx(SparklesIcon, { size: 10 })
4761
+ })
4762
+ }), /* @__PURE__ */ jsxs(MenuPopup, {
4763
+ align: "end",
4764
+ className: "min-w-0!",
4765
+ children: [
4766
+ /* @__PURE__ */ jsx(MenuGroup, { children: /* @__PURE__ */ jsx(MenuItem, {
4767
+ className: "cursor-pointer",
4768
+ onClick: () => onGenerate?.(),
4769
+ children: "Generate"
4770
+ }) }),
4771
+ /* @__PURE__ */ jsx(MenuSeparator, {}),
4772
+ /* @__PURE__ */ jsx(MenuGroup, { children: QUICK_ACTIONS.map((action) => /* @__PURE__ */ jsx(MenuItem, {
4773
+ className: "cursor-pointer",
4774
+ onClick: () => onAction(action.task, action.instructions),
4775
+ children: action.label
4776
+ }, action.label)) })
4777
+ ]
4778
+ })] });
4779
+ }
4780
+
4781
+ //#endregion
4782
+ //#region src/plugins/redactor-assistant/utils/redactorClient.ts
4783
+ const AI_ENDPOINT = "/admin/puck/redactor";
4784
+ const TIMEOUT_MS = 35e3;
4785
+ /**
4786
+ * Appelle l'endpoint Redactor backend. Ne jamais exposer de clé API côté client.
4787
+ */
4788
+ async function callRedactor(request) {
4789
+ const token = getCsrfToken();
4790
+ const controller = new AbortController();
4791
+ const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
4792
+ try {
4793
+ const response = await fetch(AI_ENDPOINT, {
4794
+ method: "POST",
4795
+ headers: {
4796
+ "Content-Type": "application/json",
4797
+ Accept: "application/json",
4798
+ ...token ? { "X-CSRF-TOKEN": token } : {}
4799
+ },
4800
+ body: JSON.stringify(request),
4801
+ credentials: "same-origin",
4802
+ signal: controller.signal
4803
+ });
4804
+ if (!response.ok) {
4805
+ const body = await response.json().catch(() => ({}));
4806
+ throw new Error(body.error || `Erreur serveur (${response.status})`);
4807
+ }
4808
+ const data = await response.json();
4809
+ if (!data.text || typeof data.text !== "string") throw new Error("Réponse Redactor invalide.");
4810
+ return { text: data.text };
4811
+ } catch (error) {
4812
+ if (error.name === "AbortError") throw new Error("La requête Redactor a expiré. Réessayez.");
4813
+ throw error;
4814
+ } finally {
4815
+ clearTimeout(timeoutId);
4816
+ }
4817
+ }
4818
+
4819
+ //#endregion
4820
+ //#region src/plugins/redactor-assistant/utils/buildContext.ts
4821
+ /**
4822
+ * Construit un résumé textuel de la page à partir des données Puck.
4823
+ */
4824
+ function buildPageSummary(data) {
4825
+ if (!data?.content?.length) return "Page vide.";
4826
+ return data.content.map((block, i) => {
4827
+ const textProps = extractTextProps(block.props);
4828
+ const propsStr = textProps.length > 0 ? `: ${textProps.join(", ")}` : "";
4829
+ return `[${i + 1}] ${block.type}${propsStr}`;
4830
+ }).join("\n");
4831
+ }
4832
+ /**
4833
+ * Extrait les propriétés textuelles d'un bloc pour le résumé.
4834
+ */
4835
+ function extractTextProps(props) {
4836
+ const textFields = [];
4837
+ for (const [key, value] of Object.entries(props)) {
4838
+ if (key === "id") continue;
4839
+ if (typeof value === "string" && value.length > 0 && value.length <= 200) {
4840
+ const truncated = value.length > 80 ? value.substring(0, 80) + "…" : value;
4841
+ textFields.push(`${key}="${truncated}"`);
4842
+ }
4843
+ }
4844
+ return textFields;
4845
+ }
4846
+ /**
4847
+ * Construit le contexte AI complet à partir des données Puck et du bloc sélectionné.
4848
+ */
4849
+ function buildContext(data, selectedBlock, brandVoice) {
4850
+ return {
4851
+ pageSummary: buildPageSummary(data),
4852
+ currentBlock: selectedBlock ? {
4853
+ type: selectedBlock.type,
4854
+ props: selectedBlock.props
4855
+ } : null,
4856
+ brandVoice: {
4857
+ tone: brandVoice?.tone ?? "professionnel",
4858
+ language: brandVoice?.language ?? "français"
4859
+ }
4860
+ };
4861
+ }
4862
+
4863
+ //#endregion
4864
+ //#region src/plugins/redactor-assistant/hooks/useRedactor.ts
4865
+ /**
4866
+ * Custom hook to manage the Redactor logic (API calls, loading, error, result).
4867
+ * Encapsulates the core logic for both the sidebar plugin and the richtext button.
4868
+ */
4869
+ function useRedactor() {
4870
+ const [instructions, setInstructions] = useState("");
4871
+ const [loading, setLoading] = useState(false);
4872
+ const [error, setError] = useState(null);
4873
+ const [result, setResult] = useState(null);
4874
+ const [previousValue, setPreviousValue] = useState(null);
4875
+ /**
4876
+ * Call the redactor API to generate or rewrite text.
4877
+ */
4878
+ const generate = async ({ task, taskInstructions, input, appData, currentBlock, outputFormat }) => {
4879
+ setLoading(true);
4880
+ setError(null);
4881
+ setResult(null);
4882
+ try {
4883
+ const context = buildContext(appData, currentBlock);
4884
+ const response = await callRedactor({
4885
+ task,
4886
+ instructions: taskInstructions || instructions,
4887
+ input,
4888
+ context,
4889
+ outputFormat
4890
+ });
4891
+ setResult(response.text);
4892
+ setPreviousValue(input);
4893
+ return response.text;
4894
+ } catch (err) {
4895
+ setError(err.message || "Unknown error.");
4896
+ throw err;
4897
+ } finally {
4898
+ setLoading(false);
4899
+ }
4900
+ };
4901
+ return {
4902
+ instructions,
4903
+ setInstructions,
4904
+ loading,
4905
+ error,
4906
+ setError,
4907
+ result,
4908
+ setResult,
4909
+ previousValue,
4910
+ setPreviousValue,
4911
+ generate
4912
+ };
4913
+ }
4914
+
4915
+ //#endregion
4916
+ //#region src/components/ui/alert.tsx
4917
+ const alertVariants = cva("relative grid w-full items-start gap-x-2 gap-y-0.5 rounded-lg border text-card-foreground text-sm has-[>svg]:has-data-[slot=alert-action]:grid-cols-[calc(var(--spacing)*4)_1fr_auto] has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-data-[slot=alert-action]:grid-cols-[1fr_auto] has-[>svg]:gap-x-2 [&>svg]:h-lh [&>svg]:w-4", {
4918
+ defaultVariants: {
4919
+ size: "default",
4920
+ variant: "default"
4921
+ },
4922
+ variants: {
4923
+ size: {
4924
+ default: "px-3.5 py-3",
4925
+ sm: "px-2.5 py-2 text-xs"
4926
+ },
4927
+ variant: {
4928
+ default: "bg-transparent dark:bg-input/32 [&>svg]:text-muted-foreground",
4929
+ error: "border-destructive/32 bg-destructive/4 [&>svg]:text-destructive",
4930
+ info: "border-info/32 bg-info/4 [&>svg]:text-info",
4931
+ success: "border-success/32 bg-success/4 [&>svg]:text-success",
4932
+ warning: "border-warning/32 bg-warning/4 [&>svg]:text-warning"
4933
+ }
4934
+ }
4935
+ });
4936
+ function Alert({ className, size, variant, ...props }) {
4937
+ return /* @__PURE__ */ jsx("div", {
4938
+ className: cn(alertVariants({
4939
+ size,
4940
+ variant
4941
+ }), className),
4942
+ "data-slot": "alert",
4943
+ role: "alert",
4944
+ ...props
4945
+ });
4946
+ }
4947
+ function AlertTitle({ className, ...props }) {
4948
+ return /* @__PURE__ */ jsx("div", {
4949
+ className: cn("font-medium [svg~&]:col-start-2", className),
4950
+ "data-slot": "alert-title",
4951
+ ...props
4952
+ });
4953
+ }
4954
+ function AlertDescription({ className, ...props }) {
4955
+ return /* @__PURE__ */ jsx("div", {
4956
+ className: cn("flex flex-col gap-2.5 text-muted-foreground [svg~&]:col-start-2", className),
4957
+ "data-slot": "alert-description",
4958
+ ...props
4959
+ });
4960
+ }
4961
+
4962
+ //#endregion
4963
+ //#region src/plugins/redactor-assistant/components/RedactorRichTextButton.tsx
4964
+ const useTypedPuck = createUsePuck();
4965
+ function RedactorRichTextButton({ value, onChange, children, label, field }) {
4966
+ const appState = useTypedPuck((s) => s.appState);
4967
+ const [mode, setMode] = useState(null);
4968
+ const { instructions, setInstructions, loading, error, result, setResult, generate } = useRedactor();
4969
+ const textValue = typeof value === "string" ? value : "";
4970
+ const selectedItem = appState.ui.itemSelector ? appState.data.content?.[appState.ui.itemSelector.index] : null;
4971
+ const handleGenerate = async (task, taskInstructions) => {
4972
+ await generate({
4973
+ task,
4974
+ taskInstructions,
4975
+ input: textValue,
4976
+ appData: appState.data,
4977
+ currentBlock: selectedItem,
4978
+ outputFormat: "html"
4979
+ }).catch(() => {});
4980
+ };
4981
+ const applyResult = () => {
4982
+ if (result === null) return;
4983
+ onChange(result);
4984
+ setResult(null);
4985
+ setMode(null);
4986
+ };
4987
+ const showPanel = loading || mode === "generate" || result !== null || !!error;
4988
+ return /* @__PURE__ */ jsxs("div", { children: [
4989
+ label && /* @__PURE__ */ jsx(Label_default, {
4990
+ label,
4991
+ tooltip: field?.tooltip,
4992
+ action: /* @__PURE__ */ jsx(RedactorMenuButton, {
4993
+ onAction: handleGenerate,
4994
+ onGenerate: () => setMode("generate"),
4995
+ loading
4996
+ })
4997
+ }),
4998
+ /* @__PURE__ */ jsx("div", {
4999
+ className: loading ? "pointer-events-none opacity-60" : "",
5000
+ children
5001
+ }),
5002
+ showPanel && /* @__PURE__ */ jsxs("div", {
5003
+ className: "mt-3 border border-gray-200 rounded-lg bg-muted p-3 flex flex-col gap-y-3",
5004
+ children: [
5005
+ error && /* @__PURE__ */ jsx(Alert, {
5006
+ variant: "error",
5007
+ size: "sm",
5008
+ children: /* @__PURE__ */ jsx(AlertTitle, { children: error })
5009
+ }),
5010
+ loading && /* @__PURE__ */ jsxs("div", {
5011
+ className: "flex items-center justify-center gap-1.5 text-muted-foreground",
5012
+ children: [/* @__PURE__ */ jsx(Loader2Icon, {
5013
+ size: 14,
5014
+ className: "animate-spin"
5015
+ }), /* @__PURE__ */ jsx("span", {
5016
+ className: "text-sm",
5017
+ children: "Generating…"
5018
+ })]
5019
+ }),
5020
+ mode === "generate" && !loading && result === null && /* @__PURE__ */ jsxs("div", {
5021
+ className: "flex flex-col",
5022
+ children: [
5023
+ /* @__PURE__ */ jsx(Label_default, {
5024
+ label: "AI writing assistance",
5025
+ tooltip: "The generated text will fully replace your current content. Your original text will not be preserved."
5026
+ }),
5027
+ /* @__PURE__ */ jsx(Textarea, {
5028
+ value: instructions,
5029
+ onChange: (e) => setInstructions(e.target.value),
5030
+ placeholder: "Ex: Write a short introduction about our services, in a professional tone…",
5031
+ disabled: loading
5032
+ }),
5033
+ /* @__PURE__ */ jsxs("div", {
5034
+ className: "flex justify-end gap-x-2 mt-3",
5035
+ children: [/* @__PURE__ */ jsx(Button, {
5036
+ variant: "outline",
5037
+ onClick: () => setMode(null),
5038
+ disabled: loading,
5039
+ children: "Cancel"
5040
+ }), /* @__PURE__ */ jsx(Button, {
5041
+ variant: "default",
5042
+ onClick: () => handleGenerate(textValue ? "rewrite" : "generate", instructions),
5043
+ disabled: loading,
5044
+ children: "Generate"
5045
+ })]
5046
+ })
5047
+ ]
5048
+ }),
5049
+ result !== null && !loading && /* @__PURE__ */ jsxs("div", {
5050
+ className: "flex flex-col",
5051
+ children: [/* @__PURE__ */ jsx(Alert, {
5052
+ variant: "success",
5053
+ size: "sm",
5054
+ children: /* @__PURE__ */ jsx(AlertDescription, {
5055
+ className: "max-h-[150px] overflow-auto",
5056
+ dangerouslySetInnerHTML: { __html: result }
5057
+ })
5058
+ }), /* @__PURE__ */ jsxs("div", {
5059
+ className: "flex justify-end gap-x-2 mt-3",
5060
+ children: [/* @__PURE__ */ jsx(Button, {
5061
+ variant: "outline",
5062
+ onClick: () => setResult(null),
5063
+ children: "Ignore"
5064
+ }), /* @__PURE__ */ jsx(Button, {
5065
+ variant: "default",
5066
+ onClick: applyResult,
5067
+ children: "Apply"
5068
+ })]
5069
+ })]
5070
+ })
5071
+ ]
5072
+ })
5073
+ ] });
5074
+ }
5075
+
5076
+ //#endregion
5077
+ //#region src/plugins/redactor-assistant/index.tsx
5078
+ createUsePuck();
5079
+ function createRedactorPlugin() {
5080
+ return {
5081
+ name: "redactor-assistant",
5082
+ overrides: { fieldTypes: { richtext: ({ children, onChange, value, field, label }) => {
5083
+ return /* @__PURE__ */ jsx(RedactorRichTextButton, {
5084
+ value,
5085
+ onChange,
5086
+ label,
5087
+ field,
5088
+ children: React.cloneElement(children, { Label: ({ children: c }) => /* @__PURE__ */ jsx(Fragment, { children: c }) })
5089
+ });
5090
+ } } }
5091
+ };
5092
+ }
5093
+
5094
+ //#endregion
5095
+ export { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, ActionBar_default as ActionBar, AnchoredToastProvider, Badge, Button, Checkbox, ColorPicker, ColorPickerContent, Dialog, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPopup, DialogTitle, DialogTrigger, DrawerItem_default as DrawerItem, Checkbox_default as FieldCheckbox, FieldGroups_default as FieldGroups, Input_default as FieldInput, NumberUnit_default as FieldNumberUnit, Radio_default as FieldRadio, Select_default as FieldSelect, Textarea_default as FieldTextarea, Frame, FrameDescription, FrameFooter, FrameHeader, FramePanel, FrameTitle, GRAY_COLORS, Input, InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, InputGroupTextarea, Label_default as Label, MediaPicker, Menu, MenuCheckboxItem, MenuGroup, MenuGroupLabel, MenuItem, MenuPopup, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSub, MenuSubPopup, MenuSubTrigger, MenuTrigger, PREDEFINED_COLORS, PagePicker, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PickerModal, Popover, PopoverClose, PopoverPopup as PopoverContent, PopoverPopup, PopoverCreateHandle, PopoverDescription, PopoverTitle, PopoverTrigger, RadioGroup, RadioGroupItem, RichTextMenuColorPicker, RichTextMenuLink, ScrollArea, ScrollBar, Select, SelectGroup, SelectGroupLabel, SelectItem, SelectPopup, SelectSeparator, SelectTrigger, SelectValue, Separator, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsPanel as TabsContent, TabsPanel, TabsList, TabsTab, TabsTab as TabsTrigger, Textarea, ToastProvider, Tooltip, TooltipPopup, TooltipProvider, TooltipTrigger, anchoredToastManager, animationDefaultProps, animationField, animationToAttributes, badgeVariants, buttonVariants, plugin_default as createPuckOverridesPlugin, createRedactorPlugin, createTemplateBlock, customClassesDefaultProps, customClassesField, customClassesToClasses, displayDefaultProps, displayField, displayToClasses, fontWeightDefaultProps, fontWeightField, fontWeightToClasses, getCsrfToken, getMediaUrl, lineHeightDefaultProps, lineHeightField, lineHeightToClasses, marginDefaultProps, marginField, marginToClasses, paddingDefaultProps, paddingField, paddingToClasses, pageField, positionDefaultProps, positionField, positionToClasses, richTextMenuColorPickerExtension, sizeDefaultProps, sizeField, sizeToClasses, spacingDefaultProps, spacingFieldNames, spacingFields, spacingOptions, spacingToClasses, textAlignDefaultProps, textAlignField, textAlignToClasses, textColorDefaultProps, textColorField, textColorToClasses, textDecorationDefaultProps, textDecorationField, textDecorationToClasses, textSizeDefaultProps, textSizeField, textSizeToClasses, textTransformDefaultProps, textTransformField, textTransformToClasses, toastManager, typographyDefaultProps, typographyFieldNames, typographyFields, typographyToClasses, useMediaUrl, useOptimizedImage, usePageUrl };
4699
5096
  //# sourceMappingURL=index.js.map