@seafile/seafile-editor 1.0.117-beta.1 → 1.0.118-beta

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.
@@ -5,16 +5,17 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.INTERNAL_EVENTS = exports.EXTERNAL_EVENTS = void 0;
7
7
  const INTERNAL_EVENTS = exports.INTERNAL_EVENTS = {
8
- ON_ARTICLE_INFO_TOGGLE: 'on_article_info_toggle',
9
8
  ON_MOUSE_ENTER_BLOCK: 'on_mouse_enter_block',
10
9
  ON_OPEN_LINK_MODAL: 'on_open_link_modal',
11
10
  ON_CLOSE_LINK_POPOVER: 'on_close_link_popover',
12
11
  ON_OPEN_FORMULA_DIALOG: 'on_open_formula_dialog',
13
12
  ON_SELECT_ALL_CELL: 'on_select_all_cell',
14
- ON_TOGGLE_IMAGE_POPOVER: 'on_toggle_image_popover'
13
+ ON_TOGGLE_IMAGE_POPOVER: 'on_toggle_image_popover',
14
+ OUTLINE_STATE_CHANGED: 'outline_state_changed'
15
15
  };
16
16
  const EXTERNAL_EVENTS = exports.EXTERNAL_EVENTS = {
17
17
  ON_HELP_INFO_TOGGLE: 'on_help_info_toggle',
18
+ ON_ARTICLE_INFO_TOGGLE: 'on_article_info_toggle',
18
19
  ON_LINK_CLICK: 'on_link_click',
19
20
  ON_INSERT_IMAGE: 'on_insert_image',
20
21
  INSERT_IMAGE: 'insert_image'
@@ -5,50 +5,81 @@ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWild
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.default = ArticleInfo;
8
+ exports.default = void 0;
9
9
  var _react = _interopRequireWildcard(require("react"));
10
- var _outline = _interopRequireDefault(require("../outline"));
11
- var _slateReact = require("slate-react");
10
+ var _resizeWidth = _interopRequireDefault(require("./resize-width"));
11
+ var _eventBus = _interopRequireDefault(require("../../utils/event-bus"));
12
+ var _eventTypes = require("../../constants/event-types");
12
13
  require("./style.css");
13
- const TAB_TYPES = {
14
- OUTLINE: 'outline',
15
- FILE_DETAIL: 'file_detail'
16
- };
17
- function ArticleInfo(_ref) {
14
+ const MIN_PANEL_WIDTH = 360;
15
+ const MAX_PANEL_WIDTH = 620;
16
+ const ArticleInfo = _ref => {
18
17
  let {
19
- children
18
+ isVisible
20
19
  } = _ref;
21
- const editor = (0, _slateReact.useSlateStatic)();
22
- const [activeTab, setActiveTab] = (0, _react.useState)(TAB_TYPES.OUTLINE);
23
- const onOutlineClick = (0, _react.useCallback)(() => {
24
- if (activeTab === TAB_TYPES.OUTLINE) return;
25
- setActiveTab(TAB_TYPES.OUTLINE);
26
- }, [activeTab]);
27
- const onDetailClick = (0, _react.useCallback)(() => {
28
- if (activeTab === TAB_TYPES.FILE_DETAIL) return;
29
- setActiveTab(TAB_TYPES.FILE_DETAIL);
30
- }, [activeTab]);
20
+ const [width, setWidth] = (0, _react.useState)(MIN_PANEL_WIDTH);
21
+ const [fileDetails, setFileDetails] = (0, _react.useState)({});
22
+ const containerWrapperStyle = (0, _react.useMemo)(() => {
23
+ const style = {
24
+ width,
25
+ zIndex: 101,
26
+ display: isVisible ? 'block' : 'none'
27
+ };
28
+ if (!style.width || style.width < MIN_PANEL_WIDTH) {
29
+ style.width = MIN_PANEL_WIDTH;
30
+ } else if (style.width > MAX_PANEL_WIDTH) {
31
+ style.width = MAX_PANEL_WIDTH;
32
+ }
33
+ return style;
34
+ }, [width, isVisible]);
35
+ const resizeWidth = (0, _react.useCallback)(width => {
36
+ if (width >= MIN_PANEL_WIDTH && width <= MAX_PANEL_WIDTH) {
37
+ setWidth(width);
38
+ }
39
+ }, []);
40
+ const resizeWidthEnd = (0, _react.useCallback)(width => {
41
+ const panelWidth = JSON.parse(window.localStorage.getItem('sf-editor-panel-width') || '{}');
42
+ window.localStorage.setItem('sf-editor-panel-width', JSON.stringify({
43
+ ...panelWidth,
44
+ width
45
+ }));
46
+ }, []);
47
+ (0, _react.useEffect)(() => {
48
+ const panelWidth = JSON.parse(window.localStorage.getItem('sf-editor-panel-width', '{}')) || {};
49
+ const width = Math.max(MIN_PANEL_WIDTH, Math.min(parseInt(panelWidth.width, 10) || MIN_PANEL_WIDTH, MAX_PANEL_WIDTH));
50
+ setWidth(width);
51
+ }, []);
52
+ const handleFileDetails = (0, _react.useCallback)(fileDetails => {
53
+ setFileDetails(fileDetails);
54
+ }, []);
55
+ (0, _react.useEffect)(() => {
56
+ const eventBus = _eventBus.default.getInstance();
57
+ const unsubscribeArticleInfoDetail = eventBus.subscribe(_eventTypes.EXTERNAL_EVENTS.ON_ARTICLE_INFO_TOGGLE, handleFileDetails);
58
+ return () => {
59
+ unsubscribeArticleInfoDetail();
60
+ };
61
+ // eslint-disable-next-line react-hooks/exhaustive-deps
62
+ }, []);
63
+ const {
64
+ component: fileDetailsComponent,
65
+ props: fileDetailsProps
66
+ } = fileDetails || {};
31
67
  return /*#__PURE__*/_react.default.createElement("div", {
32
- className: "sf-article-info-container"
33
- }, /*#__PURE__*/_react.default.createElement("ul", {
34
- className: "sf-article-info-nav nav"
35
- }, /*#__PURE__*/_react.default.createElement("li", {
36
- className: "nav-item"
37
- }, /*#__PURE__*/_react.default.createElement("span", {
38
- className: "nav-link ".concat(activeTab === TAB_TYPES.OUTLINE && 'active'),
39
- onClick: onOutlineClick
40
- }, /*#__PURE__*/_react.default.createElement("i", {
41
- className: "iconfont icon-list-ul"
42
- }))), /*#__PURE__*/_react.default.createElement("li", {
43
- className: "nav-item"
44
- }, /*#__PURE__*/_react.default.createElement("span", {
45
- className: "nav-link ".concat(activeTab === TAB_TYPES.FILE_DETAIL && 'active'),
46
- onClick: onDetailClick
47
- }, /*#__PURE__*/_react.default.createElement("i", {
48
- className: 'iconfont icon-info-circle'
49
- })))), /*#__PURE__*/_react.default.createElement("div", {
50
- className: "sf-article-info-content"
51
- }, activeTab === TAB_TYPES.OUTLINE && /*#__PURE__*/_react.default.createElement(_outline.default, {
52
- editor: editor
53
- }), activeTab === TAB_TYPES.FILE_DETAIL && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, children)));
54
- }
68
+ className: "sf-article-info-container-wrapper",
69
+ style: containerWrapperStyle
70
+ }, /*#__PURE__*/_react.default.createElement(_resizeWidth.default, {
71
+ minWidth: MIN_PANEL_WIDTH,
72
+ maxWidth: MAX_PANEL_WIDTH,
73
+ resizeWidth: resizeWidth,
74
+ resizeWidthEnd: resizeWidthEnd
75
+ }), /*#__PURE__*/_react.default.createElement("div", {
76
+ className: "sf-article-info-container",
77
+ style: {
78
+ width
79
+ }
80
+ }, fileDetailsComponent && /*#__PURE__*/_react.default.createElement(fileDetailsComponent, {
81
+ ...fileDetailsProps,
82
+ width
83
+ })));
84
+ };
85
+ var _default = exports.default = ArticleInfo;
@@ -0,0 +1,37 @@
1
+ .sf-editor-resize-width-handler {
2
+ height: 100%;
3
+ position: absolute;
4
+ right: 0;
5
+ top: 0;
6
+ width: 6px;
7
+ }
8
+
9
+ .sf-editor-resize-width-handler.resize-handler-placement-right {
10
+ left: 0;
11
+ right: auto;
12
+ }
13
+
14
+ .sf-editor-resize-width-handler:hover {
15
+ cursor: col-resize;
16
+ }
17
+
18
+ .sf-editor-resize-width-handler .sf-editor-resize-width-handler-content {
19
+ background-color: initial;
20
+ height: 100%;
21
+ position: relative;
22
+ width: 2px;
23
+ }
24
+
25
+ .sf-editor-resize-width-handler:hover .sf-editor-resize-width-handler-content {
26
+ background-color: #ccc;
27
+ }
28
+
29
+ .sf-editor-resize-width-handler .sf-editor-resize-width-handler-bar {
30
+ background-color: #2d7ff9;
31
+ border-radius: 3px;
32
+ content: "";
33
+ left: 50%;
34
+ margin-left: -3px;
35
+ position: absolute;
36
+ width: 6px;
37
+ }
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+
3
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = void 0;
8
+ var _react = _interopRequireWildcard(require("react"));
9
+ require("./index.css");
10
+ const ResizeWidth = _ref => {
11
+ let {
12
+ minWidth,
13
+ maxWidth,
14
+ resizeWidth: resizeWidthAPI,
15
+ resizeWidthEnd
16
+ } = _ref;
17
+ const [isShowHandlerBar, setIsShowHandlerBar] = (0, _react.useState)(false);
18
+ const [drag, setDrag] = (0, _react.useState)(null);
19
+ const handlerRef = (0, _react.useRef)(null);
20
+ const handlerBarRef = (0, _react.useRef)(null);
21
+ const setHandlerBarTop = handlerTop => {
22
+ if (!handlerBarRef.current || handlerTop < 0) return;
23
+ handlerBarRef.current.style.top = handlerTop + 'px';
24
+ };
25
+ const setHandlerBarPosition = event => {
26
+ if (!handlerRef.current) return;
27
+ const {
28
+ top
29
+ } = handlerRef.current.getBoundingClientRect();
30
+ // 13 is the half of the handler's element height
31
+ const handlerTop = event.pageY - top - 13;
32
+ setHandlerBarTop(handlerTop);
33
+ };
34
+ const getWidthFromMouseEvent = event => {
35
+ return event.pageX || event.touches && event.touches[0] && event.touches[0].pageX || event.changedTouches && event.changedTouches[event.changedTouches.length - 1].pageX;
36
+ };
37
+ const calculateResizedWidth = event => {
38
+ const width = getWidthFromMouseEvent(event);
39
+ const resizedWidth = document.body.clientWidth - width;
40
+ if (minWidth && resizedWidth < minWidth || maxWidth && resizedWidth > maxWidth) return -1;
41
+ return resizedWidth;
42
+ };
43
+ const onResizeWidth = event => {
44
+ const resizedWidth = calculateResizedWidth(event);
45
+ if (resizedWidth < 0) return;
46
+ if (resizeWidthAPI) {
47
+ resizeWidthAPI(resizedWidth);
48
+ }
49
+ };
50
+ const onDrag = event => {
51
+ onResizeWidth(event);
52
+ };
53
+ const onDragStart = (0, _react.useCallback)(event => {
54
+ if (event && event.dataTransfer && event.dataTransfer.setData) {
55
+ event.dataTransfer.setData('text/plain', 'dummy');
56
+ }
57
+ return true;
58
+ }, []);
59
+ const onDragEnd = event => {
60
+ onResizeWidth(event);
61
+ };
62
+ const onMouseLeave = () => {
63
+ setIsShowHandlerBar(false);
64
+ };
65
+ const onMouseEnter = event => {
66
+ setIsShowHandlerBar(true);
67
+ setHandlerBarPosition(event);
68
+ if (handlerRef.current) {
69
+ handlerRef.current.addEventListener('mouseleave', onMouseLeave);
70
+ }
71
+ };
72
+ const onMouseOver = event => {
73
+ setHandlerBarPosition(event);
74
+ };
75
+ const onMouseDown = event => {
76
+ event.preventDefault && event.preventDefault();
77
+ const currDrag = onDragStart(event);
78
+ if (currDrag === null && event.button !== 0) return;
79
+ window.addEventListener('mouseup', onMouseUp);
80
+ window.addEventListener('mousemove', onMouseMove);
81
+ if (handlerRef.current) {
82
+ handlerRef.current.removeEventListener('mouseleave', onMouseLeave);
83
+ }
84
+ setDrag(currDrag);
85
+ };
86
+ const onMouseMove = event => {
87
+ event.preventDefault && event.preventDefault();
88
+ onDrag(event);
89
+ };
90
+ const onMouseUp = event => {
91
+ window.removeEventListener('mouseup', onMouseUp);
92
+ window.removeEventListener('mousemove', onMouseMove);
93
+ onDragEnd(event, drag);
94
+ setHandlerBarTop(-9999);
95
+ setDrag(null);
96
+ setIsShowHandlerBar(false);
97
+ if (resizeWidthEnd) {
98
+ const resizeWidth = calculateResizedWidth(event);
99
+ if (resizeWidth < 0) return;
100
+ resizeWidthEnd(resizeWidth);
101
+ }
102
+ };
103
+ (0, _react.useEffect)(() => {
104
+ return () => {
105
+ window.removeEventListener('mouseup', onMouseUp);
106
+ window.removeEventListener('mousemove', onMouseMove);
107
+ };
108
+ // eslint-disable-next-line
109
+ }, []);
110
+ return /*#__PURE__*/_react.default.createElement("div", {
111
+ className: "sf-editor-resize-width-handler resize-handler-placement-right",
112
+ ref: handlerRef,
113
+ onMouseDown: onMouseDown,
114
+ onMouseOver: onMouseOver,
115
+ onMouseEnter: onMouseEnter,
116
+ onDrag: onDrag,
117
+ onDragStart: onDragStart,
118
+ onDragEnd: onDragEnd,
119
+ style: {
120
+ zIndex: 4
121
+ }
122
+ }, /*#__PURE__*/_react.default.createElement("div", {
123
+ className: "sf-editor-resize-width-handler-content"
124
+ }, isShowHandlerBar && /*#__PURE__*/_react.default.createElement("div", {
125
+ className: "sf-editor-resize-width-handler-bar",
126
+ ref: handlerBarRef,
127
+ style: {
128
+ height: 26
129
+ }
130
+ })));
131
+ };
132
+ var _default = exports.default = ResizeWidth;
@@ -1,54 +1,22 @@
1
- .sf-article-info-container {
2
- flex: 1;
1
+ .sf-article-info-container-wrapper {
3
2
  display: flex;
4
- flex-direction: column;
5
- background-color: #f5f5f5;
6
- user-select: none;
7
- min-height: 0;
8
- }
9
-
10
- .sf-article-info-container .nav {
11
- padding: 10px 0;
12
- min-width: 125px;
13
- height: 36px;
14
- border-bottom: 1px solid #eee;
15
- background-color: #fff;
16
- justify-content: space-around;
17
- flex-wrap: nowrap;
18
- flex-shrink: 0;
19
- }
20
-
21
- .sf-article-info-container .nav .nav-item {
22
- padding: 0 0.75rem;
23
- }
24
-
25
- .sf-article-info-container .nav .nav-link {
26
- padding: 0 0.75rem;
27
- transition: 0.3s color;
28
- margin-right: 0;
29
- }
30
-
31
- .sf-article-info-container .nav-link {
32
- color: #888;
3
+ flex-direction: row;
4
+ max-width: 620px;
5
+ min-width: 360px;
6
+ position: relative;
7
+ height: 100%;
33
8
  }
34
9
 
35
- .sf-article-info-container .nav .nav-link.active {
36
- color: #ff9800;
37
- border-bottom: 0;
38
- }
39
-
40
- .sf-article-info-container .nav .iconfont {
41
- font-weight: 700;
42
- font-size: 0.875rem;
10
+ .sf-article-info-container {
11
+ height: 100%;
43
12
  }
44
13
 
45
- .sf-article-info-container .sf-article-info-content {
46
- flex: 1;
47
- font-size: 0.937rem;
48
- min-height: 0;
49
- overflow: auto;
14
+ .sf-article-info-container[style*="display: none"] {
15
+ opacity: 0;
16
+ pointer-events: none;
50
17
  }
51
18
 
52
- .sf-article-info-container .sf-article-info-content:hover {
53
- overflow: auto;
19
+ .sf-article-info-container[style*="display: block"] {
20
+ opacity: 1;
21
+ pointer-events: auto;
54
22
  }
@@ -1,7 +1,9 @@
1
-
2
1
  .sf-editor-helper {
2
+ z-index:101;
3
+ position: relative;
4
+ width: 300px;
3
5
  height: 100%;
4
- flex: 1 0 350px;
6
+ right: 0;
5
7
  background-color: #fff;
6
8
  overflow-y: auto;
7
9
  overflow-x: hidden;
@@ -5,13 +5,32 @@ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWild
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.default = void 0;
8
+ exports.setOutlineSetting = exports.getOutlineSetting = exports.default = void 0;
9
9
  var _react = _interopRequireWildcard(require("react"));
10
10
  var _reactI18next = require("react-i18next");
11
+ var _classnames = _interopRequireDefault(require("classnames"));
11
12
  var _outlineItem = _interopRequireDefault(require("./outline-item"));
12
13
  var _useScrollContext = require("../../hooks/use-scroll-context");
13
14
  var _constants = require("../../constants");
15
+ var _eventBus = _interopRequireDefault(require("../../utils/event-bus"));
16
+ var _eventTypes = require("../../constants/event-types");
14
17
  require("./style.css");
18
+ const getOutlineSetting = () => {
19
+ const currentValue = localStorage.getItem('sf-editor');
20
+ const config = currentValue ? JSON.parse(currentValue) : {};
21
+ const {
22
+ outlineOpen = false
23
+ } = config;
24
+ return outlineOpen;
25
+ };
26
+ exports.getOutlineSetting = getOutlineSetting;
27
+ const setOutlineSetting = isShown => {
28
+ const currentValue = localStorage.getItem('sf-editor');
29
+ const config = currentValue ? JSON.parse(currentValue) : {};
30
+ config['outlineOpen'] = isShown;
31
+ localStorage.setItem('sf-editor', JSON.stringify(config));
32
+ };
33
+ exports.setOutlineSetting = setOutlineSetting;
15
34
  const getHeaderList = children => {
16
35
  const headerList = [];
17
36
  children.forEach(node => {
@@ -30,50 +49,65 @@ const Outline = _ref => {
30
49
  } = (0, _reactI18next.useTranslation)(_constants.TRANSLATE_NAMESPACE);
31
50
  const scrollRef = (0, _useScrollContext.useScrollContext)();
32
51
  const [headerList, setHeaderList] = (0, _react.useState)([]);
33
- const [activeId, setActiveId] = (0, _react.useState)('');
52
+ const [isShown, setIsShown] = (0, _react.useState)(false);
53
+ const [scrollLeft, setScrollLeft] = (0, _react.useState)(0);
34
54
  (0, _react.useEffect)(() => {
35
55
  const headerList = getHeaderList(editor.children);
36
56
  setHeaderList(headerList);
37
57
  }, [editor.children]);
38
- const handleScroll = (0, _react.useCallback)(e => {
39
- const scrollTop = scrollRef.current.scrollTop;
40
- const styles = getComputedStyle(scrollRef === null || scrollRef === void 0 ? void 0 : scrollRef.current);
41
- const paddingTop = parseInt(styles.paddingTop);
42
- for (let i = 0; i < headerList.length; i++) {
43
- const headerItem = headerList[i];
44
- const dom = document.getElementById(headerItem.id);
45
- const {
46
- offsetTop,
47
- offsetHeight
48
- } = dom;
49
- const styles = getComputedStyle(dom);
50
- const marginTop = parseInt(styles.marginTop);
51
- if (offsetTop + offsetHeight + marginTop > scrollTop - paddingTop) {
52
- setActiveId(headerItem.id);
53
- break;
54
- }
55
- }
56
- }, [headerList, scrollRef]);
58
+ const updateOutlineState = (0, _react.useCallback)(nextState => {
59
+ setOutlineSetting(nextState);
60
+ setIsShown(nextState);
61
+ const eventBus = _eventBus.default.getInstance();
62
+ eventBus.dispatch(_eventTypes.INTERNAL_EVENTS.OUTLINE_STATE_CHANGED, nextState);
63
+ }, []);
64
+ const toggleShow = (0, _react.useCallback)(() => {
65
+ const nextState = !isShown;
66
+ updateOutlineState(nextState);
67
+ }, [isShown, updateOutlineState]);
57
68
  (0, _react.useEffect)(() => {
58
- let observerRefValue = null;
59
- if (scrollRef.current) {
60
- scrollRef.current.addEventListener('scroll', handleScroll);
61
- observerRefValue = scrollRef.current;
62
- }
69
+ if (!scrollRef.current) return;
70
+ const updateScrollLeft = () => {
71
+ setScrollLeft(scrollRef.current.scrollLeft);
72
+ };
73
+ scrollRef.current.addEventListener('scroll', updateScrollLeft);
63
74
  return () => {
64
- observerRefValue.removeEventListener('scroll', handleScroll);
75
+ scrollRef.current.removeEventListener('scroll', updateScrollLeft);
65
76
  };
66
- }, [handleScroll, scrollRef]);
77
+ }, [scrollRef]);
78
+ (0, _react.useEffect)(() => {
79
+ const outlineState = getOutlineSetting();
80
+ updateOutlineState(outlineState);
81
+ }, [updateOutlineState]);
67
82
  return /*#__PURE__*/_react.default.createElement("div", {
83
+ className: (0, _classnames.default)('sf-editor-outline-wrapper', {
84
+ 'active': isShown
85
+ }),
86
+ style: {
87
+ left: -scrollLeft
88
+ }
89
+ }, /*#__PURE__*/_react.default.createElement("div", {
68
90
  className: "sf-editor-outline"
69
- }, headerList.length === 0 && /*#__PURE__*/_react.default.createElement("div", {
91
+ }, isShown && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
92
+ className: "sf-editor-outline-header"
93
+ }, /*#__PURE__*/_react.default.createElement("h2", {
94
+ className: "sf-editor-outline-header_title"
95
+ }, t('Outline')), /*#__PURE__*/_react.default.createElement("span", {
96
+ className: "sf-editor-outline-header_close iconfont icon-x",
97
+ onClick: toggleShow
98
+ })), headerList.length === 0 ? /*#__PURE__*/_react.default.createElement("div", {
70
99
  className: "empty-container"
71
- }, t('No_outline')), headerList.length > 0 && headerList.map((node, index) => {
72
- return /*#__PURE__*/_react.default.createElement(_outlineItem.default, {
73
- key: index,
74
- node: node,
75
- activeId: activeId
76
- });
77
- }));
100
+ }, t('No_outline')) : /*#__PURE__*/_react.default.createElement("div", {
101
+ className: "sf-editor-outline-list-container"
102
+ }, headerList.map((node, index) => /*#__PURE__*/_react.default.createElement(_outlineItem.default, {
103
+ key: index,
104
+ node: node
105
+ }))))), !isShown && /*#__PURE__*/_react.default.createElement("span", {
106
+ id: "sf-editor-outline-menu",
107
+ className: "sf-editor-outline-menu sf-editor-tooltip iconfont icon-outline",
108
+ onClick: toggleShow
109
+ }, /*#__PURE__*/_react.default.createElement("span", {
110
+ className: "custom-tooltip"
111
+ }, t('Outline'))));
78
112
  };
