@selfcommunity/react-ui 0.7.0-alpha.315 → 0.7.0-alpha.317

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.
@@ -40,7 +40,7 @@ export interface CategoriesPopularWidgetProps extends VirtualScrollerItemProps,
40
40
  *
41
41
  * This component renders a list of popular categories.
42
42
  * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/CategoriesPopular)
43
-
43
+
44
44
  #### Import
45
45
  ```jsx
46
46
  import {CategoriesPopular} from '@selfcommunity/react-ui';
@@ -43,7 +43,7 @@ const DialogRoot = (0, styles_1.styled)(BaseDialog_1.default, {
43
43
  *
44
44
  * This component renders a list of popular categories.
45
45
  * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/CategoriesPopular)
46
-
46
+
47
47
  #### Import
48
48
  ```jsx
49
49
  import {CategoriesPopular} from '@selfcommunity/react-ui';
@@ -34,6 +34,7 @@ const classes = {
34
34
  nestedComments: `${PREFIX}-nested-comments`,
35
35
  avatar: `${PREFIX}-avatar`,
36
36
  content: `${PREFIX}-content`,
37
+ showMoreContent: `${PREFIX}-show-more-content`,
37
38
  author: `${PREFIX}-author`,
38
39
  textContent: `${PREFIX}-text-content`,
39
40
  commentActionsMenu: `${PREFIX}-comment-actions-menu`,
@@ -328,6 +329,9 @@ function CommentObject(inProps) {
328
329
  // or the comment author is the logged user
329
330
  return null;
330
331
  }
332
+ const commentHtml = comment.summary_html ? comment.summary_html : comment.html;
333
+ const summaryHtmlTruncated = comment.summary_truncated ? comment.summary_truncated : false;
334
+ const summaryHtml = (0, contribution_1.getContributionHtml)(commentHtml, scRoutingContext.url);
331
335
  return (react_1.default.createElement(react_1.default.Fragment, { key: comment.id },
332
336
  editComment && editComment.id === comment.id ? (react_1.default.createElement(material_1.Box, { className: classes.comment },
333
337
  react_1.default.createElement(CommentObjectReply_1.default, Object.assign({ text: comment.html, autoFocus: true, id: `edit-${comment.id}`, onSave: handleSave, onCancel: handleCancel, editable: !isReplying || !isSavingComment }, CommentObjectReplyProps)))) : (react_1.default.createElement(BaseItem_1.default, { elevation: 0, className: classes.comment, image: react_1.default.createElement(react_core_1.Link, Object.assign({}, (!comment.author.deleted && { to: scRoutingContext.url(react_core_1.SCRoutes.USER_PROFILE_ROUTE_NAME, comment.author) }), { onClick: comment.author.deleted ? () => setOpenAlert(true) : null }),
@@ -337,7 +341,9 @@ function CommentObject(inProps) {
337
341
  react_1.default.createElement(material_1.CardContent, { className: (0, classnames_1.default)({ [classes.deleted]: obj && obj.deleted }) },
338
342
  react_1.default.createElement(react_core_1.Link, Object.assign({ className: classes.author }, (!comment.author.deleted && { to: scRoutingContext.url(react_core_1.SCRoutes.USER_PROFILE_ROUTE_NAME, comment.author) }), { onClick: comment.author.deleted ? () => setOpenAlert(true) : null }),
339
343
  react_1.default.createElement(material_1.Typography, { component: "span" }, comment.author.username)),
340
- react_1.default.createElement(material_1.Typography, { className: classes.textContent, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: { __html: (0, contribution_1.getContributionHtml)(comment, scRoutingContext.url) } })),
344
+ react_1.default.createElement(material_1.Typography, { className: classes.textContent, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: { __html: summaryHtml } }),
345
+ summaryHtmlTruncated && (react_1.default.createElement(react_core_1.Link, { to: scRoutingContext.url(react_core_1.SCRoutes.COMMENT_ROUTE_NAME, (0, contribution_1.getRouteData)(comment)), className: classes.showMoreContent },
346
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.commentObject.showMore", defaultMessage: "ui.commentObject.showMore" })))),
341
347
  scUserContext.user && (react_1.default.createElement(material_1.Box, { className: classes.commentActionsMenu },
342
348
  react_1.default.createElement(ContributionActionsMenu_1.default, { commentObject: comment, onRestoreContribution: handleRestore, onHideContribution: handleHide, onDeleteContribution: handleDelete, onEditContribution: handleEdit })))),
343
349
  react_1.default.createElement(material_1.Box, { component: "span", className: classes.contentSubSection },
@@ -19,7 +19,6 @@ const LexicalLinkPlugin_1 = require("@lexical/react/LexicalLinkPlugin");
19
19
  const ApiPlugin_1 = tslib_1.__importDefault(require("./plugins/ApiPlugin"));
20
20
  const ToolbarPlugin_1 = tslib_1.__importDefault(require("./plugins/ToolbarPlugin"));
21
21
  const LexicalListPlugin_1 = require("@lexical/react/LexicalListPlugin");
22
- const useMediaQuery_1 = tslib_1.__importDefault(require("@mui/material/useMediaQuery"));
23
22
  const FloatingLinkPlugin_1 = tslib_1.__importDefault(require("./plugins/FloatingLinkPlugin"));
24
23
  const OnBlurPlugin_1 = tslib_1.__importDefault(require("./plugins/OnBlurPlugin"));
25
24
  const OnFocusPlugin_1 = tslib_1.__importDefault(require("./plugins/OnFocusPlugin"));
@@ -110,7 +109,6 @@ const Editor = (inProps, ref) => {
110
109
  const apiRef = (0, react_1.useRef)();
111
110
  // MEMO
112
111
  const theme = (0, material_1.useTheme)();
113
- const isMobile = (0, useMediaQuery_1.default)(theme.breakpoints.down('md'));
114
112
  // HANDLERS
115
113
  const handleChange = (value) => {
116
114
  onChange && onChange(value);
@@ -7,6 +7,16 @@ const lexical_1 = require("lexical");
7
7
  const LexicalComposerContext_1 = require("@lexical/react/LexicalComposerContext");
8
8
  const useLexicalNodeSelection_1 = require("@lexical/react/useLexicalNodeSelection");
9
9
  const utils_1 = require("@lexical/utils");
10
+ /**
11
+ * Limit the width of an image
12
+ * Used to compute the padding-bottom of the div that wrap the img
13
+ */
14
+ const IMAGE_WIDTH_THRESHOLD = 500;
15
+ /**
16
+ * Calc aspect-ratio of image
17
+ * @param width
18
+ * @param height
19
+ */
10
20
  function getAspectRatio(width, height) {
11
21
  return width / height;
12
22
  }
@@ -25,7 +35,7 @@ function useSuspenseImage(src) {
25
35
  }
26
36
  function LazyImage({ altText, className, imageRef, src, width, height }) {
27
37
  useSuspenseImage(src);
28
- const aspectRatio = getAspectRatio(width, height);
38
+ const aspectRatio = getAspectRatio(IMAGE_WIDTH_THRESHOLD, height);
29
39
  return (react_1.default.createElement("div", { draggable: false, className: className, style: { position: 'relative', paddingBottom: `${100 / aspectRatio}%` } },
30
40
  react_1.default.createElement("img", { src: src, alt: altText, ref: imageRef, style: {
31
41
  position: 'absolute',
@@ -170,7 +180,7 @@ class ImageNode extends lexical_1.DecoratorNode {
170
180
  return { element };
171
181
  }
172
182
  decorate() {
173
- return (react_1.default.createElement(ImageComponent, { src: this.__src, altText: this.__altText, width: this.__width, height: this.__height, nodeKey: this.getKey() }));
183
+ return react_1.default.createElement(ImageComponent, { src: this.__src, altText: this.__altText, width: this.__width, height: this.__height, nodeKey: this.getKey() });
174
184
  }
175
185
  static importJSON(serializedNode) {
176
186
  const { altText, height, width, src } = serializedNode;
@@ -15,7 +15,6 @@ const Icon_1 = tslib_1.__importDefault(require("@mui/material/Icon"));
15
15
  const react_intl_1 = require("react-intl");
16
16
  const Poll_1 = tslib_1.__importDefault(require("./Poll"));
17
17
  const Contributors_1 = tslib_1.__importDefault(require("./Contributors"));
18
- const Composer_1 = tslib_1.__importDefault(require("../Composer"));
19
18
  const feedObject_1 = require("../../types/feedObject");
20
19
  const MarkRead_1 = tslib_1.__importDefault(require("../../shared/MarkRead"));
21
20
  const classnames_1 = tslib_1.__importDefault(require("classnames"));
@@ -36,7 +35,8 @@ const errors_1 = require("../../utils/errors");
36
35
  const react_core_1 = require("@selfcommunity/react-core");
37
36
  const UserDeletedSnackBar_1 = tslib_1.__importDefault(require("../../shared/UserDeletedSnackBar"));
38
37
  const UserAvatar_1 = tslib_1.__importDefault(require("../../shared/UserAvatar"));
39
- const MAX_SUMMARY_LENGTH = 150;
38
+ const Feed_1 = require("../../constants/Feed");
39
+ const Composer_1 = tslib_1.__importDefault(require("../Composer"));
40
40
  const messages = (0, react_intl_1.defineMessages)({
41
41
  visibleToAll: {
42
42
  id: 'ui.feedObject.visibleToAll',
@@ -369,6 +369,38 @@ function FeedObject(inProps) {
369
369
  });
370
370
  }
371
371
  };
372
+ /**
373
+ * Get contribution summary
374
+ */
375
+ const getContributionSummary = (0, react_1.useCallback)((obj, template) => {
376
+ const contributionHtml = obj.summary_html ? obj.summary_html : obj.summary;
377
+ const summaryHtmlTruncated = obj.summary_truncated ? obj.summary_truncated : obj.html.length >= Feed_1.MAX_SUMMARY_LENGTH;
378
+ const summaryHtml = expanded || template === feedObject_1.SCFeedObjectTemplateType.DETAIL
379
+ ? (0, contribution_1.getContributionHtml)(obj.html, scRoutingContext.url)
380
+ : (0, contribution_1.getContributionHtml)(contributionHtml, scRoutingContext.url);
381
+ if (template === feedObject_1.SCFeedObjectTemplateType.SHARE) {
382
+ return (react_1.default.createElement(react_1.default.Fragment, null,
383
+ react_1.default.createElement(react_core_1.Link, { to: scRoutingContext.url((0, contribution_1.getContributionRouteName)(obj), (0, contribution_1.getRouteData)(obj)), className: classes.text },
384
+ react_1.default.createElement(material_1.Typography, { component: "div", className: classes.text, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: {
385
+ __html: summaryHtml
386
+ } })),
387
+ !expanded && summaryHtmlTruncated && (react_1.default.createElement(material_1.Button, { size: "small", variant: "text", color: "inherit", onClick: () => setExpanded(!expanded) },
388
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))));
389
+ }
390
+ else if (template === feedObject_1.SCFeedObjectTemplateType.DETAIL) {
391
+ return (react_1.default.createElement(material_1.Typography, { component: "div", gutterBottom: true, className: classes.text, dangerouslySetInnerHTML: {
392
+ __html: summaryHtml
393
+ } }));
394
+ }
395
+ else {
396
+ return (react_1.default.createElement(material_1.Typography, { component: "div", gutterBottom: true, className: classes.text },
397
+ react_1.default.createElement(material_1.Typography, { component: "span", dangerouslySetInnerHTML: {
398
+ __html: summaryHtml
399
+ } }),
400
+ !expanded && summaryHtmlTruncated && (react_1.default.createElement(material_1.Button, { size: "small", variant: "text", color: "inherit", onClick: () => setExpanded(!expanded) },
401
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))));
402
+ }
403
+ }, [obj, template, expanded]);
372
404
  /**
373
405
  * Render the obj object
374
406
  * Manage variants:
@@ -402,12 +434,7 @@ function FeedObject(inProps) {
402
434
  react_1.default.createElement(CardContent_1.default, { classes: { root: classes.content } },
403
435
  react_1.default.createElement(material_1.Box, { className: classes.titleSection }, 'title' in obj && (react_1.default.createElement(react_1.default.Fragment, null, template === feedObject_1.SCFeedObjectTemplateType.DETAIL ? (react_1.default.createElement(material_1.Typography, { variant: "body1", gutterBottom: true, className: classes.title }, obj.title)) : (react_1.default.createElement(react_core_1.Link, { to: scRoutingContext.url((0, contribution_1.getContributionRouteName)(obj), (0, contribution_1.getRouteData)(obj)) },
404
436
  react_1.default.createElement(material_1.Typography, { variant: "body1", gutterBottom: true, className: classes.title }, obj.title)))))),
405
- react_1.default.createElement(material_1.Box, { className: classes.textSection }, template === feedObject_1.SCFeedObjectTemplateType.DETAIL ? (react_1.default.createElement(material_1.Typography, { component: "div", gutterBottom: true, className: classes.text, dangerouslySetInnerHTML: {
406
- __html: (0, contribution_1.getContributionHtml)(obj, scRoutingContext.url)
407
- } })) : (react_1.default.createElement(material_1.Typography, { component: "div", gutterBottom: true, className: classes.text },
408
- react_1.default.createElement(material_1.Typography, { component: "span", dangerouslySetInnerHTML: { __html: expanded ? (0, contribution_1.getContributionHtml)(obj, scRoutingContext.url) : obj.summary } }),
409
- !expanded && obj.html.length >= MAX_SUMMARY_LENGTH && (react_1.default.createElement(material_1.Button, { size: "small", variant: "text", color: "inherit", onClick: () => setExpanded(!expanded) },
410
- react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))))),
437
+ react_1.default.createElement(material_1.Box, { className: classes.textSection }, getContributionSummary(obj, template)),
411
438
  react_1.default.createElement(material_1.Box, { className: classes.mediasSection },
412
439
  react_1.default.createElement(MediasPreview_1.default, Object.assign({ medias: obj.medias }, MediasPreviewProps))),
413
440
  react_1.default.createElement(material_1.Box, { className: classes.pollsSection }, obj['poll'] && (react_1.default.createElement(Poll_1.default, Object.assign({ visible: pollVisible ||
@@ -440,11 +467,7 @@ function FeedObject(inProps) {
440
467
  react_1.default.createElement(CardContent_1.default, { classes: { root: classes.content } },
441
468
  react_1.default.createElement(material_1.Box, { className: classes.titleSection }, 'title' in obj && (react_1.default.createElement(react_core_1.Link, { to: scRoutingContext.url((0, contribution_1.getContributionRouteName)(obj), (0, contribution_1.getRouteData)(obj)) },
442
469
  react_1.default.createElement(material_1.Typography, { variant: "body1", gutterBottom: true, className: classes.title }, obj.title)))),
443
- react_1.default.createElement(material_1.Box, { className: classes.textSection },
444
- react_1.default.createElement(react_core_1.Link, { to: scRoutingContext.url((0, contribution_1.getContributionRouteName)(obj), (0, contribution_1.getRouteData)(obj)), className: classes.text },
445
- react_1.default.createElement(material_1.Typography, { component: "div", className: classes.text, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: { __html: expanded ? (0, contribution_1.getContributionHtml)(obj, scRoutingContext.url) : obj.summary } })),
446
- !expanded && obj.html.length >= MAX_SUMMARY_LENGTH && (react_1.default.createElement(material_1.Button, { size: "small", variant: "text", color: "inherit", onClick: () => setExpanded(!expanded) },
447
- react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))),
470
+ react_1.default.createElement(material_1.Box, { className: classes.textSection }, getContributionSummary(obj, template)),
448
471
  react_1.default.createElement(material_1.Box, { className: classes.mediasSection },
449
472
  react_1.default.createElement(MediasPreview_1.default, Object.assign({ medias: obj.medias }, MediasPreviewProps))),
450
473
  react_1.default.createElement(material_1.Box, { className: classes.pollsSection }, obj['poll'] && (react_1.default.createElement(Poll_1.default, Object.assign({ feedObject: obj, pollObject: obj['poll'], onChange: handleChangePoll, visible: Boolean(obj.type !== types_1.SCContributionType.DISCUSSION && !obj.html && !obj.medias.length) }, PollObjectProps))))))) : (react_1.default.createElement(Skeleton_1.default, Object.assign({ template: template }, FeedObjectSkeletonProps)))));
@@ -3,3 +3,4 @@
3
3
  */
4
4
  export declare const WIDGET_PREFIX_KEY = "widget_";
5
5
  export declare const DEFAULT_WIDGETS_NUMBER = 10;
6
+ export declare const MAX_SUMMARY_LENGTH = 150;
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_WIDGETS_NUMBER = exports.WIDGET_PREFIX_KEY = void 0;
3
+ exports.MAX_SUMMARY_LENGTH = exports.DEFAULT_WIDGETS_NUMBER = exports.WIDGET_PREFIX_KEY = void 0;
4
4
  /**
5
5
  * Feed constants
6
6
  */
7
7
  exports.WIDGET_PREFIX_KEY = 'widget_';
8
8
  exports.DEFAULT_WIDGETS_NUMBER = 10; // every how many elements insert a widget
9
+ exports.MAX_SUMMARY_LENGTH = 150; // maximum number of characters for the summary before being truncated
@@ -17,10 +17,10 @@ export declare function getContributionSnippet(obj: any): any;
17
17
  /**
18
18
  * Get the contribution text
19
19
  * Hydrate text with mention, etc.
20
- * @param obj Object of types: Discussion, Post, Status, Comment
20
+ * @param html Html of the contribution
21
21
  * @param handleUrl Func that handle urls
22
22
  */
23
- export declare function getContributionHtml(obj: any, handleUrl: any): any;
23
+ export declare function getContributionHtml(html: any, handleUrl: any): any;
24
24
  /**
25
25
  * Get route name for a contribution
26
26
  * @param obj
@@ -54,11 +54,11 @@ exports.getContributionSnippet = getContributionSnippet;
54
54
  /**
55
55
  * Get the contribution text
56
56
  * Hydrate text with mention, etc.
57
- * @param obj Object of types: Discussion, Post, Status, Comment
57
+ * @param html Html of the contribution
58
58
  * @param handleUrl Func that handle urls
59
59
  */
60
- function getContributionHtml(obj, handleUrl) {
61
- return obj.html.replace(/<mention.*? id="([0-9]+)"{1}.*?>@([a-z\d_]+)<\/mention>/gi, (match, id, username) => {
60
+ function getContributionHtml(html, handleUrl) {
61
+ return html.replace(/<mention.*? id="([0-9]+)"{1}.*?>@([a-z\d_]+)<\/mention>/gi, (match, id, username) => {
62
62
  return `<a href='${handleUrl(react_core_1.SCRoutes.USER_PROFILE_ROUTE_NAME, { id, username })}'>@${username}</a>`;
63
63
  });
64
64
  }
@@ -40,7 +40,7 @@ export interface CategoriesPopularWidgetProps extends VirtualScrollerItemProps,
40
40
  *
41
41
  * This component renders a list of popular categories.
42
42
  * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/CategoriesPopular)
43
-
43
+
44
44
  #### Import
45
45
  ```jsx
46
46
  import {CategoriesPopular} from '@selfcommunity/react-ui';
@@ -41,7 +41,7 @@ const DialogRoot = styled(BaseDialog, {
41
41
  *
42
42
  * This component renders a list of popular categories.
43
43
  * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/CategoriesPopular)
44
-
44
+
45
45
  #### Import
46
46
  ```jsx
47
47
  import {CategoriesPopular} from '@selfcommunity/react-ui';
@@ -32,6 +32,7 @@ const classes = {
32
32
  nestedComments: `${PREFIX}-nested-comments`,
33
33
  avatar: `${PREFIX}-avatar`,
34
34
  content: `${PREFIX}-content`,
35
+ showMoreContent: `${PREFIX}-show-more-content`,
35
36
  author: `${PREFIX}-author`,
36
37
  textContent: `${PREFIX}-text-content`,
37
38
  commentActionsMenu: `${PREFIX}-comment-actions-menu`,
@@ -326,6 +327,9 @@ export default function CommentObject(inProps) {
326
327
  // or the comment author is the logged user
327
328
  return null;
328
329
  }
330
+ const commentHtml = comment.summary_html ? comment.summary_html : comment.html;
331
+ const summaryHtmlTruncated = comment.summary_truncated ? comment.summary_truncated : false;
332
+ const summaryHtml = getContributionHtml(commentHtml, scRoutingContext.url);
329
333
  return (React.createElement(React.Fragment, { key: comment.id },
330
334
  editComment && editComment.id === comment.id ? (React.createElement(Box, { className: classes.comment },
331
335
  React.createElement(CommentObjectReply, Object.assign({ text: comment.html, autoFocus: true, id: `edit-${comment.id}`, onSave: handleSave, onCancel: handleCancel, editable: !isReplying || !isSavingComment }, CommentObjectReplyProps)))) : (React.createElement(BaseItem, { elevation: 0, className: classes.comment, image: React.createElement(Link, Object.assign({}, (!comment.author.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, comment.author) }), { onClick: comment.author.deleted ? () => setOpenAlert(true) : null }),
@@ -335,7 +339,9 @@ export default function CommentObject(inProps) {
335
339
  React.createElement(CardContent, { className: classNames({ [classes.deleted]: obj && obj.deleted }) },
336
340
  React.createElement(Link, Object.assign({ className: classes.author }, (!comment.author.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, comment.author) }), { onClick: comment.author.deleted ? () => setOpenAlert(true) : null }),
337
341
  React.createElement(Typography, { component: "span" }, comment.author.username)),
338
- React.createElement(Typography, { className: classes.textContent, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: { __html: getContributionHtml(comment, scRoutingContext.url) } })),
342
+ React.createElement(Typography, { className: classes.textContent, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: { __html: summaryHtml } }),
343
+ summaryHtmlTruncated && (React.createElement(Link, { to: scRoutingContext.url(SCRoutes.COMMENT_ROUTE_NAME, getRouteData(comment)), className: classes.showMoreContent },
344
+ React.createElement(FormattedMessage, { id: "ui.commentObject.showMore", defaultMessage: "ui.commentObject.showMore" })))),
339
345
  scUserContext.user && (React.createElement(Box, { className: classes.commentActionsMenu },
340
346
  React.createElement(ContributionActionsMenu, { commentObject: comment, onRestoreContribution: handleRestore, onHideContribution: handleHide, onDeleteContribution: handleDelete, onEditContribution: handleEdit })))),
341
347
  React.createElement(Box, { component: "span", className: classes.contentSubSection },
@@ -16,7 +16,6 @@ import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
16
16
  import ApiPlugin from './plugins/ApiPlugin';
17
17
  import ToolbarPlugin from './plugins/ToolbarPlugin';
18
18
  import { ListPlugin } from '@lexical/react/LexicalListPlugin';
19
- import useMediaQuery from '@mui/material/useMediaQuery';
20
19
  import FloatingLinkPlugin from './plugins/FloatingLinkPlugin';
21
20
  import OnBlurPlugin from './plugins/OnBlurPlugin';
22
21
  import OnFocusPlugin from './plugins/OnFocusPlugin';
@@ -107,7 +106,6 @@ const Editor = (inProps, ref) => {
107
106
  const apiRef = useRef();
108
107
  // MEMO
109
108
  const theme = useTheme();
110
- const isMobile = useMediaQuery(theme.breakpoints.down('md'));
111
109
  // HANDLERS
112
110
  const handleChange = (value) => {
113
111
  onChange && onChange(value);
@@ -1,8 +1,18 @@
1
1
  import React, { Suspense, useCallback, useEffect, useRef } from 'react';
2
- import { $getNodeByKey, $getSelection, $isNodeSelection, $setSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, DecoratorNode, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, KEY_ENTER_COMMAND, KEY_ESCAPE_COMMAND, SELECTION_CHANGE_COMMAND, TextNode, } from 'lexical';
2
+ import { $getNodeByKey, $getSelection, $isNodeSelection, $setSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, DecoratorNode, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, KEY_ENTER_COMMAND, KEY_ESCAPE_COMMAND, SELECTION_CHANGE_COMMAND, TextNode } from 'lexical';
3
3
  import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
4
4
  import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection';
5
5
  import { mergeRegister } from '@lexical/utils';
6
+ /**
7
+ * Limit the width of an image
8
+ * Used to compute the padding-bottom of the div that wrap the img
9
+ */
10
+ const IMAGE_WIDTH_THRESHOLD = 500;
11
+ /**
12
+ * Calc aspect-ratio of image
13
+ * @param width
14
+ * @param height
15
+ */
6
16
  function getAspectRatio(width, height) {
7
17
  return width / height;
8
18
  }
@@ -21,7 +31,7 @@ function useSuspenseImage(src) {
21
31
  }
22
32
  function LazyImage({ altText, className, imageRef, src, width, height }) {
23
33
  useSuspenseImage(src);
24
- const aspectRatio = getAspectRatio(width, height);
34
+ const aspectRatio = getAspectRatio(IMAGE_WIDTH_THRESHOLD, height);
25
35
  return (React.createElement("div", { draggable: false, className: className, style: { position: 'relative', paddingBottom: `${100 / aspectRatio}%` } },
26
36
  React.createElement("img", { src: src, alt: altText, ref: imageRef, style: {
27
37
  position: 'absolute',
@@ -166,7 +176,7 @@ export class ImageNode extends DecoratorNode {
166
176
  return { element };
167
177
  }
168
178
  decorate() {
169
- return (React.createElement(ImageComponent, { src: this.__src, altText: this.__altText, width: this.__width, height: this.__height, nodeKey: this.getKey() }));
179
+ return React.createElement(ImageComponent, { src: this.__src, altText: this.__altText, width: this.__width, height: this.__height, nodeKey: this.getKey() });
170
180
  }
171
181
  static importJSON(serializedNode) {
172
182
  const { altText, height, width, src } = serializedNode;
@@ -13,7 +13,6 @@ import Icon from '@mui/material/Icon';
13
13
  import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
14
14
  import PollObject from './Poll';
15
15
  import ContributorsFeedObject from './Contributors';
16
- import Composer from '../Composer';
17
16
  import { SCFeedObjectActivitiesType, SCFeedObjectTemplateType } from '../../types/feedObject';
18
17
  import MarkRead from '../../shared/MarkRead';
19
18
  import classNames from 'classnames';
@@ -34,7 +33,8 @@ import { catchUnauthorizedActionByBlockedUser } from '../../utils/errors';
34
33
  import { Link, SCCache, SCRoutes, UserUtils, useSCContext, useSCFetchFeedObject, useSCRouting, useSCUser } from '@selfcommunity/react-core';
35
34
  import UserDeletedSnackBar from '../../shared/UserDeletedSnackBar';
36
35
  import UserAvatar from '../../shared/UserAvatar';
37
- const MAX_SUMMARY_LENGTH = 150;
36
+ import { MAX_SUMMARY_LENGTH } from '../../constants/Feed';
37
+ import Composer from '../Composer';
38
38
  const messages = defineMessages({
39
39
  visibleToAll: {
40
40
  id: 'ui.feedObject.visibleToAll',
@@ -367,6 +367,38 @@ export default function FeedObject(inProps) {
367
367
  });
368
368
  }
369
369
  };
370
+ /**
371
+ * Get contribution summary
372
+ */
373
+ const getContributionSummary = useCallback((obj, template) => {
374
+ const contributionHtml = obj.summary_html ? obj.summary_html : obj.summary;
375
+ const summaryHtmlTruncated = obj.summary_truncated ? obj.summary_truncated : obj.html.length >= MAX_SUMMARY_LENGTH;
376
+ const summaryHtml = expanded || template === SCFeedObjectTemplateType.DETAIL
377
+ ? getContributionHtml(obj.html, scRoutingContext.url)
378
+ : getContributionHtml(contributionHtml, scRoutingContext.url);
379
+ if (template === SCFeedObjectTemplateType.SHARE) {
380
+ return (React.createElement(React.Fragment, null,
381
+ React.createElement(Link, { to: scRoutingContext.url(getContributionRouteName(obj), getRouteData(obj)), className: classes.text },
382
+ React.createElement(Typography, { component: "div", className: classes.text, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: {
383
+ __html: summaryHtml
384
+ } })),
385
+ !expanded && summaryHtmlTruncated && (React.createElement(Button, { size: "small", variant: "text", color: "inherit", onClick: () => setExpanded(!expanded) },
386
+ React.createElement(FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))));
387
+ }
388
+ else if (template === SCFeedObjectTemplateType.DETAIL) {
389
+ return (React.createElement(Typography, { component: "div", gutterBottom: true, className: classes.text, dangerouslySetInnerHTML: {
390
+ __html: summaryHtml
391
+ } }));
392
+ }
393
+ else {
394
+ return (React.createElement(Typography, { component: "div", gutterBottom: true, className: classes.text },
395
+ React.createElement(Typography, { component: "span", dangerouslySetInnerHTML: {
396
+ __html: summaryHtml
397
+ } }),
398
+ !expanded && summaryHtmlTruncated && (React.createElement(Button, { size: "small", variant: "text", color: "inherit", onClick: () => setExpanded(!expanded) },
399
+ React.createElement(FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))));
400
+ }
401
+ }, [obj, template, expanded]);
370
402
  /**
371
403
  * Render the obj object
372
404
  * Manage variants:
@@ -400,12 +432,7 @@ export default function FeedObject(inProps) {
400
432
  React.createElement(CardContent, { classes: { root: classes.content } },
401
433
  React.createElement(Box, { className: classes.titleSection }, 'title' in obj && (React.createElement(React.Fragment, null, template === SCFeedObjectTemplateType.DETAIL ? (React.createElement(Typography, { variant: "body1", gutterBottom: true, className: classes.title }, obj.title)) : (React.createElement(Link, { to: scRoutingContext.url(getContributionRouteName(obj), getRouteData(obj)) },
402
434
  React.createElement(Typography, { variant: "body1", gutterBottom: true, className: classes.title }, obj.title)))))),
403
- React.createElement(Box, { className: classes.textSection }, template === SCFeedObjectTemplateType.DETAIL ? (React.createElement(Typography, { component: "div", gutterBottom: true, className: classes.text, dangerouslySetInnerHTML: {
404
- __html: getContributionHtml(obj, scRoutingContext.url)
405
- } })) : (React.createElement(Typography, { component: "div", gutterBottom: true, className: classes.text },
406
- React.createElement(Typography, { component: "span", dangerouslySetInnerHTML: { __html: expanded ? getContributionHtml(obj, scRoutingContext.url) : obj.summary } }),
407
- !expanded && obj.html.length >= MAX_SUMMARY_LENGTH && (React.createElement(Button, { size: "small", variant: "text", color: "inherit", onClick: () => setExpanded(!expanded) },
408
- React.createElement(FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))))),
435
+ React.createElement(Box, { className: classes.textSection }, getContributionSummary(obj, template)),
409
436
  React.createElement(Box, { className: classes.mediasSection },
410
437
  React.createElement(MediasPreview, Object.assign({ medias: obj.medias }, MediasPreviewProps))),
411
438
  React.createElement(Box, { className: classes.pollsSection }, obj['poll'] && (React.createElement(PollObject, Object.assign({ visible: pollVisible ||
@@ -438,11 +465,7 @@ export default function FeedObject(inProps) {
438
465
  React.createElement(CardContent, { classes: { root: classes.content } },
439
466
  React.createElement(Box, { className: classes.titleSection }, 'title' in obj && (React.createElement(Link, { to: scRoutingContext.url(getContributionRouteName(obj), getRouteData(obj)) },
440
467
  React.createElement(Typography, { variant: "body1", gutterBottom: true, className: classes.title }, obj.title)))),
441
- React.createElement(Box, { className: classes.textSection },
442
- React.createElement(Link, { to: scRoutingContext.url(getContributionRouteName(obj), getRouteData(obj)), className: classes.text },
443
- React.createElement(Typography, { component: "div", className: classes.text, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: { __html: expanded ? getContributionHtml(obj, scRoutingContext.url) : obj.summary } })),
444
- !expanded && obj.html.length >= MAX_SUMMARY_LENGTH && (React.createElement(Button, { size: "small", variant: "text", color: "inherit", onClick: () => setExpanded(!expanded) },
445
- React.createElement(FormattedMessage, { id: "ui.feedObject.content.showMore", defaultMessage: "ui.feedObject.content.showMore" })))),
468
+ React.createElement(Box, { className: classes.textSection }, getContributionSummary(obj, template)),
446
469
  React.createElement(Box, { className: classes.mediasSection },
447
470
  React.createElement(MediasPreview, Object.assign({ medias: obj.medias }, MediasPreviewProps))),
448
471
  React.createElement(Box, { className: classes.pollsSection }, obj['poll'] && (React.createElement(PollObject, Object.assign({ feedObject: obj, pollObject: obj['poll'], onChange: handleChangePoll, visible: Boolean(obj.type !== SCContributionType.DISCUSSION && !obj.html && !obj.medias.length) }, PollObjectProps))))))) : (React.createElement(FeedObjectSkeleton, Object.assign({ template: template }, FeedObjectSkeletonProps)))));
@@ -3,3 +3,4 @@
3
3
  */
4
4
  export declare const WIDGET_PREFIX_KEY = "widget_";
5
5
  export declare const DEFAULT_WIDGETS_NUMBER = 10;
6
+ export declare const MAX_SUMMARY_LENGTH = 150;
@@ -3,3 +3,4 @@
3
3
  */
4
4
  export const WIDGET_PREFIX_KEY = 'widget_';
5
5
  export const DEFAULT_WIDGETS_NUMBER = 10; // every how many elements insert a widget
6
+ export const MAX_SUMMARY_LENGTH = 150; // maximum number of characters for the summary before being truncated
@@ -17,10 +17,10 @@ export declare function getContributionSnippet(obj: any): any;
17
17
  /**
18
18
  * Get the contribution text
19
19
  * Hydrate text with mention, etc.
20
- * @param obj Object of types: Discussion, Post, Status, Comment
20
+ * @param html Html of the contribution
21
21
  * @param handleUrl Func that handle urls
22
22
  */
23
- export declare function getContributionHtml(obj: any, handleUrl: any): any;
23
+ export declare function getContributionHtml(html: any, handleUrl: any): any;
24
24
  /**
25
25
  * Get route name for a contribution
26
26
  * @param obj
@@ -47,11 +47,11 @@ export function getContributionSnippet(obj) {
47
47
  /**
48
48
  * Get the contribution text
49
49
  * Hydrate text with mention, etc.
50
- * @param obj Object of types: Discussion, Post, Status, Comment
50
+ * @param html Html of the contribution
51
51
  * @param handleUrl Func that handle urls
52
52
  */
53
- export function getContributionHtml(obj, handleUrl) {
54
- return obj.html.replace(/<mention.*? id="([0-9]+)"{1}.*?>@([a-z\d_]+)<\/mention>/gi, (match, id, username) => {
53
+ export function getContributionHtml(html, handleUrl) {
54
+ return html.replace(/<mention.*? id="([0-9]+)"{1}.*?>@([a-z\d_]+)<\/mention>/gi, (match, id, username) => {
55
55
  return `<a href='${handleUrl(SCRoutes.USER_PROFILE_ROUTE_NAME, { id, username })}'>@${username}</a>`;
56
56
  });
57
57
  }