@manuscripts/body-editor 2.8.6 → 2.8.7

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.
@@ -94,7 +94,8 @@ const canInsert = (type) => (state) => {
94
94
  const { $from, $to } = state.selection;
95
95
  if (($from.node().type === transform_1.schema.nodes.title ||
96
96
  $from.node().type === transform_1.schema.nodes.section_title) &&
97
- $from.pos === $to.pos) {
97
+ $from.pos === $to.pos &&
98
+ type !== transform_1.schema.nodes.text) {
98
99
  return false;
99
100
  }
100
101
  if ((0, transform_1.isElementNodeType)(type) &&
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.openInsertSpecialCharacterDialog = void 0;
30
+ const style_guide_1 = require("@manuscripts/style-guide");
31
+ const react_1 = __importStar(require("react"));
32
+ const react_select_1 = __importDefault(require("react-select"));
33
+ const styled_components_1 = __importDefault(require("styled-components"));
34
+ const editor_props_1 = require("../../plugins/editor-props");
35
+ const ReactSubView_1 = __importDefault(require("../../views/ReactSubView"));
36
+ const unicodeRanges = [
37
+ { label: 'Latin', value: [0x0100, 0x024f] },
38
+ { label: 'Greek and Coptic', value: [0x0370, 0x03ff] },
39
+ { label: 'Mathematical Operators', value: [0x2200, 0x22ff] },
40
+ { label: 'Arrows', value: [0x2190, 0x21ff] },
41
+ ];
42
+ const reservedCharacters = new Set([
43
+ 0x0380, 0x0381, 0x0382, 0x0383, 0x03a2, 0x0378, 0x0379, 0x038b, 0x038d,
44
+ ]);
45
+ const generateCharacters = (start, end) => Array.from({ length: end - start + 1 }, (_, i) => start + i)
46
+ .filter((c) => !reservedCharacters.has(c))
47
+ .map((c) => String.fromCharCode(c));
48
+ const InsertSpecialCharacterDialog = ({ view, }) => {
49
+ const [isOpen, setOpen] = (0, react_1.useState)(true);
50
+ const [range, setRange] = (0, react_1.useState)(unicodeRanges[0].value);
51
+ const handleRangeChange = (range) => range && setRange(range.value);
52
+ const handleClose = () => setOpen(false);
53
+ const addCharacter = (event) => view.dispatch(view.state.tr.insertText(event.currentTarget.value, view.state.selection.from));
54
+ return (react_1.default.createElement(style_guide_1.StyledModal, { isOpen: isOpen, onRequestClose: handleClose, shouldCloseOnOverlayClick: true },
55
+ react_1.default.createElement(Container, { "data-cy": "special-characters-modal" },
56
+ react_1.default.createElement(style_guide_1.ModalHeader, null,
57
+ react_1.default.createElement(style_guide_1.CloseButton, { onClick: handleClose, "data-cy": "modal-close-button" })),
58
+ react_1.default.createElement(StyledModalBody, null,
59
+ react_1.default.createElement(StyledModalSidebar, null,
60
+ react_1.default.createElement(style_guide_1.ModalSidebarHeader, null,
61
+ react_1.default.createElement(style_guide_1.ModalSidebarTitle, null, "Insert special characters")),
62
+ react_1.default.createElement(StyledSidebarContent, null,
63
+ react_1.default.createElement(react_select_1.default, { onChange: handleRangeChange, classNamePrefix: 'special-characters-ranges-select', defaultValue: unicodeRanges[0], options: unicodeRanges, components: {
64
+ Option: OptionComponent,
65
+ }, menuPosition: "fixed" }),
66
+ react_1.default.createElement(CharactersSetContainer, null,
67
+ react_1.default.createElement(CharactersSet, null, generateCharacters(range[0], range[1]).map((character) => (react_1.default.createElement(Character, { key: character, value: character, onClick: addCharacter, "data-cy": "special-character" }, character)))))),
68
+ react_1.default.createElement(ButtonsContainer, null,
69
+ react_1.default.createElement(style_guide_1.PrimaryButton, { onClick: handleClose }, "Close")))))));
70
+ };
71
+ const OptionComponent = ({ innerProps, data, }) => {
72
+ return (react_1.default.createElement(OptionWrapper, Object.assign({}, innerProps, { ref: null }), data.label));
73
+ };
74
+ const Container = (0, styled_components_1.default)(style_guide_1.ModalContainer) `
75
+ padding: 8px;
76
+ `;
77
+ const StyledModalSidebar = (0, styled_components_1.default)(style_guide_1.ModalSidebar) `
78
+ background: white;
79
+ width: 30vw;
80
+ `;
81
+ const StyledModalBody = (0, styled_components_1.default)(style_guide_1.ModalBody) `
82
+ height: 60vh;
83
+ `;
84
+ const StyledSidebarContent = (0, styled_components_1.default)(style_guide_1.SidebarContent) `
85
+ display: flex;
86
+ flex-direction: column;
87
+ `;
88
+ const ButtonsContainer = (0, styled_components_1.default)(style_guide_1.ButtonGroup) `
89
+ padding-top: ${(props) => props.theme.grid.unit * 5}px;
90
+ `;
91
+ const OptionWrapper = styled_components_1.default.div `
92
+ padding-left: ${(props) => props.theme.grid.unit * 4}px;
93
+ padding-top: ${(props) => props.theme.grid.unit * 2}px;
94
+ padding-bottom: ${(props) => props.theme.grid.unit * 2}px;
95
+
96
+ background-color: ${(props) => props.focused ? props.theme.colors.background.fifth : 'transparent'};
97
+
98
+ &:hover {
99
+ background-color: ${(props) => props.theme.colors.background.fifth};
100
+ }
101
+ `;
102
+ const CharactersSetContainer = styled_components_1.default.div `
103
+ flex: 1;
104
+ overflow-y: scroll;
105
+ margin: 18px 0;
106
+ border: 1px solid #ddd;
107
+ `;
108
+ const CharactersSet = (0, styled_components_1.default)(style_guide_1.IconButtonGroup) `
109
+ display: grid;
110
+ grid-template-columns: repeat(auto-fit, minmax(28px, max-content));
111
+ height: ${(props) => props.theme.grid.unit * 8}px;
112
+ `;
113
+ const Character = (0, styled_components_1.default)(style_guide_1.IconButton) `
114
+ border-bottom: 1px solid #ddd;
115
+ border-right: 1px solid #ddd;
116
+ border-radius: unset;
117
+
118
+ :hover {
119
+ background-color: #f0f0f0 !important;
120
+ }
121
+
122
+ :active,
123
+ :focus {
124
+ color: inherit !important;
125
+ border-bottom: 1px solid #ddd !important;
126
+ border-right: 1px solid #ddd !important;
127
+ }
128
+ `;
129
+ const openInsertSpecialCharacterDialog = (view) => {
130
+ if (!view) {
131
+ return;
132
+ }
133
+ const { state } = view;
134
+ const props = (0, editor_props_1.getEditorProps)(state);
135
+ const dialog = (0, ReactSubView_1.default)(props, InsertSpecialCharacterDialog, { view }, state.doc, () => 0, view);
136
+ document.body.appendChild(dialog);
137
+ };
138
+ exports.openInsertSpecialCharacterDialog = openInsertSpecialCharacterDialog;
package/dist/cjs/menus.js CHANGED
@@ -23,6 +23,7 @@ const commands_1 = require("./commands");
23
23
  const InsertEmbedDialog_1 = require("./components/toolbar/InsertEmbedDialog");
24
24
  const InsertTableDialog_1 = require("./components/toolbar/InsertTableDialog");
25
25
  const ListMenuItem_1 = require("./components/toolbar/ListMenuItem");
26
+ const InsertSpecialCharacter_1 = require("./components/views/InsertSpecialCharacter");
26
27
  const hierarchy_1 = require("./lib/hierarchy");
27
28
  const editor_props_1 = require("./plugins/editor-props");
28
29
  const getEditorMenus = (editor) => {
@@ -317,6 +318,12 @@ const getEditorMenus = (editor) => {
317
318
  isEnabled: isCommandValid((0, commands_1.canInsert)(transform_1.schema.nodes.inline_footnote)),
318
319
  run: doCommand(commands_1.insertInlineFootnote),
319
320
  },
321
+ {
322
+ id: 'insert-special-character',
323
+ label: 'Special Characters',
324
+ isEnabled: isCommandValid((0, commands_1.canInsert)(transform_1.schema.nodes.text)),
325
+ run: () => (0, InsertSpecialCharacter_1.openInsertSpecialCharacterDialog)(editor.view),
326
+ },
320
327
  {
321
328
  id: 'insert-comment',
322
329
  label: 'Comment',
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MATHJAX_VERSION = exports.VERSION = void 0;
4
- exports.VERSION = '2.8.6';
4
+ exports.VERSION = '2.8.7';
5
5
  exports.MATHJAX_VERSION = '3.2.2';
@@ -86,7 +86,8 @@ export const canInsert = (type) => (state) => {
86
86
  const { $from, $to } = state.selection;
87
87
  if (($from.node().type === schema.nodes.title ||
88
88
  $from.node().type === schema.nodes.section_title) &&
89
- $from.pos === $to.pos) {
89
+ $from.pos === $to.pos &&
90
+ type !== schema.nodes.text) {
90
91
  return false;
91
92
  }
92
93
  if (isElementNodeType(type) &&
@@ -0,0 +1,108 @@
1
+ import { ButtonGroup, CloseButton, IconButton, IconButtonGroup, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, PrimaryButton, SidebarContent, StyledModal, } from '@manuscripts/style-guide';
2
+ import React, { useState } from 'react';
3
+ import Select from 'react-select';
4
+ import styled from 'styled-components';
5
+ import { getEditorProps } from '../../plugins/editor-props';
6
+ import ReactSubView from '../../views/ReactSubView';
7
+ const unicodeRanges = [
8
+ { label: 'Latin', value: [0x0100, 0x024f] },
9
+ { label: 'Greek and Coptic', value: [0x0370, 0x03ff] },
10
+ { label: 'Mathematical Operators', value: [0x2200, 0x22ff] },
11
+ { label: 'Arrows', value: [0x2190, 0x21ff] },
12
+ ];
13
+ const reservedCharacters = new Set([
14
+ 0x0380, 0x0381, 0x0382, 0x0383, 0x03a2, 0x0378, 0x0379, 0x038b, 0x038d,
15
+ ]);
16
+ const generateCharacters = (start, end) => Array.from({ length: end - start + 1 }, (_, i) => start + i)
17
+ .filter((c) => !reservedCharacters.has(c))
18
+ .map((c) => String.fromCharCode(c));
19
+ const InsertSpecialCharacterDialog = ({ view, }) => {
20
+ const [isOpen, setOpen] = useState(true);
21
+ const [range, setRange] = useState(unicodeRanges[0].value);
22
+ const handleRangeChange = (range) => range && setRange(range.value);
23
+ const handleClose = () => setOpen(false);
24
+ const addCharacter = (event) => view.dispatch(view.state.tr.insertText(event.currentTarget.value, view.state.selection.from));
25
+ return (React.createElement(StyledModal, { isOpen: isOpen, onRequestClose: handleClose, shouldCloseOnOverlayClick: true },
26
+ React.createElement(Container, { "data-cy": "special-characters-modal" },
27
+ React.createElement(ModalHeader, null,
28
+ React.createElement(CloseButton, { onClick: handleClose, "data-cy": "modal-close-button" })),
29
+ React.createElement(StyledModalBody, null,
30
+ React.createElement(StyledModalSidebar, null,
31
+ React.createElement(ModalSidebarHeader, null,
32
+ React.createElement(ModalSidebarTitle, null, "Insert special characters")),
33
+ React.createElement(StyledSidebarContent, null,
34
+ React.createElement(Select, { onChange: handleRangeChange, classNamePrefix: 'special-characters-ranges-select', defaultValue: unicodeRanges[0], options: unicodeRanges, components: {
35
+ Option: OptionComponent,
36
+ }, menuPosition: "fixed" }),
37
+ React.createElement(CharactersSetContainer, null,
38
+ React.createElement(CharactersSet, null, generateCharacters(range[0], range[1]).map((character) => (React.createElement(Character, { key: character, value: character, onClick: addCharacter, "data-cy": "special-character" }, character)))))),
39
+ React.createElement(ButtonsContainer, null,
40
+ React.createElement(PrimaryButton, { onClick: handleClose }, "Close")))))));
41
+ };
42
+ const OptionComponent = ({ innerProps, data, }) => {
43
+ return (React.createElement(OptionWrapper, Object.assign({}, innerProps, { ref: null }), data.label));
44
+ };
45
+ const Container = styled(ModalContainer) `
46
+ padding: 8px;
47
+ `;
48
+ const StyledModalSidebar = styled(ModalSidebar) `
49
+ background: white;
50
+ width: 30vw;
51
+ `;
52
+ const StyledModalBody = styled(ModalBody) `
53
+ height: 60vh;
54
+ `;
55
+ const StyledSidebarContent = styled(SidebarContent) `
56
+ display: flex;
57
+ flex-direction: column;
58
+ `;
59
+ const ButtonsContainer = styled(ButtonGroup) `
60
+ padding-top: ${(props) => props.theme.grid.unit * 5}px;
61
+ `;
62
+ const OptionWrapper = styled.div `
63
+ padding-left: ${(props) => props.theme.grid.unit * 4}px;
64
+ padding-top: ${(props) => props.theme.grid.unit * 2}px;
65
+ padding-bottom: ${(props) => props.theme.grid.unit * 2}px;
66
+
67
+ background-color: ${(props) => props.focused ? props.theme.colors.background.fifth : 'transparent'};
68
+
69
+ &:hover {
70
+ background-color: ${(props) => props.theme.colors.background.fifth};
71
+ }
72
+ `;
73
+ const CharactersSetContainer = styled.div `
74
+ flex: 1;
75
+ overflow-y: scroll;
76
+ margin: 18px 0;
77
+ border: 1px solid #ddd;
78
+ `;
79
+ const CharactersSet = styled(IconButtonGroup) `
80
+ display: grid;
81
+ grid-template-columns: repeat(auto-fit, minmax(28px, max-content));
82
+ height: ${(props) => props.theme.grid.unit * 8}px;
83
+ `;
84
+ const Character = styled(IconButton) `
85
+ border-bottom: 1px solid #ddd;
86
+ border-right: 1px solid #ddd;
87
+ border-radius: unset;
88
+
89
+ :hover {
90
+ background-color: #f0f0f0 !important;
91
+ }
92
+
93
+ :active,
94
+ :focus {
95
+ color: inherit !important;
96
+ border-bottom: 1px solid #ddd !important;
97
+ border-right: 1px solid #ddd !important;
98
+ }
99
+ `;
100
+ export const openInsertSpecialCharacterDialog = (view) => {
101
+ if (!view) {
102
+ return;
103
+ }
104
+ const { state } = view;
105
+ const props = getEditorProps(state);
106
+ const dialog = ReactSubView(props, InsertSpecialCharacterDialog, { view }, state.doc, () => 0, view);
107
+ document.body.appendChild(dialog);
108
+ };
package/dist/es/menus.js CHANGED
@@ -20,6 +20,7 @@ import { activateSearchReplace, addInlineComment, blockActive, canInsert, insert
20
20
  import { openEmbedDialog } from './components/toolbar/InsertEmbedDialog';
21
21
  import { openInsertTableDialog } from './components/toolbar/InsertTableDialog';
22
22
  import { ListMenuItem } from './components/toolbar/ListMenuItem';
23
+ import { openInsertSpecialCharacterDialog } from './components/views/InsertSpecialCharacter';
23
24
  import { deleteClosestParentElement, findClosestParentElementNodeName, } from './lib/hierarchy';
24
25
  import { getEditorProps } from './plugins/editor-props';
25
26
  export const getEditorMenus = (editor) => {
@@ -314,6 +315,12 @@ export const getEditorMenus = (editor) => {
314
315
  isEnabled: isCommandValid(canInsert(schema.nodes.inline_footnote)),
315
316
  run: doCommand(insertInlineFootnote),
316
317
  },
318
+ {
319
+ id: 'insert-special-character',
320
+ label: 'Special Characters',
321
+ isEnabled: isCommandValid(canInsert(schema.nodes.text)),
322
+ run: () => openInsertSpecialCharacterDialog(editor.view),
323
+ },
317
324
  {
318
325
  id: 'insert-comment',
319
326
  label: 'Comment',
@@ -1,2 +1,2 @@
1
- export const VERSION = '2.8.6';
1
+ export const VERSION = '2.8.7';
2
2
  export const MATHJAX_VERSION = '3.2.2';
@@ -0,0 +1,2 @@
1
+ import { EditorView } from 'prosemirror-view';
2
+ export declare const openInsertSpecialCharacterDialog: (view?: EditorView) => void;
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "2.8.6";
1
+ export declare const VERSION = "2.8.7";
2
2
  export declare const MATHJAX_VERSION = "3.2.2";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@manuscripts/body-editor",
3
3
  "description": "Prosemirror components for editing and viewing manuscripts",
4
- "version": "2.8.6",
4
+ "version": "2.8.7",
5
5
  "repository": "github:Atypon-OpenSource/manuscripts-body-editor",
6
6
  "license": "Apache-2.0",
7
7
  "main": "dist/cjs",
@@ -1173,3 +1173,11 @@ th:hover > .table-context-menu-button,
1173
1173
  .search-result.search-result-selected {
1174
1174
  background-color: #ffbdf8;
1175
1175
  }
1176
+
1177
+ .special-characters-ranges-select__control {
1178
+ width: fit-content;
1179
+ }
1180
+
1181
+ .special-characters-ranges-select__menu {
1182
+ min-width: 220px;
1183
+ }