Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LPS-98734 Move AlloyEditor to external component #76268

Closed
wants to merge 13 commits into from
Closed
@@ -1,3 +1,28 @@
@keyframes FragmentCommentResolvedDecrease {
from {
max-height: 100vh;
}

to {
max-height: 0;
min-height: 0;
padding-top: 0;
transform: scaleY(0.9) translateY(-10%);
}
}

@keyframes FragmentCommentResolvedFadeOut {
to {
opacity: 0;
}
}

@keyframes FragmentCommentResolvedCheckFadeIn {
to {
opacity: 1;
}
}

.fragments-editor__fragment-comment {
min-height: 5rem;
padding-top: 1rem;
Expand All @@ -9,11 +34,40 @@
min-height: 10rem;
}

&--resolved {
animation: FragmentCommentResolvedDecrease ease 0.4s,
FragmentCommentResolvedFadeOut ease 0.3s;
animation-delay: 0.5s;
animation-fill-mode: forwards;
overflow: hidden;
}

& + & {
border-top: solid thin #e7e7ed;
}

> form {
margin-bottom: 1rem;
}

.resolved {
align-items: center;
animation: FragmentCommentResolvedCheckFadeIn ease 0.3s;
animation-fill-mode: forwards;
background: #edf9f0;
bottom: 0;
color: #287d3c;
display: flex;
font-size: 48px;
justify-content: center;
left: 0;
opacity: 0;
position: absolute;
right: 0;
top: 0;
}

.content {
hyphens: auto;
}
}
Expand Up @@ -17,16 +17,12 @@
import ClayButton from '@clayui/button';
import PropTypes from 'prop-types';
import React from 'react';
import Loader from './Loader.es';

const Button = ({children, loading, ...props}) => (
<ClayButton {...props}>
<span className="d-inline-flex fragments-editor__button">
{loading && (
<span
aria-hidden="true"
className="loading-animation loading-animation-sm m-0 mr-1"
/>
)}
{loading && <Loader />}

{children}
</span>
Expand Down
@@ -0,0 +1,120 @@
/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/

import {EventHandler} from 'metal-events';
import PropTypes from 'prop-types';
import React, {useEffect, useRef, useState} from 'react';

import {getConnectedReactComponent} from '../../store/ConnectedComponent.es';

const Editor = props => {
const [editor, setEditor] = useState(null);

const {autoFocus, editorConfig, initialValue, onChange} = props;
const wrapperRef = useRef(null);

useEffect(() => {
if (editor) {
const nativeEditor = editor.get('nativeEditor');

if (!nativeEditor.getData() || !initialValue) {
nativeEditor.setData(initialValue);
}
}
}, [editor, initialValue]);

useEffect(() => {
const editorEventHandler = new EventHandler();

if (editor && onChange) {
const nativeEditor = editor.get('nativeEditor');

editorEventHandler.add(
nativeEditor.on('change', () =>
onChange(nativeEditor.getData())
)
);

editorEventHandler.add(
nativeEditor.on('actionPerformed', () =>
onChange(nativeEditor.getData())
)
);
}

return () => {
editorEventHandler.removeAllListeners();
editorEventHandler.dispose();
};
}, [editor, onChange]);

useEffect(() => {
const editor = AlloyEditor.editable(wrapperRef.current, {
...editorConfig,
enterMode: 1,
startupFocus: autoFocus
});

setEditor(editor);

return () => {
editor.destroy();
setEditor(null);
};
}, [autoFocus, editorConfig]);

return (
<div
className="alloy-editor-container"
id={`${props.portletNamespace}${props.id}`}
>
<div
className="alloy-editor alloy-editor-placeholder form-control"
contentEditable={false}
data-placeholder={props.placeholder}
data-required={false}
id={`${props.portletNamespace}${props.id}`}
name={props.id}
ref={wrapperRef}
/>
</div>
);
};

Editor.defaultProps = {
autoFocus: false,
editorConfig: {},
portletNamespace: ''
};

Editor.propTypes = {
autoFocus: PropTypes.bool,
editorConfig: PropTypes.object,
id: PropTypes.string.isRequired,
initialValue: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
placeholder: PropTypes.string.isRequired,
portletNamespace: PropTypes.string
};

const ConnectedEditor = getConnectedReactComponent(
state => ({
editorConfig: state.defaultEditorConfigurations.text.editorConfig,
portletNamespace: state.portletNamespace
}),
() => ({})
)(Editor);

export {ConnectedEditor, Editor};
export default ConnectedEditor;
@@ -0,0 +1,27 @@
/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/

/* eslint no-unused-vars: "warn" */

import React from 'react';

const Loader = () => (
<span
aria-hidden="true"
className="loading-animation loading-animation-sm m-0 mr-1"
/>
);

export {Loader};
export default Loader;
Expand Up @@ -21,7 +21,7 @@ const Textarea = props => (
className={`form-control fragments-editor__textarea ${
!props.value ? 'fragments-editor__textarea--empty' : ''
}`}
ref={textarea => props.autofocus && textarea && textarea.focus()}
ref={textarea => props.autoFocus && textarea && textarea.focus()}
{...props}
/>
);
Expand Down
Expand Up @@ -48,14 +48,15 @@ const AddCommentForm = props => {
});
};

