Skip to content

Commit

Permalink
Remove link element from disclaimer embed toolbar + add warning indic…
Browse files Browse the repository at this point in the history
…ating if disclaimer is copied from other language version
  • Loading branch information
katrinewi committed Jan 16, 2025
1 parent 3e1b8eb commit 988cb27
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 102 deletions.
6 changes: 3 additions & 3 deletions src/components/SlateEditor/plugins/link/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const StyledPopoverContent = styled(PopoverContent, {
base: {
flexDirection: "row",
gap: "xsmall",
zIndex: "modal",
zIndex: "dropdown",
},
});

Expand Down Expand Up @@ -142,9 +142,9 @@ const Link = ({ attributes, editor, element, children }: Props) => {
};

return (
<DialogRoot open={editMode} onOpenChange={(details) => toggleEditMode(details.open)} context="alert">
<DialogRoot open={editMode} onOpenChange={(details) => toggleEditMode(details.open)}>
<PopoverRoot
modal
modal={false}
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus={false}
onOpenChange={(details) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,100 +6,38 @@
*
*/

import { TextArea, Text, FieldRoot, FieldHelper, FieldErrorMessage } from "@ndla/primitives";
import { TextArea, FieldRoot, FieldHelper, FieldErrorMessage } from "@ndla/primitives";
import { styled } from "@ndla/styled-system/jsx";
import { ContentEditableFieldLabel } from "../../../Form/ContentEditableFieldLabel";
import { FieldWarning } from "../../../Form/FieldWarning";
import { FormField } from "../../../FormField";
import { SlatePlugin } from "../../interfaces";
import RichTextEditor from "../../RichTextEditor";
import { RichTextIndicator } from "../../RichTextIndicator";
import { breakPlugin } from "../break";
import { breakRenderer } from "../break/render";
import { linkPlugin } from "../link";
import { linkRenderer } from "../link/render";
import { markPlugin } from "../mark";
import { markRenderer } from "../mark/render";
import { noopPlugin } from "../noop";
import { noopRenderer } from "../noop/render";
import { paragraphPlugin } from "../paragraph";
import { paragraphRenderer } from "../paragraph/render";
import saveHotkeyPlugin from "../saveHotkey";
import { spanPlugin } from "../span";
import { spanRenderer } from "../span/render";
import { textTransformPlugin } from "../textTransform";
import { toolbarPlugin } from "../toolbar";
import { createToolbarAreaOptions, createToolbarDefaultValues } from "../toolbar/toolbarState";

const toolbarOptions = createToolbarDefaultValues({
text: {
hidden: true,
},
mark: {
code: {
hidden: true,
},
},
block: { hidden: true },
inline: {
hidden: true,
"content-link": { hidden: false },
},
});
import { CategoryFilters, createToolbarAreaOptions } from "../toolbar/toolbarState";

export const toolbarAreaFilters = createToolbarAreaOptions();

export const disclaimerPlugins: SlatePlugin[] = [
spanPlugin,
paragraphPlugin,
toolbarPlugin(toolbarOptions, toolbarAreaFilters),
textTransformPlugin,
breakPlugin,
saveHotkeyPlugin,
markPlugin,
noopPlugin,
linkPlugin,
];

const renderers: SlatePlugin[] = [
noopRenderer,
paragraphRenderer,
markRenderer,
breakRenderer,
spanRenderer,
linkRenderer,
];

const plugins = disclaimerPlugins.concat(renderers);

const StyledTextArea = styled(TextArea, {
base: {
minHeight: "surface.3xsmall",
height: "unset",
},
});

const StyledText = styled(Text, {
base: {
width: "unset!",
top: "xsmall!",
},
});

interface Props {
submitted: boolean;
title: string;
description: string;
plugins: SlatePlugin[];
toolbarOptions: CategoryFilters;
}

export const DisclaimerField = ({ submitted, title, description }: Props) => {
export const DisclaimerField = ({ submitted, title, description, plugins, toolbarOptions }: Props) => {
return (
<FormField name="disclaimer">
{({ field, meta, helpers }) => (
<FieldRoot invalid={!!meta.error}>
<ContentEditableFieldLabel>
{title}
<RichTextIndicator />
</ContentEditableFieldLabel>
<ContentEditableFieldLabel>{title}</ContentEditableFieldLabel>
<FieldHelper textStyle="body.medium">{description}</FieldHelper>
<StyledTextArea asChild>
<RichTextEditor
Expand All @@ -111,14 +49,10 @@ export const DisclaimerField = ({ submitted, title, description }: Props) => {
toolbarOptions={toolbarOptions}
toolbarAreaFilters={toolbarAreaFilters}
noArticleStyling
renderPlaceholder={(placeholder) => (
<StyledText {...placeholder.attributes} textStyle="body.article" asChild consumeCss>
<span>{placeholder.children}</span>
</StyledText>
)}
data-testid="disclaimer-editor"
/>
</StyledTextArea>
<FieldWarning name={field.name} />
<FieldErrorMessage>{meta.error}</FieldErrorMessage>
</FieldRoot>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,55 @@ import { useTranslation } from "react-i18next";
import { Descendant } from "slate";
import { Button, DialogBody } from "@ndla/primitives";
import { UuDisclaimerEmbedData } from "@ndla/types-embed";
import { DisclaimerField } from "./DisclaimerField";
import { DisclaimerField, toolbarAreaFilters } from "./DisclaimerField";
import { inlineContentToEditorValue, inlineContentToHTML } from "../../../../util/articleContentConverter";
import { FormActionsContainer, FormikForm } from "../../../FormikForm";
import validateFormik, { RulesType } from "../../../formikValidationSchema";
import { SlatePlugin } from "../../interfaces";
import { breakPlugin } from "../break";
import { breakRenderer } from "../break/render";
import { markPlugin } from "../mark";
import { markRenderer } from "../mark/render";
import { noopPlugin } from "../noop";
import { noopRenderer } from "../noop/render";
import { paragraphPlugin } from "../paragraph";
import { paragraphRenderer } from "../paragraph/render";
import saveHotkeyPlugin from "../saveHotkey";
import { spanPlugin } from "../span";
import { spanRenderer } from "../span/render";
import { textTransformPlugin } from "../textTransform";
import { toolbarPlugin } from "../toolbar";
import { createToolbarDefaultValues } from "../toolbar/toolbarState";

const toolbarOptions = createToolbarDefaultValues({
text: {
hidden: true,
},
mark: {
code: {
hidden: true,
},
},
block: { hidden: true },
inline: {
hidden: true,
},
});

export const disclaimerPlugins: SlatePlugin[] = [
spanPlugin,
paragraphPlugin,
toolbarPlugin(toolbarOptions, toolbarAreaFilters),
textTransformPlugin,
breakPlugin,
saveHotkeyPlugin,
markPlugin,
noopPlugin,
];

const renderers: SlatePlugin[] = [noopRenderer, paragraphRenderer, markRenderer, breakRenderer, spanRenderer];

const plugins = disclaimerPlugins.concat(renderers);

interface DisclaimerFormProps {
initialData?: UuDisclaimerEmbedData;
Expand Down Expand Up @@ -71,6 +116,8 @@ const DisclaimerForm = ({ initialData, onOpenChange, onSave }: DisclaimerFormPro
submitted={isSubmitting}
title={t("form.disclaimer.editorHeader")}
description={t("form.disclaimer.description")}
toolbarOptions={toolbarOptions}
plugins={plugins}
/>
<FormActionsContainer>
<Button onClick={() => onOpenChange(false)} variant="secondary">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,22 @@
*
*/

import parse from "html-react-parser";
import { ReactNode, useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Editor, Element, Path, Transforms } from "slate";
import { ReactEditor, RenderElementProps } from "slate-react";
import { Portal } from "@ark-ui/react";
import { transform } from "@ndla/article-converter";
import { PencilFill } from "@ndla/icons";
import { DialogContent, DialogHeader, DialogRoot, DialogTitle, DialogTrigger, IconButton } from "@ndla/primitives";
import { styled } from "@ndla/styled-system/jsx";
import { UuDisclaimerEmbedData, UuDisclaimerMetaData } from "@ndla/types-embed";
import { EmbedWrapper, UuDisclaimerEmbed } from "@ndla/ui";
import DisclaimerForm from "./DisclaimerForm";
import { DisclaimerElement, TYPE_DISCLAIMER } from "./types";
import { usePreviewArticle } from "../../../../modules/article/articleGqlQueries";
import DeleteButton from "../../../DeleteButton";
import { DialogCloseButton } from "../../../DialogCloseButton";
import MoveContentButton from "../../../MoveContentButton";
import { useArticleLanguage } from "../../ArticleLanguageProvider";

interface Props {
attributes: RenderElementProps["attributes"];
Expand Down Expand Up @@ -61,26 +59,18 @@ const SlateDisclaimer = ({ attributes, children, element, editor }: Props) => {
setModalOpen(!!element.isFirstEdit);
}, [element.isFirstEdit]);

const articleLanguage = useArticleLanguage();

const articleContentData = usePreviewArticle(element.data?.disclaimer, articleLanguage, undefined, false, {
enabled: !!element.data?.disclaimer.length,
});

const transformedContent = useMemo(() => {
return transform(articleContentData?.data ?? "", {});
}, [articleContentData?.data]);

const embed: UuDisclaimerMetaData | undefined = useMemo(() => {
if (!element.data) return undefined;

const parsedContent = element.data?.disclaimer ? (parse(element.data?.disclaimer) as string) : "";

return {
status: "success",
data: { transformedContent: "" },
data: { transformedContent: parsedContent },
embedData: element.data,
resource: "uu-disclaimer",
};
}, [element]);
}, [element.data]);

const onOpenChange = useCallback(
(open: boolean) => {
Expand Down Expand Up @@ -152,14 +142,9 @@ const SlateDisclaimer = ({ attributes, children, element, editor }: Props) => {
);

return (
<DialogRoot
open={modalOpen}
onOpenChange={(details) => onOpenChange(details.open)}
onInteractOutside={(e) => e.preventDefault()}
onPointerDownOutside={() => onOpenChange(false)}
>
<DialogRoot open={modalOpen} onOpenChange={(details) => setModalOpen(details.open)}>
<StyledEmbedWrapper data-testid="slate-disclaimer-block" {...attributes}>
{!!embed && !!transformedContent && (
{!!embed && (
<>
<ButtonContainer contentEditable={false}>
<DeleteButton aria-label={t("delete")} data-testid="delete-disclaimer" onClick={handleDelete} />
Expand All @@ -180,7 +165,7 @@ const SlateDisclaimer = ({ attributes, children, element, editor }: Props) => {
onMouseDown={handleRemoveDisclaimer}
/>
</ButtonContainer>
<UuDisclaimerEmbed transformedDisclaimer={transformedContent} embed={{ ...embed }}>
<UuDisclaimerEmbed transformedDisclaimer={embed.data.transformedContent} embed={{ ...embed }}>
{children}
</UuDisclaimerEmbed>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ const translateFields: TranslateType[] = [
field: "tags.tags",
type: "text",
},
{
field: "disclaimer.disclaimer",
type: "html",
},
];

const EditLearningResource = ({ isNewlyCreated }: Props) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,28 @@ import LearningResourceTaxonomy from "./LearningResourceTaxonomy";
import FormAccordion from "../../../../components/Accordion/FormAccordion";
import FormAccordions from "../../../../components/Accordion/FormAccordions";
import QualityEvaluation from "../../../../components/QualityEvaluation/QualityEvaluation";
import { SlatePlugin } from "../../../../components/SlateEditor/interfaces";
import { IsNewArticleLanguageProvider } from "../../../../components/SlateEditor/IsNewArticleLanguageProvider";
import { DisclaimerField } from "../../../../components/SlateEditor/plugins/uuDisclaimer/DisclaimerField";
import { breakPlugin } from "../../../../components/SlateEditor/plugins/break";
import { breakRenderer } from "../../../../components/SlateEditor/plugins/break/render";
import { linkPlugin } from "../../../../components/SlateEditor/plugins/link";
import { linkRenderer } from "../../../../components/SlateEditor/plugins/link/render";
import { markPlugin } from "../../../../components/SlateEditor/plugins/mark";
import { markRenderer } from "../../../../components/SlateEditor/plugins/mark/render";
import { noopPlugin } from "../../../../components/SlateEditor/plugins/noop";
import { noopRenderer } from "../../../../components/SlateEditor/plugins/noop/render";
import { paragraphPlugin } from "../../../../components/SlateEditor/plugins/paragraph";
import { paragraphRenderer } from "../../../../components/SlateEditor/plugins/paragraph/render";
import saveHotkeyPlugin from "../../../../components/SlateEditor/plugins/saveHotkey";
import { spanPlugin } from "../../../../components/SlateEditor/plugins/span";
import { spanRenderer } from "../../../../components/SlateEditor/plugins/span/render";
import { textTransformPlugin } from "../../../../components/SlateEditor/plugins/textTransform";
import { toolbarPlugin } from "../../../../components/SlateEditor/plugins/toolbar";
import { createToolbarDefaultValues } from "../../../../components/SlateEditor/plugins/toolbar/toolbarState";
import {
DisclaimerField,
toolbarAreaFilters,
} from "../../../../components/SlateEditor/plugins/uuDisclaimer/DisclaimerField";
import config from "../../../../config";
import { STORED_HIDE_COMMENTS, TAXONOMY_WRITE_SCOPE } from "../../../../constants";
import { CopyrightFieldGroup, VersionAndNotesPanel, MetaDataField } from "../../../FormikForm";
Expand All @@ -33,6 +53,45 @@ import RelatedContentFieldGroup from "../../components/RelatedContentFieldGroup"
import RevisionNotes from "../../components/RevisionNotes";
import { FlatArticleKeys } from "../../components/types";

const toolbarOptions = createToolbarDefaultValues({
text: {
hidden: true,
},
mark: {
code: {
hidden: true,
},
},
block: { hidden: true },
inline: {
hidden: true,
"content-link": { hidden: false },
},
});

export const disclaimerPlugins: SlatePlugin[] = [
spanPlugin,
paragraphPlugin,
toolbarPlugin(toolbarOptions, toolbarAreaFilters),
textTransformPlugin,
breakPlugin,
saveHotkeyPlugin,
markPlugin,
noopPlugin,
linkPlugin,
];

const renderers: SlatePlugin[] = [
noopRenderer,
paragraphRenderer,
markRenderer,
breakRenderer,
spanRenderer,
linkRenderer,
];

const plugins = disclaimerPlugins.concat(renderers);

const StyledWrapper = styled("div", {
base: {
display: "grid",
Expand Down Expand Up @@ -191,6 +250,8 @@ const LearningResourcePanels = ({
submitted={submitted}
title={t("form.articleDisclaimer.title")}
description={t("form.articleDisclaimer.description")}
plugins={plugins}
toolbarOptions={toolbarOptions}
/>
</FormAccordion>
{config.ndlaEnvironment === "test" && (
Expand Down
Loading

0 comments on commit 988cb27

Please sign in to comment.