79
113
  var _default = exports.default = Outline;
@@ -10,23 +10,31 @@ var _react = _interopRequireWildcard(require("react"));
10
10
  var _classnames = _interopRequireDefault(require("classnames"));
11
11
  const OutlineItem = _ref => {
12
12
  let {
13
- node,
14
- activeId
13
+ node
15
14
  } = _ref;
15
+ const [isHighlighted, setIsHighlighted] = (0, _react.useState)(false);
16
+ const onMouseOver = (0, _react.useCallback)(() => {
17
+ setIsHighlighted(true);
18
+ }, []);
19
+ const onMouseOut = (0, _react.useCallback)(() => {
20
+ setIsHighlighted(false);
21
+ }, []);
16
22
  const onItemClick = (0, _react.useCallback)(() => {
17
23
  const {
18
24
  id
19
25
  } = node;
20
26
  document.getElementById(id).scrollIntoView();
21
27
  }, [node]);
22
- const className = (0, _classnames.default)({
23
- 'outline-h2': node.type === 'header2',
24
- 'outline-h3': node.type === 'header3',
25
- 'active': node.id === activeId
28
+ const className = (0, _classnames.default)('sf-editor-outline-item', {
29
+ 'pl-5': node.type === 'header2',
30
+ 'pl-7': node.type === 'header3',
31
+ 'active': isHighlighted
26
32
  });
27
33
  return /*#__PURE__*/_react.default.createElement("div", {
28
34
  className: className,
29
- onClick: onItemClick
35
+ onClick: onItemClick,
36
+ onMouseOver: onMouseOver,
37
+ onMouseOut: onMouseOut
30
38
  }, node.children.map(child => child.text).join(''));
31
39
  };
32
40
  var _default = exports.default = OutlineItem;
@@ -1,45 +1,128 @@
1
+ .sf-editor-outline-wrapper {
2
+ display: flex;
3
+ margin: 20px 30px 20px 16px;
4
+ min-height: 0;
5
+ pointer-events: none;
6
+ position: fixed;
7
+ bottom: 0;
8
+ top: 100px;
9
+ z-index: 101;
10
+ }
11
+
12
+ .sf-editor-outline-wrapper.active {
13
+ pointer-events: all;
14
+ }
15
+
1
16
  .sf-editor-outline {
2
- border-left: 1px solid #ddd;
3
- padding: .5rem 1rem .5rem 0;
17
+ display: flex;
18
+ flex: 1 1;
19
+ flex-direction: column;
20
+ font-size: 14px;
21
+ min-height: 0;
22
+ position: relative;
23
+ width: 220px;
4
24
  }
5
25
 
6
- .sf-editor-outline .outline-h2,
7
- .sf-editor-outline .outline-h3 {
8
- white-space: nowrap;
9
- overflow: hidden;
10
- text-overflow: ellipsis;
26
+ .sf-editor-outline.active {
27
+ pointer-events: all;
11
28
  }
12
29
 
13
- .sf-editor-outline .outline-h2 {
14
- margin-left: 20px;
15
- line-height: 2.5;
16
- color:#364149;
17
- white-space: nowrap;
18
- cursor:pointer;
30
+ .sf-editor-outline-header {
31
+ display: flex;
32
+ justify-content: space-between;
33
+ align-items: center;
34
+ padding: 0.25rem 0;
35
+ color: #999;
36
+ border-bottom: 1px solid #dbdbdb;
19
37
  }
20
38
 
21
- .sf-editor-outline .outline-h2:hover {
22
- color: #eb8205;
39
+ .sf-editor-outline-header_title {
40
+ font-size: 14px;
41
+ line-height: 1.1;
42
+ margin: 0 !important;
43
+ }
44
+
45
+ .sf-editor-outline-header_close {
46
+ cursor: pointer;
47
+ font-size: 14px;
23
48
  }
24
49
 
25
- .sf-editor-outline .outline-h3 {
26
- margin-left: 40px;
27
- line-height: 2.5;
28
- color:#364149;
29
- white-space: nowrap;
30
- cursor:pointer;
50
+ .sf-editor-outline-header_close:hover {
51
+ color: #555;
31
52
  }
32
53
 
33
- .sf-editor-outline .outline-h3:hover {
54
+ .sf-editor-outline-list-container {
55
+ display: flex;
56
+ flex: 1 1;
57
+ flex-direction: column;
58
+ list-style: none;
59
+ overflow-x: hidden;
60
+ overflow-y: auto;
61
+ padding: .5rem 0;
62
+ word-break: break-word;
63
+ }
64
+
65
+ .sf-editor-outline-item {
66
+ padding: 4px 6px 4px 0;
67
+ width: 100%;
68
+ overflow-wrap: anywhere;
69
+ cursor: pointer;
70
+ }
71
+
72
+ .sf-editor-outline-item.active {
34
73
  color: #eb8205;
35
74
  }
36
75
 
37
- .sf-editor-outline .empty-container {
38
- margin-top: 10px;
76
+ .sf-editor-outline-menu {
77
+ line-height: 1;
78
+ font-size: 14px;
79
+ color: #888;
80
+ cursor: pointer;
81
+ width: 28px;
82
+ height: 28px;
83
+ background: #fff;
84
+ border-radius: 0 50% 50% 0;
85
+ box-shadow: 0 0 6px rgba(0, 0, 0, 0.12);
86
+ display: flex;
87
+ align-items: center;
88
+ justify-content: center;
89
+ position: absolute;
90
+ top: 20px;
91
+ left: -15px;;
92
+ pointer-events: all;
93
+ }
94
+
95
+ .sf-editor-outline-menu .custom-tooltip {
96
+ visibility: hidden;
97
+ opacity: 0;
98
+ width: 80px;
99
+ background-color: rgba(0, 0, 0, 0.7);
100
+ color: #fff;
39
101
  text-align: center;
102
+ border-radius: 4px;
103
+ padding: 5px 0;
104
+ position: absolute;
105
+ z-index: 1;
106
+ left: 100%;
107
+ margin-left: 42px;
108
+ transform: translateX(-50%);
109
+ transition: opacity 0.3s;
40
110
  }
41
111
 
42
- .sf-editor-outline .outline-h2.active,
43
- .sf-editor-outline .outline-h3.active {
44
- color: #eb8205;
112
+ .sf-editor-outline-menu:hover .custom-tooltip {
113
+ visibility: visible;
114
+ opacity: 1;
115
+ }
116
+
117
+ .sf-editor-outline-menu.disabled {
118
+ opacity: .65;
119
+ }
120
+
121
+ .sf-editor-outline-menu:not(.disabled):hover {
122
+ color: #333;
123
+ }
124
+
125
+ .sf-editor-outline .empty-container {
126
+ margin-top: 10px;
127
+ text-align: center;
45
128
  }
@@ -19,8 +19,8 @@ function EditorHelp(_ref) {
19
19
  } = _ref;
20
20
  const [isShowHelpInfo, setIsShowHelpInfo] = (0, _react.useState)(false);
21
21
  const [isShowArticleInfo, setIsShowArticleInfo] = (0, _react.useState)(false);
22
- const updateArticleInfoState = (0, _react.useCallback)(state => {
23
- setIsShowArticleInfo(state);
22
+ const updateArticleInfoState = (0, _react.useCallback)(() => {
23
+ setIsShowArticleInfo(prevState => !prevState);
24
24
  setIsShowHelpInfo(false);
25
25
  }, []);
26
26
  const updateHelpInfoState = (0, _react.useCallback)(state => {
@@ -29,20 +29,20 @@ function EditorHelp(_ref) {
29
29
  }, []);
30
30
  (0, _react.useEffect)(() => {
31
31
  const eventBus = _eventBus.default.getInstance();
32
- const unsubscribeArticleInfo = eventBus.subscribe(_eventTypes.INTERNAL_EVENTS.ON_ARTICLE_INFO_TOGGLE, updateArticleInfoState);
32
+ const unsubscribeArticleInfo = eventBus.subscribe(_eventTypes.EXTERNAL_EVENTS.ON_ARTICLE_INFO_TOGGLE, updateArticleInfoState);
33
33
  const unsubscribeHelpInfo = eventBus.subscribe(_eventTypes.EXTERNAL_EVENTS.ON_HELP_INFO_TOGGLE, updateHelpInfoState);
34
34
  return () => {
35
35
  unsubscribeHelpInfo();
36
36
  unsubscribeArticleInfo();
37
37
  };
38
38
  // eslint-disable-next-line react-hooks/exhaustive-deps
39
- }, []);
39
+ }, [updateArticleInfoState, updateHelpInfoState]);
40
40
  const containerClass = (0, _classnames.default)('sf-markdown-help-wrapper', {
41
41
  'active': isShowArticleInfo || isShowHelpInfo
42
42
  });
43
43
  return /*#__PURE__*/_react.default.createElement("div", {
44
44
  className: containerClass
45
- }, isShowArticleInfo && /*#__PURE__*/_react.default.createElement(_articleInfo.default, {
46
- children: children
45
+ }, /*#__PURE__*/_react.default.createElement(_articleInfo.default, {
46
+ isVisible: isShowArticleInfo
47
47
  }), isShowHelpInfo && /*#__PURE__*/_react.default.createElement(_hotkeysHelper.default, null));
48
48
  }
@@ -1,15 +1,16 @@
1
1
  .sf-markdown-help-wrapper {
2
2
  display: none;
3
- background-color: #fff;
4
- border-left: 1px solid #eee;
5
- flex: 0 0 300px;
6
3
  height: 100%;
7
4
  overflow-x: hidden;
8
5
  overflow-y: auto;
9
- width: 300px;
6
+ position: relative;
10
7
  }
11
8
 
12
9
  .sf-markdown-help-wrapper.active {
13
10
  display: flex;
14
11
  flex-direction: column;
12
+ position: relative;
13
+ right: 0;
14
+ width: auto;
15
+ overflow: visible;
15
16
  }
@@ -18,6 +18,8 @@ var _core = require("../../extension/core");
18
18
  var _useScrollContext = require("../../hooks/use-scroll-context");
19
19
  var _useInsertImage = _interopRequireDefault(require("../../hooks/use-insert-image"));
20
20
  var _common = require("../../utils/common");
21
+ var _outline = _interopRequireDefault(require("../../containers/outline"));
22
+ var _eventTypes = require("../../constants/event-types");
21
23
  require("./style.css");
22
24
  const isMacOS = (0, _common.isMac)();
23
25
  function SlateEditor(_ref) {
@@ -31,6 +33,7 @@ function SlateEditor(_ref) {
31
33
  children
32
34
  } = _ref;
33
35
  const [slateValue, setSlateValue] = (0, _react.useState)(value);
36
+ const [containerStyle, setContainerStyle] = (0, _react.useState)({});
34
37
  const scrollRef = (0, _react.useRef)(null);
35
38
  const editor = (0, _react.useMemo)(() => (0, _withPropsEditor.default)(_extension.baseEditor, {
36
39
  editorApi,
@@ -41,6 +44,33 @@ function SlateEditor(_ref) {
41
44
  }, [editor]);
42
45
  (0, _useInsertImage.default)(editor);
43
46
  const decorate = (0, _extension.useHighlight)(editor);
47
+
48
+ // Adjust article container margin-left value according to isShown of the outline and width of window
49
+ const handleWindowResize = (0, _react.useCallback)(newIsShown => {
50
+ const rect = scrollRef.current.getBoundingClientRect();
51
+ const articleElement = document.querySelector('.article');
52
+ const articleRect = articleElement ? articleElement.getBoundingClientRect() : null;
53
+ if (newIsShown && articleRect && (rect.width - articleRect.width) / 2 < 280) {
54
+ setContainerStyle({
55
+ marginLeft: 280
56
+ });
57
+ } else {
58
+ setContainerStyle({});
59
+ }
60
+ }, []);
61
+ (0, _react.useEffect)(() => {
62
+ const eventBus = _eventBus.default.getInstance();
63
+ const unsubscribeOutline = eventBus.subscribe(_eventTypes.INTERNAL_EVENTS.OUTLINE_STATE_CHANGED, handleWindowResize);
64
+ return unsubscribeOutline;
65
+ }, [handleWindowResize]);
66
+ (0, _react.useEffect)(() => {
67
+ handleWindowResize();
68
+ window.addEventListener('resize', handleWindowResize);
69
+ return () => {
70
+ window.removeEventListener('resize', handleWindowResize);
71
+ };
72
+ // eslint-disable-next-line react-hooks/exhaustive-deps
73
+ }, []);
44
74
  const onChange = (0, _react.useCallback)(value => {
45
75
  setSlateValue(value);
46
76
  if (editor.forceNormalize) return;
@@ -124,7 +154,12 @@ function SlateEditor(_ref) {
124
154
  ref: scrollRef,
125
155
  className: "sf-slate-scroll-container ".concat(isMacOS ? '' : 'isWin')
126
156
  }, /*#__PURE__*/_react.default.createElement("div", {
127
- className: "sf-slate-article-container"
157
+ className: "sf-slate-article-content"
158
+ }, /*#__PURE__*/_react.default.createElement(_outline.default, {
159
+ editor: editor
160
+ }), /*#__PURE__*/_react.default.createElement("div", {
161
+ className: "sf-slate-article-container",
162
+ style: containerStyle
128
163
  }, /*#__PURE__*/_react.default.createElement("div", {
129
164
  className: "article"
130
165
  }, /*#__PURE__*/_react.default.createElement(_extension.SetNodeToDecorations, null), /*#__PURE__*/_react.default.createElement(_slateReact.Editable, {
@@ -133,7 +168,7 @@ function SlateEditor(_ref) {
133
168
  renderLeaf: _extension.renderLeaf,
134
169
  onKeyDown: eventProxy.onKeyDown,
135
170
  onCopy: eventProxy.onCopy
136
- })))), /*#__PURE__*/_react.default.createElement(_editorHelp.default, {
171
+ }))))), /*#__PURE__*/_react.default.createElement(_editorHelp.default, {
137
172
  children: children
138
173
  })))));
139
174
  }
@@ -4,6 +4,7 @@
4
4
  flex-direction: column;
5
5
  min-height: 0;
6
6
  min-width: 0;
7
+ position:relative;
7
8
  }
8
9
 
9
10
  .sf-slate-editor-container .sf-slate-editor-toolbar {
@@ -29,10 +30,16 @@
29
30
  }
30
31
 
31
32
  .sf-slate-editor-container .sf-slate-scroll-container {
33
+ z-index: 100;
34
+ overflow-x: hidden;
35
+ overflow-y: auto;
32
36
  height: 100%;
33
37
  width: 100%;
34
38
  background-color: #fafaf9;
35
39
  overflow: auto;
40
+ flex: 1 1;
41
+ display: flex;
42
+ position: relative;
36
43
  }
37
44
 
38
45
  .sf-slate-editor-container .sf-slate-scroll-container.isWin::-webkit-scrollbar{
@@ -49,6 +56,13 @@
49
56
  border-radius: 10px;
50
57
  }
51
58
 
59
+ .sf-slate-scroll-container .sf-slate-article-content{
60
+ display: flex;
61
+ position: absolute;
62
+ min-width: 1100px;
63
+ width: 100%;
64
+ }
65
+
52
66
  .sf-slate-editor-container .sf-slate-article-container {
53
67
  flex: 1;
54
68
  position: relative;
@@ -57,6 +71,8 @@
57
71
  margin: 0 auto;
58
72
  padding-top: 20px;
59
73
  padding-bottom: 20px;
74
+ width: 794px;
75
+ top: 0px;
60
76
  }
61
77
 
62
78
  .sf-slate-editor-container .sf-slate-editor-content .article {
@@ -111,11 +127,6 @@
111
127
  margin: 20px !important;
112
128
  padding: 20px 30px;
113
129
  }
114
-
115
- .sf-markdown-help-wrapper {
116
- width: 250px !important;
117
- flex: 0 0 250px;
118
- }
119
130
  }
120
131
 
121
132
  @media (max-width: 768px) {
@@ -91,12 +91,7 @@ const Toolbar = _ref => {
91
91
  isSupportInsertSeafileImage: isSupportInsertSeafileImage
92
92
  })), isSupportFormula && /*#__PURE__*/_react.default.createElement(_menu10.default, commonProps), isSupportColumn && /*#__PURE__*/_react.default.createElement(_menu12.default, commonProps)), isShowSubTableMenu && /*#__PURE__*/_react.default.createElement(_commons.MenuGroup, {
93
93
  className: "sf-menu-group sf-table-operations-group"
94
- }, /*#__PURE__*/_react.default.createElement(_tableOperator.AlignmentDropDown, commonProps), /*#__PURE__*/_react.default.createElement(_tableOperator.ColumnOperationDropDownList, commonProps), /*#__PURE__*/_react.default.createElement(_tableOperator.RowOperationDropDownList, commonProps), /*#__PURE__*/_react.default.createElement(_tableOperator.RemoveTableMenu, commonProps)), /*#__PURE__*/_react.default.createElement(_commons.MenuGroup, null, /*#__PURE__*/_react.default.createElement(_menu11.default, commonProps)), isRichEditor && /*#__PURE__*/_react.default.createElement("div", {
95
- className: "sf-slate-article-info-control",
96
- onClick: updateArticleInfoState
97
- }, /*#__PURE__*/_react.default.createElement("span", {
98
- className: sideIconClass
99
- })), !isRichEditor && /*#__PURE__*/_react.default.createElement("div", {
94
+ }, /*#__PURE__*/_react.default.createElement(_tableOperator.AlignmentDropDown, commonProps), /*#__PURE__*/_react.default.createElement(_tableOperator.ColumnOperationDropDownList, commonProps), /*#__PURE__*/_react.default.createElement(_tableOperator.RowOperationDropDownList, commonProps), /*#__PURE__*/_react.default.createElement(_tableOperator.RemoveTableMenu, commonProps)), /*#__PURE__*/_react.default.createElement(_commons.MenuGroup, null, /*#__PURE__*/_react.default.createElement(_menu11.default, commonProps)), !isRichEditor && /*#__PURE__*/_react.default.createElement("div", {
100
95
  className: "sf-slate-help-info-control",
101
96
  onClick: onHelpIconToggle
102
97
  }, /*#__PURE__*/_react.default.createElement("span", {
@@ -6,9 +6,9 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  var _slate = require("slate");
8
8
  var _seafileEditor = require("@seafile/seafile-editor");
9
+ const PREVIEW_TEXT_LENGTH = 150;
9
10
  const getPreviewContent = function (content) {
10
11
  let isMarkdown = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
11
- let isShowAllPreviewText = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
12
12
  const slateNodes = isMarkdown ? (0, _seafileEditor.mdStringToSlate)(content) : content;
13
13
  let previewContent = {
14
14
  previewText: '',
@@ -20,7 +20,7 @@ const getPreviewContent = function (content) {
20
20
  }
21
21
  };
22
22
  getPreviewInfo(slateNodes, previewContent);
23
- getPreviewText(slateNodes, previewContent, isShowAllPreviewText);
23
+ getPreviewText(slateNodes, previewContent);
24
24
  return previewContent;
25
25
  };
26
26
  const getPreviewInfo = (nodes, previewContent) => {
@@ -44,16 +44,14 @@ const getPreviewInfo = (nodes, previewContent) => {
44
44
  nodeIndex++;
45
45
  }
46
46
  };
47
- const getPreviewText = function (content, previewContent) {
48
- let isShowAllPreviewText = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
47
+ const getPreviewText = (content, previewContent) => {
49
48
  let previewText = '';
50
- console.log(isShowAllPreviewText);
51
49
  for (let index = 0; index < content.length; index++) {
52
- const nodeText = getTextOfNode(content[index]) || '';
53
- if (isShowAllPreviewText) {
54
- previewText += nodeText + ' ';
55
- } else {
56
- previewText += nodeText.slice(0, 150) + ' ';
50
+ previewText += getTextOfNode(content[index]) + ' ';
51
+ let textLength = previewText.length;
52
+ if (textLength >= PREVIEW_TEXT_LENGTH) {
53
+ previewText = textLength > PREVIEW_TEXT_LENGTH ? previewText.slice(0, PREVIEW_TEXT_LENGTH) : previewText;
54
+ break;
57
55
  }
58
56
  }
59
57
  previewContent.previewText = previewText;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seafile/seafile-editor",
3
- "version": "1.0.117-beta.1",
3
+ "version": "1.0.118beta",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {