@manuscripts/body-editor 3.18.5 → 3.18.6

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.
Files changed (32) hide show
  1. package/dist/cjs/components/references/CitationEditor.js +5 -5
  2. package/dist/cjs/components/references/InsertCitationModal.js +142 -0
  3. package/dist/cjs/components/references/ReferenceSearchResults.js +2 -2
  4. package/dist/cjs/components/references/ReferenceSearchSection.js +16 -10
  5. package/dist/cjs/components/references/SearchInput.js +1 -8
  6. package/dist/cjs/versions.js +1 -1
  7. package/dist/cjs/views/citation_editable.js +1 -0
  8. package/dist/es/components/references/CitationEditor.js +5 -5
  9. package/dist/es/components/references/InsertCitationModal.js +102 -0
  10. package/dist/es/components/references/ReferenceSearchResults.js +2 -2
  11. package/dist/es/components/references/ReferenceSearchSection.js +16 -10
  12. package/dist/es/components/references/SearchInput.js +0 -7
  13. package/dist/es/versions.js +1 -1
  14. package/dist/es/views/citation_editable.js +1 -0
  15. package/dist/types/components/references/CitationEditor.d.ts +1 -0
  16. package/dist/types/components/references/{ReferenceSearch.d.ts → InsertCitationModal.d.ts} +2 -1
  17. package/dist/types/components/references/ReferenceSearchResults.d.ts +1 -0
  18. package/dist/types/components/references/ReferenceSearchSection.d.ts +1 -0
  19. package/dist/types/components/references/SearchInput.d.ts +0 -1
  20. package/dist/types/versions.d.ts +1 -1
  21. package/package.json +2 -2
  22. package/src/components/references/CitationEditor.tsx +8 -4
  23. package/src/components/references/InsertCitationModal.tsx +198 -0
  24. package/src/components/references/ReferenceSearchResults.tsx +15 -2
  25. package/src/components/references/ReferenceSearchSection.tsx +19 -10
  26. package/src/components/references/SearchInput.tsx +0 -8
  27. package/src/versions.ts +1 -1
  28. package/src/views/citation_editable.ts +1 -0
  29. package/styles/popper.css +4 -0
  30. package/dist/cjs/components/references/ReferenceSearch.js +0 -133
  31. package/dist/es/components/references/ReferenceSearch.js +0 -93
  32. package/src/components/references/ReferenceSearch.tsx +0 -149
@@ -35,7 +35,7 @@ import { cleanItemValues } from '../../lib/utils'
35
35
  import { BibliographyItemSource } from './BibliographyItemSource'
36
36
  import { CitedItem, CitedItems } from './CitationViewer'
37
37
  import { ReferenceLine } from './ReferenceLine'
38
- import { ReferenceSearch } from './ReferenceSearch'
38
+ import { InsertCitationModal } from './InsertCitationModal'
39
39
  import { ReferencesModal } from './ReferencesModal'
40
40
 
41
41
  const Container = withFocusTrap(styled.div``)
@@ -63,6 +63,7 @@ export interface CitationEditorProps {
63
63
  onSave: (item: BibliographyItemAttrs[]) => void
64
64
  onDelete: (item: BibliographyItemAttrs) => void
65
65
  onCancel: () => void
66
+ isNodeDeleted: () => boolean
66
67
  canEdit: boolean
67
68
  }
68
69
 
