import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
import { Component, useEnvironment, useDesugaredRelativeSingleField, VariableInputTransformer, HasMany, SugaredField, BindingError } from "@contember/react-binding";
import { emptyArray, useReferentiallyStableCallback, noop } from "@contember/react-utils";
import { FieldContainer, EditorCanvas } from "@contember/ui";
import { useMemo, useState, useCallback, useLayoutEffect, Fragment as Fragment$1 } from "react";
import { Range, Transforms } from "slate";
import { Slate } from "slate-react";
import { TextareaField } from "@contember/react-form-fields-ui";
import { shouldCancelStart } from "@contember/utilities";
import { EditableCanvas } from "../baseEditor/EditableCanvas.js";
import { RichEditor } from "../RichEditor.js";
import { BlockHoveringToolbarContents } from "./BlockHoveringToolbarContents.js";
import { ReferencesProvider } from "./references/ReferencesProvider.js";
import { useGetReferencedEntity } from "./references/useGetReferencedEntity.js";
import { useInsertElementWithReference } from "./references/useInsertElementWithReference.js";
import { SortedBlocksContext } from "./state/SortedBlocksContext.js";
import { useBlockEditorState } from "./state/useBlockEditorState.js";
import { useEditorReferenceBlocks } from "./templating/useEditorReferenceBlocks.js";
import { useCreateElementReference } from "./references/useCreateElementReference.js";
import { initBlockEditor } from "./editor/initBlockEditor.js";
import { SortableRepeaterContainer } from "../../collections/Repeater/SortableRepeaterContainer.js";
import { ContentOutlet } from "./templating/ContentOutlet.js";
import { RichTextField } from "../RichTextField/RichTextField.js";
import { useDiscriminatedData } from "../../discrimination/useDiscriminatedData.js";
import { useNormalizedBlocks } from "../../blocks/useNormalizedBlocks.js";
import { getDiscriminatedBlock } from "../../blocks/getDiscriminatedBlock.js";
import { createEditorWithEssentials } from "../baseEditor/createEditorWithEssentials.js";
import { paragraphElementType } from "../plugins/element/paragraphs/ParagraphElement.js";
import { HoveringToolbars } from "../toolbars/HoveringToolbars.js";
import { Repeater } from "../../collections/Repeater/Repeater.js";
const BlockEditorComponent = Component(
  (props) => {
    const environment = useEnvironment();
    assertStaticBlockEditorInvariants(props);
    const {
      contentField,
      label,
      placeholder,
      sortableBy,
      children,
      size,
      leadingFieldBackedElements = emptyArray,
      trailingFieldBackedElements = emptyArray,
      referencesField,
      referenceDiscriminationField,
      monolithicReferencesMode = false,
      embedReferenceDiscriminateBy,
      embedContentDiscriminationField,
      embedHandlers = emptyArray,
      toolbarScheme,
      inlineButtons = defaultInlineButtons,
      blockButtons,
      otherBlockButtons,
      showToolbarLabels,
      plugins,
      augmentEditor,
      augmentEditorBuiltins,
      ...blockListProps
    } = props;
    const desugaredReferenceDiscriminationField = useDesugaredRelativeSingleField(referenceDiscriminationField);
    const desugaredEmbedContentDiscriminationField = useDesugaredRelativeSingleField(embedContentDiscriminationField);
    const editorReferenceBlocks = useEditorReferenceBlocks(children);
    const discriminatedEmbedHandlers = useDiscriminatedData(embedHandlers);
    const embedReferenceDiscriminant = useMemo(() => {
      if (embedReferenceDiscriminateBy !== void 0) {
        return VariableInputTransformer.transformValue(embedReferenceDiscriminateBy, environment);
      }
      return void 0;
    }, [embedReferenceDiscriminateBy, environment]);
    const embedSubBlocks = useNormalizedBlocks(
      embedReferenceDiscriminant !== void 0 ? getDiscriminatedBlock(editorReferenceBlocks, embedReferenceDiscriminant)?.datum.children : void 0
      // TODO this may crash
    );
    const [baseEditor] = useState(() => createEditorWithEssentials(paragraphElementType));
    const { nodes, onChange, sortedBlocksRef, refreshBlocks } = useBlockEditorState({
      editor: baseEditor,
      blockList: blockListProps,
      contentField,
      sortableBy,
      monolithicReferencesMode,
      referencesField
    });
    const getReferencedEntity = useGetReferencedEntity({
      monolithicReferencesMode,
      referencesField,
      sortedBlocksRef
    });
    const createElementReference = useCreateElementReference({
      sortedBlocksRef,
      monolithicReferencesMode,
      referenceDiscriminationField,
      referencesField,
      refreshBlocks
    });
    const stableCreateElementReference = useReferentiallyStableCallback(createElementReference);
    const insertElementWithReference = useInsertElementWithReference({
      editor: baseEditor,
      createElementReference: stableCreateElementReference
    });
    const stableGetReferencedEntity = useReferentiallyStableCallback(getReferencedEntity);
    const [editor] = useState(() => initBlockEditor({
      editor: baseEditor,
      augmentEditor,
      augmentEditorBuiltins,
      editorReferenceBlocks,
      embedContentDiscriminationField: desugaredEmbedContentDiscriminationField,
      embedHandlers: discriminatedEmbedHandlers,
      embedReferenceDiscriminateBy: embedReferenceDiscriminant,
      embedSubBlocks,
      plugins,
      referenceDiscriminationField: desugaredReferenceDiscriminationField,
      createElementReferences: stableCreateElementReference,
      getReferencedEntity: stableGetReferencedEntity,
      insertElementWithReference
    }));
    const shouldDisplayInlineToolbar = useCallback(() => {
      const selection = baseEditor.selection;
      return !(!selection || Range.isCollapsed(selection));
    }, [baseEditor]);
    const leadingElements = useFieldBackedElementFields(leadingFieldBackedElements);
    const trailingElements = useFieldBackedElementFields(trailingFieldBackedElements);
    const [_, setMeaninglessState] = useState(0);
    useLayoutEffect(() => {
      if (editor.children !== nodes && JSON.stringify(editor.children) !== JSON.stringify(nodes)) {
        editor.children = nodes;
        setMeaninglessState((meaninglessState) => meaninglessState + 1);
      }
    }, [nodes, editor]);
    return /* @__PURE__ */ jsxDEV(FieldContainer, { label, useLabelElement: false, children: /* @__PURE__ */ jsxDEV(ReferencesProvider, { getReferencedEntity, children: /* @__PURE__ */ jsxDEV(SortedBlocksContext.Provider, { value: sortedBlocksRef.current, children: /* @__PURE__ */ jsxDEV(
      SortableRepeaterContainer,
      {
        axis: "y",
        lockAxis: "y",
        helperClass: "is-dragged",
        lockToContainerEdges: true,
        useWindowAsScrollContainer: true,
        useDragHandle: true,
        onSortEnd: useCallback((data) => {
          Transforms.moveNodes(editor, {
            at: [data.oldIndex],
            to: [data.newIndex]
          });
        }, [editor]),
        shouldCancelStart,
        children: /* @__PURE__ */ jsxDEV(Slate, { editor, value: nodes, onChange, children: /* @__PURE__ */ jsxDEV(
          EditorCanvas,
          {
            inset: "hovering-toolbar",
            underlyingComponent: EditableCanvas,
            componentProps: {
              renderElement: baseEditor.renderElement,
              renderLeaf: baseEditor.renderLeaf,
              onKeyDown: baseEditor.onKeyDown,
              onFocusCapture: baseEditor.onFocus,
              onBlurCapture: baseEditor.onBlur,
              onDOMBeforeInput: baseEditor.onDOMBeforeInput,
              onDrop: (e) => {
                e.preventDefault();
              },
              placeholder,
              leading: leadingElements,
              trailing: trailingElements
            },
            size: size ?? "large",
            children: useMemo(
              () => /* @__PURE__ */ jsxDEV(
                HoveringToolbars,
                {
                  toolbarScheme,
                  shouldDisplayInlineToolbar,
                  inlineButtons,
                  showLabels: showToolbarLabels,
                  blockButtons: /* @__PURE__ */ jsxDEV(
                    BlockHoveringToolbarContents,
                    {
                      editorReferenceBlocks,
                      blockButtons,
                      otherBlockButtons,
                      showLabels: showToolbarLabels
                    },
                    void 0,
                    false,
                    {
                      fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
                      lineNumber: 251,
                      columnNumber: 14
                    },
                    void 0
                  )
                },
                void 0,
                false,
                {
                  fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
                  lineNumber: 245,
                  columnNumber: 12
                },
                void 0
              ),
              [blockButtons, editorReferenceBlocks, inlineButtons, otherBlockButtons, shouldDisplayInlineToolbar, showToolbarLabels, toolbarScheme]
            )
          },
          void 0,
          false,
          {
            fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
            lineNumber: 223,
            columnNumber: 9
          },
          void 0
        ) }, void 0, false, {
          fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
          lineNumber: 222,
          columnNumber: 8
        }, void 0)
      },
      void 0,
      false,
      {
        fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
        lineNumber: 207,
        columnNumber: 7
      },
      void 0
    ) }, void 0, false, {
      fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
      lineNumber: 206,
      columnNumber: 6
    }, void 0) }, void 0, false, {
      fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
      lineNumber: 205,
      columnNumber: 5
    }, void 0) }, void 0, false, {
      fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
      lineNumber: 204,
      columnNumber: 4
    }, void 0);
  },
  (props, environment) => {
    assertStaticBlockEditorInvariants(props);
    const embedHandlers = Array.from(props.embedHandlers || []);
    const inlineButtons = props.inlineButtons ? (Array.isArray(props.inlineButtons[0]) ? props.inlineButtons : [props.inlineButtons]).flat() : emptyArray;
    const references = !!(props.referencesField && props.referenceDiscriminationField) && /* @__PURE__ */ jsxDEV(
      HasMany,
      {
        ...typeof props.referencesField === "string" ? { field: props.referencesField } : props.referencesField,
        initialEntityCount: 0,
        children: [
          inlineButtons.filter((button) => "referenceContent" in button).map(({ referenceContent: Content }, i) => {
            return /* @__PURE__ */ jsxDEV(Content, { referenceId: "", editor: 0, selection: null, onSuccess: noop, onCancel: noop }, i, false, {
              fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
              lineNumber: 290,
              columnNumber: 8
            }, void 0);
          }),
          /* @__PURE__ */ jsxDEV(SugaredField, { field: props.referenceDiscriminationField }, void 0, false, {
            fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
            lineNumber: 293,
            columnNumber: 5
          }, void 0),
          props.children,
          props.embedContentDiscriminationField && /* @__PURE__ */ jsxDEV(Fragment, { children: [
            /* @__PURE__ */ jsxDEV(SugaredField, { field: props.embedContentDiscriminationField }, void 0, false, {
              fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
              lineNumber: 297,
              columnNumber: 7
            }, void 0),
            embedHandlers.map((handler, i) => /* @__PURE__ */ jsxDEV(Fragment$1, { children: handler.staticRender(environment) }, i, false, {
              fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
              lineNumber: 299,
              columnNumber: 8
            }, void 0))
          ] }, void 0, true, {
            fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
            lineNumber: 296,
            columnNumber: 6
          }, void 0)
        ]
      },
      void 0,
      true,
      {
        fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
        lineNumber: 282,
        columnNumber: 4
      },
      void 0
    );
    return /* @__PURE__ */ jsxDEV(Fragment, { children: [
      props.leadingFieldBackedElements?.map((item, i) => "element" in item ? /* @__PURE__ */ jsxDEV(Fragment$1, { children: item.element }, `leading_${i}`, false, {
        fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
        lineNumber: 309,
        columnNumber: 26
      }, void 0) : /* @__PURE__ */ jsxDEV(SugaredField, { field: item.field }, `leading_${i}`, false, {
        fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
        lineNumber: 309,
        columnNumber: 85
      }, void 0)),
      props.trailingFieldBackedElements?.map((item, i) => "element" in item ? /* @__PURE__ */ jsxDEV(Fragment$1, { children: item.element }, `trailing_${i}`, false, {
        fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
        lineNumber: 312,
        columnNumber: 26
      }, void 0) : /* @__PURE__ */ jsxDEV(SugaredField, { field: item.field }, `trailing_${i}`, false, {
        fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
        lineNumber: 312,
        columnNumber: 86
      }, void 0)),
      /* @__PURE__ */ jsxDEV(Repeater, { ...props, label: props.label ?? "", initialEntityCount: 0, children: [
        /* @__PURE__ */ jsxDEV(SugaredField, { field: props.sortableBy }, void 0, false, {
          fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
          lineNumber: 315,
          columnNumber: 6
        }, void 0),
        /* @__PURE__ */ jsxDEV(SugaredField, { field: props.contentField }, void 0, false, {
          fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
          lineNumber: 316,
          columnNumber: 6
        }, void 0),
        !props.monolithicReferencesMode && references
      ] }, void 0, true, {
        fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
        lineNumber: 314,
        columnNumber: 5
      }, void 0),
      props.monolithicReferencesMode && references
    ] }, void 0, true, {
      fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
      lineNumber: 307,
      columnNumber: 4
    }, void 0);
  },
  "BlockEditor"
);
const BlockEditor = Object.assign(BlockEditorComponent, {
  ContentOutlet
});
const useFieldBackedElementFields = (elements) => {
  return /* @__PURE__ */ jsxDEV(Fragment, { children: elements.map((el, i) => {
    if ("element" in el) {
      return /* @__PURE__ */ jsxDEV(Fragment$1, { children: el.element }, i, false, {
        fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
        lineNumber: 345,
        columnNumber: 12
      }, void 0);
    }
    if (el.format === "plainText") {
      return /* @__PURE__ */ jsxDEV(
        TextareaField,
        {
          distinction: "seamless",
          field: el.field,
          label: void 0,
          placeholder: el.placeholder,
          size: el.size
        },
        i,
        false,
        {
          fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
          lineNumber: 349,
          columnNumber: 6
        },
        void 0
      );
    }
    return /* @__PURE__ */ jsxDEV(RichTextField, { field: el.field, label: void 0, placeholder: el.placeholder, distinction: el.distinction ?? "seamless" }, i, false, {
      fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
      lineNumber: 359,
      columnNumber: 11
    }, void 0);
  }) }, void 0, false, {
    fileName: "/__w/interface/interface/packages/admin/src/components/bindingFacade/richText/blockEditor/BlockEditor.tsx",
    lineNumber: 342,
    columnNumber: 9
  }, void 0);
};
const assertStaticBlockEditorInvariants = (props, environment) => {
  {
    if (props.referencesField !== void 0 && props.referenceDiscriminationField === void 0) {
      throw new BindingError(
        `BlockEditor: missing the 'referenceDiscriminationField' prop. Without it the editor cannot tell different kinds of references apart!`
      );
    }
    if (props.referencesField === void 0 && props.referenceDiscriminationField !== void 0) {
      throw new BindingError(
        `BlockEditor: supplied the 'referenceDiscriminationField' prop but missing 'referencesField'. Either remove 'referenceDiscriminationField' to get rid of this error or provide 'referencesField' to enable content references.`
      );
    }
    if (props.referencesField !== void 0 && (props.embedReferenceDiscriminateBy === void 0 || props.embedContentDiscriminationField === void 0 || props.embedHandlers === void 0) && (props.embedReferenceDiscriminateBy !== void 0 || props.embedContentDiscriminationField !== void 0 || props.embedHandlers !== void 0)) {
      throw new BindingError(
        `BlockEditor: trying to enable embeds without content references being enabled. In order to use embeds, provide both the 'referenceDiscriminationField' as well as the 'referencesField' prop`
      );
    }
    if (props.embedReferenceDiscriminateBy !== void 0) {
      if (props.embedContentDiscriminationField === void 0) {
        throw new BindingError(
          `BlockEditor: You enabled embed blocks by supplying the 'embedReferenceDiscriminateBy' prop but then failed to also supply the 'embedContentDiscriminationField'. Without it, the editor would not be able to distinguish between the kinds of embedded content.`
        );
      }
      if (!props.embedHandlers || Array.from(props.embedHandlers).length === 0) {
        throw new BindingError(
          `BlockEditor: You enabled embed blocks by supplying the 'embedReferenceDiscriminateBy' prop but then failed to also supply any embed handlers. Without them, the editor would not be able to recognize any embedded content.`
        );
      }
    }
  }
};
const RB = RichEditor.buttons;
const defaultInlineButtons = [
  [RB.bold, RB.italic, RB.underline, RB.anchor],
  [RB.headingOne, RB.headingTwo],
  [RB.strikeThrough, RB.code]
];
export {
  BlockEditor
};
//# sourceMappingURL=BlockEditor.js.map