const _handleTextareaChange = event => {
if (event.target) {
setTextareaContent(event.target.value);
const _handleTextareaChange = content => {
if (content) {
setTextareaContent(content);
}
};

return (
<CommentForm
id="pageEditorCommentEditor"
loading={addingComment}
onCancelButtonClick={_handleCancelButtonClick}
onFormFocus={_handleFormFocus}
Expand Down
Expand Up @@ -15,27 +15,24 @@
import ClayButton from '@clayui/button';
import PropTypes from 'prop-types';
import React from 'react';

import Button from '../../common/Button.es';
import InvisibleFieldset from '../../common/InvisibleFieldset.es';
import Textarea from '../../common/Textarea.es';

const NEW_COMMENT_ID = 'pageEditorNewCommentId';
import ConnectedEditor from '../../common/Editor.es';

const CommentForm = props => (
<form onFocus={props.onFormFocus}>
<InvisibleFieldset disabled={props.loading}>
<div className="form-group form-group-sm">
<label className="sr-only" htmlFor={NEW_COMMENT_ID}>
<label className="sr-only" htmlFor={props.id}>
{Liferay.Language.get('add-comment')}
</label>

<Textarea
autofocus={props.autofocus}
id={NEW_COMMENT_ID}
<ConnectedEditor
autoFocus={props.autoFocus}
id={props.id}
initialValue={props.textareaContent}
onChange={props.onTextareaChange}
placeholder={Liferay.Language.get('type-your-comment-here')}
value={props.textareaContent}
/>
</div>

Expand Down Expand Up @@ -66,15 +63,16 @@ const CommentForm = props => (
);

CommentForm.defaultProps = {
autofocus: false,
autoFocus: false,
loading: false,
onFormFocus: () => {},
showButtons: false
};

CommentForm.propTypes = {
autofocus: PropTypes.bool,
autoFocus: PropTypes.bool,
loading: PropTypes.bool,
id: PropTypes.string,
onCancelButtonClick: PropTypes.func.isRequired,
onFormFocus: PropTypes.func,
onSubmitButtonClick: PropTypes.func.isRequired,
Expand Down
Expand Up @@ -17,8 +17,6 @@ import React, {useState} from 'react';

import CommentForm from './CommentForm.es';
import {editFragmentEntryLinkComment} from '../../../utils/FragmentsEditorFetchUtils.es';
import {getConnectedReactComponent} from '../../../store/ConnectedComponent.es';
import {updateFragmentEntryLinkCommentAction} from '../../../actions/updateFragmentEntryLinkComment.es';

const EditCommentForm = props => {
const [editingComment, setEditingComment] = useState(false);
Expand All @@ -32,18 +30,19 @@ const EditCommentForm = props => {
.then(comment => {
setEditingComment(false);

props.editComment(props.fragmentEntryLinkId, comment);
props.onEdit(comment);
props.onCloseForm();
});
};

return (
<CommentForm
autofocus
autoFocus
id={`pageEditorCommentEditor_${props.commentId}`}
loading={editingComment}
onCancelButtonClick={() => props.onCloseForm()}
onSubmitButtonClick={_handleCommentButtonClick}
onTextareaChange={event => setTextareaContent(event.target.value)}
onTextareaChange={content => setTextareaContent(content)}
showButtons
submitButtonLabel={Liferay.Language.get('update')}
textareaContent={textareaContent}
Expand All @@ -52,28 +51,15 @@ const EditCommentForm = props => {
};

EditCommentForm.defaultProps = {
editComment: () => {}
onEdit: () => {}
};

EditCommentForm.propTypes = {
body: PropTypes.string.isRequired,
commentId: PropTypes.string.isRequired,
editComment: PropTypes.func,
onCloseForm: PropTypes.func.isRequired
onCloseForm: PropTypes.func.isRequired,
onEdit: PropTypes.func
};

const ConnectedEditCommentForm = getConnectedReactComponent(
() => ({}),
dispatch => ({
editComment: (fragmentEntryLinkId, comment) =>
dispatch(
updateFragmentEntryLinkCommentAction(
fragmentEntryLinkId,
comment
)
)
})
)(EditCommentForm);

export {ConnectedEditCommentForm, EditCommentForm};
export default ConnectedEditCommentForm;
export {EditCommentForm};
export default EditCommentForm;