@@ -81,6 +82,7 @@ export const CitationEditor: React.FC<CitationEditorProps> = ({
81
82
  onUncite,
82
83
  onCancel,
83
84
  canEdit,
85
+ isNodeDeleted,
84
86
  }) => {
85
87
  const [items, dispatchItems] = useReducer(itemsReducer, $items)
86
88
  const [rids, dispatchRids] = useReducer(ridsReducer, $rids)
@@ -181,9 +183,10 @@ export const CitationEditor: React.FC<CitationEditorProps> = ({
181
183
  }
182
184
  if (searching) {
183
185
  return (
184
- <ReferenceSearch
186
+ <InsertCitationModal
185
187
  sources={sources}
186
188
  items={items}
189
+ citationCounts={citationCounts}
187
190
  onAdd={handleAdd}
188
191
  onCite={(items) => {
189
192
  setSearching(false)
@@ -193,12 +196,13 @@ export const CitationEditor: React.FC<CitationEditorProps> = ({
193
196
  />
194
197
  )
195
198
  }
196
- if (!rids.length) {
199
+ if (!rids.length && !isNodeDeleted()) {
197
200
  return (
198
- <ReferenceSearch
201
+ <InsertCitationModal
199
202
  query={query}
200
203
  sources={sources}
201
204
  items={items}
205
+ citationCounts={citationCounts}
202
206
  onAdd={handleAdd}
203
207
  onCite={handleCite}
204
208
  onCancel={onCancel}
@@ -0,0 +1,198 @@
1
+ /*!
2
+ * © 2023 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import {
18
+ AddNewIcon,
19
+ ButtonGroup,
20
+ CloseButton,
21
+ IconTextButton,
22
+ ModalContainer,
23
+ ModalHeader,
24
+ ModalSidebar,
25
+ ModalSidebarHeader,
26
+ ModalSidebarTitle,
27
+ PrimaryButton,
28
+ SidebarContent,
29
+ StyledModal,
30
+ TertiaryButton,
31
+ withFocusTrap,
32
+ } from '@manuscripts/style-guide'
33
+ import { BibliographyItemAttrs } from '@manuscripts/transform'
34
+ import { debounce } from 'lodash'
35
+ import React, { useEffect, useMemo, useState } from 'react'
36
+ import styled from 'styled-components'
37
+
38
+ import { StyledModalBody } from '../form/CreateModalStyles'
39
+ import {
40
+ BibliographyItemSource,
41
+ DocumentReferenceSource,
42
+ } from './BibliographyItemSource'
43
+ import { ReferenceSearchSection } from './ReferenceSearchSection'
44
+ import { SearchInput } from './SearchInput'
45
+
46
+ const Container = withFocusTrap(ModalContainer)
47
+
48
+ const StyledModalSidebar = styled(ModalSidebar)`
49
+ background: white;
50
+ width: 44vw;
51
+ padding: ${(props) => props.theme.grid.unit * 6}px;
52
+ `
53
+
54
+ const StyledSidebarContent = styled(SidebarContent)`
55
+ display: flex;
56
+ flex-direction: column;
57
+ gap: ${(props) => props.theme.grid.unit * 4}px;
58
+ padding: 6px;
59
+ `
60
+
61
+ const StyledSidebarHeader = styled(ModalSidebarHeader)`
62
+ padding: 0;
63
+ `
64
+
65
+ const InsertCitationButton = styled(IconTextButton)`
66
+ svg {
67
+ margin-right: ${(props) => props.theme.grid.unit * 2}px;
68
+ }
69
+ `
70
+
71
+ const Actions = styled(ButtonGroup)`
72
+ display: flex;
73
+ align-items: center;
74
+ justify-content: space-between;
75
+ padding: ${(props) => props.theme.grid.unit * 4}px 0;
76
+ `
77
+
78
+ export const InsertCitationModal: React.FC<{
79
+ query?: string
80
+ sources: BibliographyItemSource[]
81
+ items: BibliographyItemAttrs[]
82
+ citationCounts: Map<string, number>
83
+ onAdd: () => void
84
+ onCite: (items: BibliographyItemAttrs[]) => void
85
+ onCancel: () => void
86
+ }> = ({
87
+ query: initialQuery,
88
+ sources,
89
+ items,
90
+ citationCounts,
91
+ onAdd,
92
+ onCite,
93
+ onCancel,
94
+ }) => {
95
+ const [isOpen, setOpen] = useState(true)
96
+ const [query, setQuery] = useState<string>(initialQuery || '')
97
+ const [selections, setSelections] = useState(
98
+ new Map<string, BibliographyItemAttrs>()
99
+ )
100
+
101
+ const handleClose = () => {
102
+ onCancel()
103
+ setOpen(false)
104
+ }
105
+
106
+ const toggleSelection = (item: BibliographyItemAttrs) => {
107
+ const id = item.id
108
+ if (selections.has(id)) {
109
+ selections.delete(id)
110
+ setSelections(new Map([...selections]))
111
+ } else {
112
+ selections.set(id, item)
113
+ setSelections(new Map([...selections]))
114
+ }
115
+ }
116
+
117
+ const isSelected = (item: BibliographyItemAttrs) => {
118
+ return selections.has(item.id)
119
+ }
120
+
121
+ const document = new DocumentReferenceSource(items)
122
+
123
+ const handleClick = () => {
124
+ const items = Array.from(selections.values())
125
+ return onCite(items)
126
+ }
127
+
128
+ const debouncedSetQuery = useMemo(
129
+ () =>
130
+ debounce((e) => {
131
+ setQuery(e.target.value.trim())
132
+ }, 800),
133
+ []
134
+ )
135
+
136
+ useEffect(() => () => debouncedSetQuery.cancel(), [debouncedSetQuery])
137
+
138
+ return (
139
+ <StyledModal
140
+ isOpen={isOpen}
141
+ onRequestClose={handleClose}
142
+ shouldCloseOnOverlayClick={true}
143
+ >
144
+ <Container data-cy="reference-finder">
145
+ <ModalHeader>
146
+ <CloseButton onClick={handleClose} data-cy="modal-close-button" />
147
+ </ModalHeader>
148
+ <StyledModalBody>
149
+ <StyledModalSidebar>
150
+ <StyledSidebarHeader>
151
+ <ModalSidebarTitle>Insert Citation</ModalSidebarTitle>
152
+ </StyledSidebarHeader>
153
+ <StyledSidebarContent>
154
+ <SearchInput
155
+ onChange={debouncedSetQuery}
156
+ defaultValue={initialQuery}
157
+ />
158
+ <ReferenceSearchSection
159
+ key={document.id}
160
+ query={query}
161
+ source={document}
162
+ documentCitationCounts={citationCounts}
163
+ isSelected={isSelected}
164
+ onSelect={toggleSelection}
165
+ />
166
+ {query.length
167
+ ? sources.map((source) => (
168
+ <ReferenceSearchSection
169
+ key={source.id}
170
+ query={query}
171
+ source={source}
172
+ isSelected={isSelected}
173
+ onSelect={toggleSelection}
174
+ />
175
+ ))
176
+ : ''}
177
+ </StyledSidebarContent>
178
+ <Actions>
179
+ <InsertCitationButton onClick={onAdd}>
180
+ <AddNewIcon />
181
+ Add new
182
+ </InsertCitationButton>
183
+ <ButtonGroup>
184
+ <TertiaryButton onClick={handleClose}>Cancel</TertiaryButton>
185
+ <PrimaryButton
186
+ onClick={handleClick}
187
+ disabled={selections.size === 0}
188
+ >
189
+ Insert Citation
190
+ </PrimaryButton>
191
+ </ButtonGroup>
192
+ </Actions>
193
+ </StyledModalSidebar>
194
+ </StyledModalBody>
195
+ </Container>
196
+ </StyledModal>
197
+ )
198
+ }
@@ -69,10 +69,18 @@ export const ReferenceSearchResult = withNavigableListItem(styled.div`
69
69
  export const ReferenceSearchResults: React.FC<{
70
70
  items: BibliographyItemAttrs[]
71
71
  total: number
72
+ documentCitationCounts?: Map<string, number>
72
73
  isSelected: (item: BibliographyItemAttrs) => boolean
73
74
  onSelect: (item: BibliographyItemAttrs) => void
74
75
  onShowMore: () => void
75
- }> = ({ items, total, isSelected, onSelect, onShowMore }) => {
76
+ }> = ({
77
+ items,
78
+ total,
79
+ documentCitationCounts,
80
+ isSelected,
81
+ onSelect,
82
+ onShowMore,
83
+ }) => {
76
84
  const list = useRef<HTMLElement>(null)
77
85
  const onExpandReferenceList = () => {
78
86
  const element = list.current
@@ -100,7 +108,12 @@ export const ReferenceSearchResults: React.FC<{
100
108
  <AddIcon width={24} height={24} />
101
109
  )}
102
110
  </StatusIcon>
103
- <ReferenceLine item={item} />
111
+ <ReferenceLine
112
+ item={item}
113
+ showUncited={
114
+ documentCitationCounts && !documentCitationCounts.get(item.id)
115
+ }
116
+ />
104
117
  </ReferenceSearchResult>
105
118
  ))}
106
119
  {items.length < 25 && total > items.length ? (
@@ -31,16 +31,23 @@ import { ReferenceSearchResults } from './ReferenceSearchResults'
31
31
  import { ReferenceSearchResultsPlaceholder } from './ReferenceSearchResultsPlaceholder'
32
32
 
33
33
  const SearchSourceLabel = styled(IconTextButton)`
34
- margin: ${(props) => props.theme.grid.unit * 2}px
35
- ${(props) => props.theme.grid.unit * 4}px
36
- ${(props) => props.theme.grid.unit * 2}px;
37
- color: ${(props) => props.theme.colors.text.secondary};
38
-
39
- &:hover {
40
- color: ${(props) => props.theme.colors.text.muted};
34
+ height: ${(props) => props.theme.grid.unit * 10}px;
35
+ background: #f2f2f2;
36
+ display: flex;
37
+ justify-content: flex-start;
38
+ padding: ${(props) => props.theme.grid.unit * 2}px;
39
+ svg {
40
+ margin-right: ${(props) => props.theme.grid.unit * 2}px;
41
41
  }
42
42
  `
43
43
 
44
+ const Container = styled.div`
45
+ display: flex;
46
+ flex-direction: column;
47
+ border-radius: 4px;
48
+ border: 1px solid #e2e2e2;
49
+ `
50
+
44
51
  type RunningState = {
45
52
  type: 'running'
46
53
  promise: BibliographyItemSearch
@@ -57,9 +64,10 @@ type State = RunningState | CompletedState
57
64
  export const ReferenceSearchSection: React.FC<{
58
65
  query: string
59
66
  source: BibliographyItemSource
67
+ documentCitationCounts?: Map<string, number>
60
68
  isSelected: (item: BibliographyItemAttrs) => boolean
61
69
  onSelect: (item: BibliographyItemAttrs) => void
62
- }> = ({ query, source, isSelected, onSelect }) => {
70
+ }> = ({ query, source, documentCitationCounts, isSelected, onSelect }) => {
63
71
  const [expanded, setExpanded] = useState(true)
64
72
  const [state, setState] = useState<State>()
65
73
  const [limit, setLimit] = useState(3)
@@ -97,7 +105,7 @@ export const ReferenceSearchSection: React.FC<{
97
105
  }
98
106
 
99
107
  return (
100
- <>
108
+ <Container>
101
109
  <SearchSourceLabel onClick={toggleExpanded}>
102
110
  {expanded ? (
103
111
  <TriangleExpandedIcon className={'icon'} />
@@ -114,11 +122,12 @@ export const ReferenceSearchSection: React.FC<{
114
122
  <ReferenceSearchResults
115
123
  items={state.items}
116
124
  total={state.total}
125
+ documentCitationCounts={documentCitationCounts}
117
126
  isSelected={isSelected}
118
127
  onSelect={onSelect}
119
128
  onShowMore={handleShowMore}
120
129
  />
121
130
  )}
122
- </>
131
+ </Container>
123
132
  )
124
133
  }
@@ -21,9 +21,7 @@ import styled from 'styled-components'
21
21
  const SearchContainer = styled.div`
22
22
  align-items: center;
23
23
  display: flex;
24
- flex: 1 0 auto;
25
24
  position: relative;
26
- margin: 12px;
27
25
  `
28
26
 
29
27
  const SearchIconContainer = styled.span`
@@ -50,12 +48,6 @@ const SearchTextField = styled(TextField)`
50
48
  }
51
49
  `
52
50
 
53
- export const SearchWrapper = styled.div`
54
- display: flex;
55
- align-items: center;
56
- padding: ${(props) => props.theme.grid.unit * 3}px;
57
- `
58
-
59
51
  export const SearchInput: React.FC<InputHTMLAttributes<HTMLInputElement>> = (
60
52
  props
61
53
  ) => {
package/src/versions.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  //THIS FILE WAS GENERATED BY versions.mjs
2
- export const VERSION = '3.18.5';
2
+ export const VERSION = '3.18.6';
3
3
  export const MATHJAX_VERSION = '3.2.2';
@@ -160,6 +160,7 @@ export class CitationEditableView extends CitationView {
160
160
  onSave: this.handleSave,
161
161
  onDelete: this.handleDelete,
162
162
  onCancel: this.handleCancel,
163
+ isNodeDeleted: () => isDeleted(this.node),
163
164
  canEdit: can.editCitationsAndRefs,
164
165
  }
165
166
 
package/styles/popper.css CHANGED
@@ -239,6 +239,10 @@
239
239
  width: 600px;
240
240
  }
241
241
 
242
+ .popper .citation-editor:empty {
243
+ border: none;
244
+ }
245
+
242
246
  .popper .footnote-editor {
243
247
  width: 600px;
244
248
  }
@@ -1,133 +0,0 @@
1
- "use strict";
2
- /*!
3
- * © 2023 Atypon Systems LLC
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * http://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- */
17
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
- if (k2 === undefined) k2 = k;
19
- var desc = Object.getOwnPropertyDescriptor(m, k);
20
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
- desc = { enumerable: true, get: function() { return m[k]; } };
22
- }
23
- Object.defineProperty(o, k2, desc);
24
- }) : (function(o, m, k, k2) {
25
- if (k2 === undefined) k2 = k;
26
- o[k2] = m[k];
27
- }));
28
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
- Object.defineProperty(o, "default", { enumerable: true, value: v });
30
- }) : function(o, v) {
31
- o["default"] = v;
32
- });
33
- var __importStar = (this && this.__importStar) || (function () {
34
- var ownKeys = function(o) {
35
- ownKeys = Object.getOwnPropertyNames || function (o) {
36
- var ar = [];
37
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
- return ar;
39
- };
40
- return ownKeys(o);
41
- };
42
- return function (mod) {
43
- if (mod && mod.__esModule) return mod;
44
- var result = {};
45
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
- __setModuleDefault(result, mod);
47
- return result;
48
- };
49
- })();
50
- var __importDefault = (this && this.__importDefault) || function (mod) {
51
- return (mod && mod.__esModule) ? mod : { "default": mod };
52
- };
53
- Object.defineProperty(exports, "__esModule", { value: true });
54
- exports.ReferenceSearch = void 0;
55
- const style_guide_1 = require("@manuscripts/style-guide");
56
- const debounce_1 = __importDefault(require("lodash/debounce"));
57
- const react_1 = __importStar(require("react"));
58
- const styled_components_1 = __importDefault(require("styled-components"));
59
- const BibliographyItemSource_1 = require("./BibliographyItemSource");
60
- const ReferenceSearchSection_1 = require("./ReferenceSearchSection");
61
- const SearchInput_1 = require("./SearchInput");
62
- const ReferenceSearchSectionContainer = styled_components_1.default.div `
63
- max-height: 400px;
64
- overflow-y: auto;
65
- `;
66
- const Actions = (0, styled_components_1.default)(style_guide_1.ButtonGroup) `
67
- align-items: center;
68
- box-shadow: 0 -2px 12px 0 rgba(216, 216, 216, 0.26);
69
- display: flex;
70
- justify-content: space-between;
71
- padding: ${(props) => props.theme.grid.unit * 4}px;
72
- `;
73
- const Container = (0, style_guide_1.withFocusTrap)(styled_components_1.default.div `
74
- flex: 1;
75
- font-family: ${(props) => props.theme.font.family.sans};
76
- `);
77
- const AddReferenceActions = (0, styled_components_1.default)(style_guide_1.ButtonGroup) `
78
- button {
79
- margin-right: ${(props) => props.theme.grid.unit * 8}px;
80
- }
81
-
82
- button:hover,
83
- button:active {
84
- path {
85
- stroke: ${(props) => props.theme.colors.brand.medium};
86
- }
87
- rect {
88
- stroke: ${(props) => props.theme.colors.brand.medium};
89
- }
90
- }
91
- `;
92
- const ReferenceSearch = ({ query: initialQuery, sources, items, onAdd, onCite, onCancel }) => {
93
- const [query, setQuery] = (0, react_1.useState)(initialQuery || '');
94
- const [selections, setSelections] = (0, react_1.useState)(new Map());
95
- const toggleSelection = (item) => {
96
- const id = item.id;
97
- if (selections.has(id)) {
98
- selections.delete(id);
99
- setSelections(new Map([...selections]));
100
- }
101
- else {
102
- selections.set(id, item);
103
- setSelections(new Map([...selections]));
104
- }
105
- };
106
- const isSelected = (item) => {
107
- return selections.has(item.id);
108
- };
109
- const document = new BibliographyItemSource_1.DocumentReferenceSource(items);
110
- const handleClick = () => {
111
- const items = Array.from(selections.values());
112
- return onCite(items);
113
- };
114
- const debouncedSetQuery = (0, debounce_1.default)((e) => {
115
- setQuery(e.target.value.trim());
116
- }, 800);
117
- return (react_1.default.createElement(Container, { "data-cy": 'reference-finder' },
118
- react_1.default.createElement(SearchInput_1.SearchInput, { onChange: debouncedSetQuery, defaultValue: initialQuery }),
119
- react_1.default.createElement(ReferenceSearchSectionContainer, null,
120
- react_1.default.createElement(ReferenceSearchSection_1.ReferenceSearchSection, { key: document.id, query: query, source: document, isSelected: isSelected, onSelect: toggleSelection }),
121
- query.length
122
- ? sources.map((source) => (react_1.default.createElement(ReferenceSearchSection_1.ReferenceSearchSection, { key: source.id, query: query, source: source, isSelected: isSelected, onSelect: toggleSelection })))
123
- : ''),
124
- react_1.default.createElement(Actions, null,
125
- react_1.default.createElement(AddReferenceActions, null,
126
- react_1.default.createElement(style_guide_1.IconTextButton, { onClick: onAdd },
127
- react_1.default.createElement(style_guide_1.AddNewIcon, null),
128
- "Add new")),
129
- react_1.default.createElement(style_guide_1.ButtonGroup, null,
130
- react_1.default.createElement(style_guide_1.SecondaryButton, { onClick: onCancel }, "Close"),
131
- react_1.default.createElement(style_guide_1.PrimaryButton, { onClick: handleClick, disabled: selections.size === 0 }, "Cite")))));
132
- };
133
- exports.ReferenceSearch = ReferenceSearch;
@@ -1,93 +0,0 @@
1
- /*!
2
- * © 2023 Atypon Systems LLC
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
- import { AddNewIcon, ButtonGroup, IconTextButton, PrimaryButton, SecondaryButton, withFocusTrap, } from '@manuscripts/style-guide';
17
- import debounce from 'lodash/debounce';
18
- import React, { useState } from 'react';
19
- import styled from 'styled-components';
20
- import { DocumentReferenceSource, } from './BibliographyItemSource';
21
- import { ReferenceSearchSection } from './ReferenceSearchSection';
22
- import { SearchInput } from './SearchInput';
23
- const ReferenceSearchSectionContainer = styled.div `
24
- max-height: 400px;
25
- overflow-y: auto;
26
- `;
27
- const Actions = styled(ButtonGroup) `
28
- align-items: center;
29
- box-shadow: 0 -2px 12px 0 rgba(216, 216, 216, 0.26);
30
- display: flex;
31
- justify-content: space-between;
32
- padding: ${(props) => props.theme.grid.unit * 4}px;
33
- `;
34
- const Container = withFocusTrap(styled.div `
35
- flex: 1;
36
- font-family: ${(props) => props.theme.font.family.sans};
37
- `);
38
- const AddReferenceActions = styled(ButtonGroup) `
39
- button {
40
- margin-right: ${(props) => props.theme.grid.unit * 8}px;
41
- }
42
-
43
- button:hover,
44
- button:active {
45
- path {
46
- stroke: ${(props) => props.theme.colors.brand.medium};
47
- }
48
- rect {
49
- stroke: ${(props) => props.theme.colors.brand.medium};
50
- }
51
- }
52
- `;
53
- export const ReferenceSearch = ({ query: initialQuery, sources, items, onAdd, onCite, onCancel }) => {
54
- const [query, setQuery] = useState(initialQuery || '');
55
- const [selections, setSelections] = useState(new Map());
56
- const toggleSelection = (item) => {
57
- const id = item.id;
58
- if (selections.has(id)) {
59
- selections.delete(id);
60
- setSelections(new Map([...selections]));
61
- }
62
- else {
63
- selections.set(id, item);
64
- setSelections(new Map([...selections]));
65
- }
66
- };
67
- const isSelected = (item) => {
68
- return selections.has(item.id);
69
- };
70
- const document = new DocumentReferenceSource(items);
71
- const handleClick = () => {
72
- const items = Array.from(selections.values());
73
- return onCite(items);
74
- };
75
- const debouncedSetQuery = debounce((e) => {
76
- setQuery(e.target.value.trim());
77
- }, 800);
78
- return (React.createElement(Container, { "data-cy": 'reference-finder' },
79
- React.createElement(SearchInput, { onChange: debouncedSetQuery, defaultValue: initialQuery }),
80
- React.createElement(ReferenceSearchSectionContainer, null,
81
- React.createElement(ReferenceSearchSection, { key: document.id, query: query, source: document, isSelected: isSelected, onSelect: toggleSelection }),
82
- query.length
83
- ? sources.map((source) => (React.createElement(ReferenceSearchSection, { key: source.id, query: query, source: source, isSelected: isSelected, onSelect: toggleSelection })))
84
- : ''),
85
- React.createElement(Actions, null,
86
- React.createElement(AddReferenceActions, null,
87
- React.createElement(IconTextButton, { onClick: onAdd },
88
- React.createElement(AddNewIcon, null),
89
- "Add new")),
90
- React.createElement(ButtonGroup, null,
91
- React.createElement(SecondaryButton, { onClick: onCancel }, "Close"),
92
- React.createElement(PrimaryButton, { onClick: handleClick, disabled: selections.size === 0 }, "Cite")))));
93
- };