@portone/docx-editor 0.1.0
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.
- package/CHANGELOG.md +7 -0
- package/CONTRIBUTING.md +63 -0
- package/LICENSE +203 -0
- package/README.md +48 -0
- package/assets/editor.png +0 -0
- package/dist/DocxEditor.d.ts +123 -0
- package/dist/DocxEditor.js +348 -0
- package/dist/core.d.ts +36 -0
- package/dist/core.js +38 -0
- package/dist/docx/comments/constants.d.ts +8 -0
- package/dist/docx/comments/constants.js +20 -0
- package/dist/docx/comments/model.d.ts +37 -0
- package/dist/docx/comments/model.js +104 -0
- package/dist/docx/comments/reading.d.ts +36 -0
- package/dist/docx/comments/reading.js +149 -0
- package/dist/docx/comments/writing.d.ts +11 -0
- package/dist/docx/comments/writing.js +327 -0
- package/dist/docx/comments.d.ts +3 -0
- package/dist/docx/comments.js +4 -0
- package/dist/docx/container.d.ts +12 -0
- package/dist/docx/container.js +130 -0
- package/dist/docx/documentSettings.d.ts +4 -0
- package/dist/docx/documentSettings.js +14 -0
- package/dist/docx/exportDocx.d.ts +15 -0
- package/dist/docx/exportDocx.js +163 -0
- package/dist/docx/exportRefs.d.ts +16 -0
- package/dist/docx/exportRefs.js +10 -0
- package/dist/docx/formatting/direct.d.ts +30 -0
- package/dist/docx/formatting/direct.js +201 -0
- package/dist/docx/formatting/effectiveParagraph.d.ts +15 -0
- package/dist/docx/formatting/effectiveParagraph.js +81 -0
- package/dist/docx/formatting/styles.d.ts +67 -0
- package/dist/docx/formatting/styles.js +165 -0
- package/dist/docx/formatting/tabStops.d.ts +8 -0
- package/dist/docx/formatting/tabStops.js +65 -0
- package/dist/docx/formatting.d.ts +4 -0
- package/dist/docx/formatting.js +4 -0
- package/dist/docx/headersFooters.d.ts +36 -0
- package/dist/docx/headersFooters.js +218 -0
- package/dist/docx/hyperlink.d.ts +75 -0
- package/dist/docx/hyperlink.js +71 -0
- package/dist/docx/importDocx.d.ts +21 -0
- package/dist/docx/importDocx.js +263 -0
- package/dist/docx/importParagraph.d.ts +32 -0
- package/dist/docx/importParagraph.js +308 -0
- package/dist/docx/importTable.d.ts +9 -0
- package/dist/docx/importTable.js +275 -0
- package/dist/docx/media.d.ts +60 -0
- package/dist/docx/media.js +213 -0
- package/dist/docx/notes.d.ts +22 -0
- package/dist/docx/notes.js +71 -0
- package/dist/docx/pageGeometry.d.ts +75 -0
- package/dist/docx/pageGeometry.js +88 -0
- package/dist/docx/paraProps.d.ts +74 -0
- package/dist/docx/paraProps.js +167 -0
- package/dist/docx/propsXml.d.ts +49 -0
- package/dist/docx/propsXml.js +302 -0
- package/dist/docx/relationships.d.ts +42 -0
- package/dist/docx/relationships.js +94 -0
- package/dist/docx/runProps.d.ts +51 -0
- package/dist/docx/runProps.js +207 -0
- package/dist/docx/scan.d.ts +20 -0
- package/dist/docx/scan.js +110 -0
- package/dist/docx/sdt.d.ts +56 -0
- package/dist/docx/sdt.js +104 -0
- package/dist/docx/sdtProps.d.ts +18 -0
- package/dist/docx/sdtProps.js +11 -0
- package/dist/docx/serializeBlock.d.ts +4 -0
- package/dist/docx/serializeBlock.js +30 -0
- package/dist/docx/serializeParagraph.d.ts +15 -0
- package/dist/docx/serializeParagraph.js +208 -0
- package/dist/docx/serializeTable.d.ts +12 -0
- package/dist/docx/serializeTable.js +134 -0
- package/dist/docx/session.d.ts +81 -0
- package/dist/docx/session.js +79 -0
- package/dist/docx/tableFormatting/editing.d.ts +64 -0
- package/dist/docx/tableFormatting/editing.js +318 -0
- package/dist/docx/tableFormatting/reading.d.ts +96 -0
- package/dist/docx/tableFormatting/reading.js +221 -0
- package/dist/docx/tableFormatting.d.ts +2 -0
- package/dist/docx/tableFormatting.js +3 -0
- package/dist/docx/tableTemplate.d.ts +22 -0
- package/dist/docx/tableTemplate.js +111 -0
- package/dist/docx/theme.d.ts +40 -0
- package/dist/docx/theme.js +61 -0
- package/dist/docx/uniqueControls.d.ts +14 -0
- package/dist/docx/uniqueControls.js +62 -0
- package/dist/download.d.ts +57 -0
- package/dist/download.js +44 -0
- package/dist/editor/clipboard/images.d.ts +14 -0
- package/dist/editor/clipboard/images.js +158 -0
- package/dist/editor/clipboard/inlineFormatting.d.ts +21 -0
- package/dist/editor/clipboard/inlineFormatting.js +232 -0
- package/dist/editor/commands/breakCommands.d.ts +8 -0
- package/dist/editor/commands/breakCommands.js +19 -0
- package/dist/editor/commands/canRunCommand.d.ts +6 -0
- package/dist/editor/commands/canRunCommand.js +10 -0
- package/dist/editor/commands/commentCommands.d.ts +3 -0
- package/dist/editor/commands/commentCommands.js +4 -0
- package/dist/editor/commands/comments/editing.d.ts +21 -0
- package/dist/editor/commands/comments/editing.js +305 -0
- package/dist/editor/commands/comments/model.d.ts +31 -0
- package/dist/editor/commands/comments/model.js +0 -0
- package/dist/editor/commands/comments/reading.d.ts +8 -0
- package/dist/editor/commands/comments/reading.js +58 -0
- package/dist/editor/commands/formatting/editing.d.ts +32 -0
- package/dist/editor/commands/formatting/editing.js +138 -0
- package/dist/editor/commands/formatting/reading.d.ts +57 -0
- package/dist/editor/commands/formatting/reading.js +82 -0
- package/dist/editor/commands/formatting/shared.d.ts +32 -0
- package/dist/editor/commands/formatting/shared.js +53 -0
- package/dist/editor/commands/formattingCommands.d.ts +2 -0
- package/dist/editor/commands/formattingCommands.js +3 -0
- package/dist/editor/commands/historyCommands.d.ts +11 -0
- package/dist/editor/commands/historyCommands.js +16 -0
- package/dist/editor/commands/indentCommands.d.ts +15 -0
- package/dist/editor/commands/indentCommands.js +44 -0
- package/dist/editor/commands/index.d.ts +82 -0
- package/dist/editor/commands/index.js +171 -0
- package/dist/editor/commands/linkCommands.d.ts +56 -0
- package/dist/editor/commands/linkCommands.js +146 -0
- package/dist/editor/commands/listCommands.d.ts +58 -0
- package/dist/editor/commands/listCommands.js +140 -0
- package/dist/editor/commands/lockCommands.d.ts +47 -0
- package/dist/editor/commands/lockCommands.js +198 -0
- package/dist/editor/commands/noteQueries.d.ts +12 -0
- package/dist/editor/commands/noteQueries.js +29 -0
- package/dist/editor/commands/paragraphCommands.d.ts +59 -0
- package/dist/editor/commands/paragraphCommands.js +113 -0
- package/dist/editor/commands/spacingCommands.d.ts +23 -0
- package/dist/editor/commands/spacingCommands.js +48 -0
- package/dist/editor/commands/tabCommands.d.ts +5 -0
- package/dist/editor/commands/tabCommands.js +65 -0
- package/dist/editor/createEditor.d.ts +59 -0
- package/dist/editor/createEditor.js +160 -0
- package/dist/editor/documentStyles.d.ts +60 -0
- package/dist/editor/documentStyles.js +80 -0
- package/dist/editor/externalClipboard.d.ts +11 -0
- package/dist/editor/externalClipboard.js +323 -0
- package/dist/editor/imageFiles.d.ts +74 -0
- package/dist/editor/imageFiles.js +173 -0
- package/dist/editor/insertImage.d.ts +31 -0
- package/dist/editor/insertImage.js +35 -0
- package/dist/editor/insertTable.d.ts +18 -0
- package/dist/editor/insertTable.js +44 -0
- package/dist/editor/paragraphEdits.d.ts +42 -0
- package/dist/editor/paragraphEdits.js +59 -0
- package/dist/editor/plainText.d.ts +3 -0
- package/dist/editor/plainText.js +50 -0
- package/dist/editor/plugins/bookmarkProtection.d.ts +3 -0
- package/dist/editor/plugins/bookmarkProtection.js +28 -0
- package/dist/editor/plugins/columnResize.d.ts +27 -0
- package/dist/editor/plugins/columnResize.js +192 -0
- package/dist/editor/plugins/commentDecorations.d.ts +3 -0
- package/dist/editor/plugins/commentDecorations.js +23 -0
- package/dist/editor/plugins/commentReservations.d.ts +5 -0
- package/dist/editor/plugins/commentReservations.js +26 -0
- package/dist/editor/plugins/dropCaret.d.ts +10 -0
- package/dist/editor/plugins/dropCaret.js +11 -0
- package/dist/editor/plugins/imagePaste.d.ts +8 -0
- package/dist/editor/plugins/imagePaste.js +265 -0
- package/dist/editor/plugins/keymap.d.ts +5 -0
- package/dist/editor/plugins/keymap.js +94 -0
- package/dist/editor/plugins/linkPanel.d.ts +23 -0
- package/dist/editor/plugins/linkPanel.js +39 -0
- package/dist/editor/plugins/listInputRules.d.ts +14 -0
- package/dist/editor/plugins/listInputRules.js +36 -0
- package/dist/editor/plugins/lockedContent.d.ts +6 -0
- package/dist/editor/plugins/lockedContent.js +41 -0
- package/dist/editor/plugins/noteProtection.d.ts +3 -0
- package/dist/editor/plugins/noteProtection.js +25 -0
- package/dist/editor/plugins/numberingDecorations.d.ts +42 -0
- package/dist/editor/plugins/numberingDecorations.js +110 -0
- package/dist/editor/plugins/rowResize.d.ts +15 -0
- package/dist/editor/plugins/rowResize.js +196 -0
- package/dist/editor/plugins/styledParagraphs.d.ts +15 -0
- package/dist/editor/plugins/styledParagraphs.js +65 -0
- package/dist/editor/plugins/tabCaret.d.ts +3 -0
- package/dist/editor/plugins/tabCaret.js +126 -0
- package/dist/editor/plugins/tabDecorations.d.ts +11 -0
- package/dist/editor/plugins/tabDecorations.js +87 -0
- package/dist/editor/plugins/tabLayout.d.ts +16 -0
- package/dist/editor/plugins/tabLayout.js +328 -0
- package/dist/editor/plugins/tabPointer.d.ts +7 -0
- package/dist/editor/plugins/tabPointer.js +95 -0
- package/dist/editor/plugins/tableContextMenu.d.ts +21 -0
- package/dist/editor/plugins/tableContextMenu.js +88 -0
- package/dist/editor/plugins/textContextMenu.d.ts +15 -0
- package/dist/editor/plugins/textContextMenu.js +90 -0
- package/dist/editor/views/imageResize.d.ts +53 -0
- package/dist/editor/views/imageResize.js +167 -0
- package/dist/editor/views/runMarkView.d.ts +15 -0
- package/dist/editor/views/runMarkView.js +9 -0
- package/dist/editor/views/tableView.d.ts +24 -0
- package/dist/editor/views/tableView.js +32 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +38 -0
- package/dist/model/format.d.ts +240 -0
- package/dist/model/format.js +305 -0
- package/dist/model/tabStops.d.ts +17 -0
- package/dist/model/tabStops.js +22 -0
- package/dist/numbering/listTemplate.d.ts +29 -0
- package/dist/numbering/listTemplate.js +83 -0
- package/dist/numbering/markers.d.ts +24 -0
- package/dist/numbering/markers.js +93 -0
- package/dist/numbering/parseNumbering.d.ts +65 -0
- package/dist/numbering/parseNumbering.js +116 -0
- package/dist/numbering/writeNumbering.d.ts +13 -0
- package/dist/numbering/writeNumbering.js +49 -0
- package/dist/ooxml/errors.d.ts +39 -0
- package/dist/ooxml/errors.js +21 -0
- package/dist/ooxml/image.d.ts +88 -0
- package/dist/ooxml/image.js +106 -0
- package/dist/ooxml/tabStops.d.ts +3 -0
- package/dist/ooxml/tabStops.js +51 -0
- package/dist/ooxml/units.d.ts +37 -0
- package/dist/ooxml/units.js +116 -0
- package/dist/ooxml/xml.d.ts +36 -0
- package/dist/ooxml/xml.js +89 -0
- package/dist/page/PageGuides.d.ts +16 -0
- package/dist/page/PageGuides.js +114 -0
- package/dist/page/measureBlocks.d.ts +25 -0
- package/dist/page/measureBlocks.js +80 -0
- package/dist/page/pageDecorations.d.ts +36 -0
- package/dist/page/pageDecorations.js +211 -0
- package/dist/page/pageLayout.d.ts +176 -0
- package/dist/page/pageLayout.js +157 -0
- package/dist/page/tableMeasurements.d.ts +10 -0
- package/dist/page/tableMeasurements.js +115 -0
- package/dist/page/usePageLayout.d.ts +57 -0
- package/dist/page/usePageLayout.js +141 -0
- package/dist/schema/docxSchema.d.ts +9 -0
- package/dist/schema/docxSchema.js +863 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +9 -0
- package/dist/schema/locks.d.ts +112 -0
- package/dist/schema/locks.js +211 -0
- package/dist/schema/rendering.d.ts +6 -0
- package/dist/schema/rendering.js +46 -0
- package/dist/styles/classNames.d.ts +214 -0
- package/dist/styles/classNames.js +208 -0
- package/dist/styles/colors.d.ts +11 -0
- package/dist/styles/colors.js +14 -0
- package/dist/styles/fontSizes.d.ts +6 -0
- package/dist/styles/fontSizes.js +20 -0
- package/dist/styles/fontStack.d.ts +55 -0
- package/dist/styles/fontStack.js +262 -0
- package/dist/styles/fonts.d.ts +6 -0
- package/dist/styles/fonts.js +11 -0
- package/dist/styles/inlineStyle.d.ts +67 -0
- package/dist/styles/inlineStyle.js +212 -0
- package/dist/styles/lineSpacings.d.ts +11 -0
- package/dist/styles/lineSpacings.js +10 -0
- package/dist/styles.css +1650 -0
- package/dist/table/cellBorders.d.ts +12 -0
- package/dist/table/cellBorders.js +9 -0
- package/dist/table/cellFormatting.d.ts +57 -0
- package/dist/table/cellFormatting.js +173 -0
- package/dist/table/columns.d.ts +25 -0
- package/dist/table/columns.js +155 -0
- package/dist/table/commands.d.ts +19 -0
- package/dist/table/commands.js +63 -0
- package/dist/table/format.d.ts +35 -0
- package/dist/table/format.js +26 -0
- package/dist/table/gridBorders.d.ts +42 -0
- package/dist/table/gridBorders.js +192 -0
- package/dist/table/index.d.ts +16 -0
- package/dist/table/index.js +52 -0
- package/dist/table/merge.d.ts +36 -0
- package/dist/table/merge.js +125 -0
- package/dist/table/resize.d.ts +55 -0
- package/dist/table/resize.js +66 -0
- package/dist/table/rowResize.d.ts +14 -0
- package/dist/table/rowResize.js +44 -0
- package/dist/table/rows.d.ts +32 -0
- package/dist/table/rows.js +89 -0
- package/dist/table/widths.d.ts +69 -0
- package/dist/table/widths.js +97 -0
- package/dist/ui/AlignMenu.d.ts +15 -0
- package/dist/ui/AlignMenu.js +64 -0
- package/dist/ui/CellStyleGroup.d.ts +15 -0
- package/dist/ui/CellStyleGroup.js +232 -0
- package/dist/ui/ColorPicker.d.ts +13 -0
- package/dist/ui/ColorPicker.js +165 -0
- package/dist/ui/CommentsPanel.d.ts +15 -0
- package/dist/ui/CommentsPanel.js +348 -0
- package/dist/ui/FontFamilySelect.d.ts +14 -0
- package/dist/ui/FontFamilySelect.js +59 -0
- package/dist/ui/FontSizeSelect.d.ts +11 -0
- package/dist/ui/FontSizeSelect.js +49 -0
- package/dist/ui/InsertImageButton.d.ts +9 -0
- package/dist/ui/InsertImageButton.js +47 -0
- package/dist/ui/LinkCard.d.ts +12 -0
- package/dist/ui/LinkCard.js +127 -0
- package/dist/ui/LinkPanel.d.ts +9 -0
- package/dist/ui/LinkPanel.js +121 -0
- package/dist/ui/MenuChoice.d.ts +11 -0
- package/dist/ui/MenuChoice.js +32 -0
- package/dist/ui/NotesPanel.d.ts +6 -0
- package/dist/ui/NotesPanel.js +33 -0
- package/dist/ui/ParagraphStyleSelect.d.ts +11 -0
- package/dist/ui/ParagraphStyleSelect.js +62 -0
- package/dist/ui/Popover.d.ts +22 -0
- package/dist/ui/Popover.js +74 -0
- package/dist/ui/SpacingMenu.d.ts +12 -0
- package/dist/ui/SpacingMenu.js +54 -0
- package/dist/ui/TableMenu.d.ts +12 -0
- package/dist/ui/TableMenu.js +112 -0
- package/dist/ui/TableSizePicker.d.ts +9 -0
- package/dist/ui/TableSizePicker.js +53 -0
- package/dist/ui/TextMenu.d.ts +15 -0
- package/dist/ui/TextMenu.js +194 -0
- package/dist/ui/Toolbar.d.ts +19 -0
- package/dist/ui/Toolbar.js +448 -0
- package/dist/ui/ToolbarButton.d.ts +23 -0
- package/dist/ui/ToolbarButton.js +56 -0
- package/dist/ui/Tooltip.d.ts +19 -0
- package/dist/ui/Tooltip.js +47 -0
- package/dist/ui/ZoomSelect.d.ts +7 -0
- package/dist/ui/ZoomSelect.js +44 -0
- package/dist/ui/comments/CommentComposer.d.ts +17 -0
- package/dist/ui/comments/CommentComposer.js +59 -0
- package/dist/ui/comments/useCommentRailLayout.d.ts +18 -0
- package/dist/ui/comments/useCommentRailLayout.js +183 -0
- package/dist/ui/keyboardWalk.d.ts +22 -0
- package/dist/ui/keyboardWalk.js +70 -0
- package/dist/ui/openAddress.d.ts +11 -0
- package/dist/ui/openAddress.js +16 -0
- package/dist/ui/panelPlacement.d.ts +51 -0
- package/dist/ui/panelPlacement.js +71 -0
- package/dist/ui/presets.d.ts +11 -0
- package/dist/ui/presets.js +0 -0
- package/dist/ui/rovingFocus.d.ts +20 -0
- package/dist/ui/rovingFocus.js +61 -0
- package/dist/ui/runCommand.d.ts +5 -0
- package/dist/ui/runCommand.js +13 -0
- package/dist/ui/useDismiss.d.ts +6 -0
- package/dist/ui/useDismiss.js +31 -0
- package/dist/ui/useFitWidthZoom.d.ts +2 -0
- package/dist/ui/useFitWidthZoom.js +26 -0
- package/dist/ui/useGridKeyboard.d.ts +12 -0
- package/dist/ui/useGridKeyboard.js +90 -0
- package/dist/ui/useMenuKeyboard.d.ts +12 -0
- package/dist/ui/useMenuKeyboard.js +56 -0
- package/dist/ui/zoom.d.ts +4 -0
- package/dist/ui/zoom.js +21 -0
- package/package.json +120 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// src/ui/InsertImageButton.tsx
|
|
2
|
+
import { Image } from "lucide-react";
|
|
3
|
+
import { useRef } from "react";
|
|
4
|
+
import {
|
|
5
|
+
IMAGE_FILE_ACCEPT,
|
|
6
|
+
imageFilesIn,
|
|
7
|
+
insertImageFiles
|
|
8
|
+
} from "../editor/imageFiles.js";
|
|
9
|
+
import { canInsertImage } from "../editor/insertImage.js";
|
|
10
|
+
import { ToolbarButton } from "./ToolbarButton.js";
|
|
11
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
function InsertImageButton({
|
|
13
|
+
view,
|
|
14
|
+
state
|
|
15
|
+
}) {
|
|
16
|
+
const pickerRef = useRef(null);
|
|
17
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18
|
+
/* @__PURE__ */ jsx(
|
|
19
|
+
ToolbarButton,
|
|
20
|
+
{
|
|
21
|
+
label: "Insert image",
|
|
22
|
+
icon: Image,
|
|
23
|
+
disabled: !view.editable || !canInsertImage(state),
|
|
24
|
+
onRun: () => pickerRef.current?.click()
|
|
25
|
+
}
|
|
26
|
+
),
|
|
27
|
+
/* @__PURE__ */ jsx(
|
|
28
|
+
"input",
|
|
29
|
+
{
|
|
30
|
+
ref: pickerRef,
|
|
31
|
+
type: "file",
|
|
32
|
+
accept: IMAGE_FILE_ACCEPT,
|
|
33
|
+
hidden: true,
|
|
34
|
+
onChange: async (event) => {
|
|
35
|
+
const picker = event.currentTarget;
|
|
36
|
+
const files = imageFilesIn(picker);
|
|
37
|
+
picker.value = "";
|
|
38
|
+
await insertImageFiles(view, files);
|
|
39
|
+
if (!view.isDestroyed) view.focus();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
] });
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
InsertImageButton
|
|
47
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Shows the destination and available actions for the link under the selection. */
|
|
2
|
+
import type { EditorState } from "prosemirror-state";
|
|
3
|
+
import type { EditorView } from "prosemirror-view";
|
|
4
|
+
import { type ReactElement } from "react";
|
|
5
|
+
import { type ActiveLinkSpan } from "../editor/commands/linkCommands";
|
|
6
|
+
export interface LinkCardProps {
|
|
7
|
+
view: EditorView;
|
|
8
|
+
state: EditorState;
|
|
9
|
+
link: ActiveLinkSpan;
|
|
10
|
+
readOnly?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function LinkCard({ view, state, link, readOnly, }: LinkCardProps): ReactElement | null;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// src/ui/LinkCard.tsx
|
|
2
|
+
import { ExternalLink, Link2Off, Pencil } from "lucide-react";
|
|
3
|
+
import {
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useRef,
|
|
7
|
+
useState
|
|
8
|
+
} from "react";
|
|
9
|
+
import {
|
|
10
|
+
removeLink
|
|
11
|
+
} from "../editor/commands/linkCommands.js";
|
|
12
|
+
import { openLinkPanel } from "../editor/plugins/linkPanel.js";
|
|
13
|
+
import { editorClassNames } from "../styles/classNames.js";
|
|
14
|
+
import { openAddress, openable } from "./openAddress.js";
|
|
15
|
+
import {
|
|
16
|
+
pointBelowPos,
|
|
17
|
+
usePanelAtPoint
|
|
18
|
+
} from "./panelPlacement.js";
|
|
19
|
+
import { commandRunner } from "./runCommand.js";
|
|
20
|
+
import { ICON_SIZE } from "./ToolbarButton.js";
|
|
21
|
+
import { Tooltip, tooltipAttribute } from "./Tooltip.js";
|
|
22
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
23
|
+
function useLinkPoint(view, at) {
|
|
24
|
+
const [point, setPoint] = useState(() => pointBelowPos(view, at));
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const measure = () => setPoint((was) => {
|
|
27
|
+
const now = pointBelowPos(view, at);
|
|
28
|
+
return was.clientX === now.clientX && was.clientY === now.clientY ? was : now;
|
|
29
|
+
});
|
|
30
|
+
measure();
|
|
31
|
+
document.addEventListener("scroll", measure, true);
|
|
32
|
+
window.addEventListener("resize", measure);
|
|
33
|
+
return () => {
|
|
34
|
+
document.removeEventListener("scroll", measure, true);
|
|
35
|
+
window.removeEventListener("resize", measure);
|
|
36
|
+
};
|
|
37
|
+
}, [view, at]);
|
|
38
|
+
return point;
|
|
39
|
+
}
|
|
40
|
+
function useEscape(onEscape) {
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
const onKeyDown = (event) => {
|
|
43
|
+
if (event.key === "Escape") onEscape();
|
|
44
|
+
};
|
|
45
|
+
document.addEventListener("keydown", onKeyDown, true);
|
|
46
|
+
return () => document.removeEventListener("keydown", onKeyDown, true);
|
|
47
|
+
}, [onEscape]);
|
|
48
|
+
}
|
|
49
|
+
function LinkCard({
|
|
50
|
+
view,
|
|
51
|
+
state,
|
|
52
|
+
link,
|
|
53
|
+
readOnly = false
|
|
54
|
+
}) {
|
|
55
|
+
const box = useRef(null);
|
|
56
|
+
const [hidden, setHidden] = useState(false);
|
|
57
|
+
const placement = usePanelAtPoint(box, useLinkPoint(view, link.from));
|
|
58
|
+
const run = commandRunner(view);
|
|
59
|
+
const hide = useCallback(() => {
|
|
60
|
+
if (box.current?.contains(document.activeElement)) view.focus();
|
|
61
|
+
setHidden(true);
|
|
62
|
+
}, [view]);
|
|
63
|
+
useEscape(hide);
|
|
64
|
+
if (hidden) return null;
|
|
65
|
+
const href = link.href;
|
|
66
|
+
return /* @__PURE__ */ jsxs(
|
|
67
|
+
"div",
|
|
68
|
+
{
|
|
69
|
+
ref: box,
|
|
70
|
+
className: editorClassNames.linkCard,
|
|
71
|
+
role: "group",
|
|
72
|
+
"aria-label": "Link",
|
|
73
|
+
style: {
|
|
74
|
+
left: placement?.left,
|
|
75
|
+
top: placement?.top,
|
|
76
|
+
// Hide until the card has been measured.
|
|
77
|
+
visibility: placement ? void 0 : "hidden"
|
|
78
|
+
},
|
|
79
|
+
children: [
|
|
80
|
+
href === null ? /* @__PURE__ */ jsx("span", { className: editorClassNames.linkCardNote, children: "This link points at a place in the document rather than at an address." }) : (
|
|
81
|
+
// Keep the tooltip outside the address's clipped overflow.
|
|
82
|
+
/* @__PURE__ */ jsx(Tooltip, { label: href, children: /* @__PURE__ */ jsx("span", { className: editorClassNames.linkCardAddress, children: href }) })
|
|
83
|
+
),
|
|
84
|
+
href !== null && /* @__PURE__ */ jsx(
|
|
85
|
+
"button",
|
|
86
|
+
{
|
|
87
|
+
type: "button",
|
|
88
|
+
className: editorClassNames.toolbarButton,
|
|
89
|
+
disabled: !openable(href),
|
|
90
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
91
|
+
onClick: () => openAddress(href),
|
|
92
|
+
"aria-label": "Open",
|
|
93
|
+
...tooltipAttribute("Open"),
|
|
94
|
+
children: /* @__PURE__ */ jsx(ExternalLink, { size: ICON_SIZE, "aria-hidden": "true" })
|
|
95
|
+
}
|
|
96
|
+
),
|
|
97
|
+
!readOnly && openLinkPanel(state) && /* @__PURE__ */ jsx(
|
|
98
|
+
"button",
|
|
99
|
+
{
|
|
100
|
+
type: "button",
|
|
101
|
+
className: editorClassNames.toolbarButton,
|
|
102
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
103
|
+
onClick: () => run(openLinkPanel),
|
|
104
|
+
"aria-label": "Edit",
|
|
105
|
+
...tooltipAttribute("Edit"),
|
|
106
|
+
children: /* @__PURE__ */ jsx(Pencil, { size: ICON_SIZE, "aria-hidden": "true" })
|
|
107
|
+
}
|
|
108
|
+
),
|
|
109
|
+
!readOnly && removeLink(state) && /* @__PURE__ */ jsx(
|
|
110
|
+
"button",
|
|
111
|
+
{
|
|
112
|
+
type: "button",
|
|
113
|
+
className: editorClassNames.toolbarButton,
|
|
114
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
115
|
+
onClick: () => run(removeLink),
|
|
116
|
+
"aria-label": "Remove",
|
|
117
|
+
...tooltipAttribute("Remove"),
|
|
118
|
+
children: /* @__PURE__ */ jsx(Link2Off, { size: ICON_SIZE, "aria-hidden": "true" })
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
export {
|
|
126
|
+
LinkCard
|
|
127
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Edits or removes the link on the current selection. */
|
|
2
|
+
import type { EditorState } from "prosemirror-state";
|
|
3
|
+
import type { EditorView } from "prosemirror-view";
|
|
4
|
+
import { type ReactElement } from "react";
|
|
5
|
+
export interface LinkPanelProps {
|
|
6
|
+
view: EditorView;
|
|
7
|
+
state: EditorState;
|
|
8
|
+
}
|
|
9
|
+
export declare function LinkPanel({ view, state }: LinkPanelProps): ReactElement;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// src/ui/LinkPanel.tsx
|
|
2
|
+
import { Check, Link2 } from "lucide-react";
|
|
3
|
+
import {
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useRef,
|
|
7
|
+
useState
|
|
8
|
+
} from "react";
|
|
9
|
+
import {
|
|
10
|
+
activeLink,
|
|
11
|
+
removeLink,
|
|
12
|
+
setLink
|
|
13
|
+
} from "../editor/commands/linkCommands.js";
|
|
14
|
+
import { closeLinkPanel } from "../editor/plugins/linkPanel.js";
|
|
15
|
+
import { editorClassNames } from "../styles/classNames.js";
|
|
16
|
+
import { pointBelowPos, usePanelAtPoint } from "./panelPlacement.js";
|
|
17
|
+
import { commandRunner } from "./runCommand.js";
|
|
18
|
+
import { ICON_SIZE } from "./ToolbarButton.js";
|
|
19
|
+
import { tooltipAttribute } from "./Tooltip.js";
|
|
20
|
+
import { useDismiss } from "./useDismiss.js";
|
|
21
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
22
|
+
var FOCUSABLE = "input,button:not(:disabled)";
|
|
23
|
+
function LinkPanel({ view, state }) {
|
|
24
|
+
const box = useRef(null);
|
|
25
|
+
const field = useRef(null);
|
|
26
|
+
const current = activeLink(state);
|
|
27
|
+
const [address, setAddress] = useState(current ?? "");
|
|
28
|
+
const placement = usePanelAtPoint(
|
|
29
|
+
box,
|
|
30
|
+
pointBelowPos(view, state.selection.head)
|
|
31
|
+
);
|
|
32
|
+
const run = commandRunner(view);
|
|
33
|
+
const close = useCallback(() => {
|
|
34
|
+
closeLinkPanel(view.state, (tr) => view.dispatch(tr));
|
|
35
|
+
view.focus();
|
|
36
|
+
}, [view]);
|
|
37
|
+
useDismiss(box, true, close);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const input = field.current;
|
|
40
|
+
if (!input || !placement || input === document.activeElement) return;
|
|
41
|
+
input.focus({ preventScroll: true });
|
|
42
|
+
input.select();
|
|
43
|
+
}, [placement]);
|
|
44
|
+
const emptied = address.trim() === "";
|
|
45
|
+
const applies = emptied ? removeLink(state) : setLink(address)(state);
|
|
46
|
+
const apply = () => {
|
|
47
|
+
run(emptied ? removeLink : setLink(address));
|
|
48
|
+
close();
|
|
49
|
+
};
|
|
50
|
+
const onKeyDown = (event) => {
|
|
51
|
+
if (event.key !== "Tab") return;
|
|
52
|
+
const controls = Array.from(
|
|
53
|
+
box.current?.querySelectorAll(FOCUSABLE) ?? []
|
|
54
|
+
);
|
|
55
|
+
if (controls.length === 0) return;
|
|
56
|
+
const at = controls.findIndex(
|
|
57
|
+
(control) => control === document.activeElement
|
|
58
|
+
);
|
|
59
|
+
const step = event.shiftKey ? -1 : 1;
|
|
60
|
+
const next = controls[(at + step + controls.length) % controls.length];
|
|
61
|
+
next.focus();
|
|
62
|
+
event.preventDefault();
|
|
63
|
+
};
|
|
64
|
+
return /* @__PURE__ */ jsx(
|
|
65
|
+
"div",
|
|
66
|
+
{
|
|
67
|
+
ref: box,
|
|
68
|
+
className: editorClassNames.linkPanel,
|
|
69
|
+
role: "dialog",
|
|
70
|
+
"aria-label": "Link",
|
|
71
|
+
onKeyDown,
|
|
72
|
+
style: {
|
|
73
|
+
left: placement?.left,
|
|
74
|
+
top: placement?.top,
|
|
75
|
+
// Hide until the dialog has been measured.
|
|
76
|
+
visibility: placement ? void 0 : "hidden"
|
|
77
|
+
},
|
|
78
|
+
children: /* @__PURE__ */ jsxs("div", { className: editorClassNames.linkPanelRow, children: [
|
|
79
|
+
/* @__PURE__ */ jsx(
|
|
80
|
+
Link2,
|
|
81
|
+
{
|
|
82
|
+
size: ICON_SIZE,
|
|
83
|
+
"aria-hidden": "true",
|
|
84
|
+
className: editorClassNames.linkPanelIcon
|
|
85
|
+
}
|
|
86
|
+
),
|
|
87
|
+
/* @__PURE__ */ jsx(
|
|
88
|
+
"input",
|
|
89
|
+
{
|
|
90
|
+
ref: field,
|
|
91
|
+
type: "text",
|
|
92
|
+
className: editorClassNames.linkAddress,
|
|
93
|
+
"aria-label": "Address",
|
|
94
|
+
value: address,
|
|
95
|
+
onChange: (event) => setAddress(event.target.value),
|
|
96
|
+
onKeyDown: (event) => {
|
|
97
|
+
if (event.key !== "Enter") return;
|
|
98
|
+
event.preventDefault();
|
|
99
|
+
apply();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
),
|
|
103
|
+
/* @__PURE__ */ jsx(
|
|
104
|
+
"button",
|
|
105
|
+
{
|
|
106
|
+
type: "button",
|
|
107
|
+
className: editorClassNames.toolbarButton,
|
|
108
|
+
disabled: !applies,
|
|
109
|
+
onClick: apply,
|
|
110
|
+
"aria-label": "Apply",
|
|
111
|
+
...tooltipAttribute("Apply"),
|
|
112
|
+
children: /* @__PURE__ */ jsx(Check, { size: ICON_SIZE, "aria-hidden": "true" })
|
|
113
|
+
}
|
|
114
|
+
)
|
|
115
|
+
] })
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
export {
|
|
120
|
+
LinkPanel
|
|
121
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Choice row with a fixed check slot for stable label alignment. */
|
|
2
|
+
import { type LucideIcon } from "lucide-react";
|
|
3
|
+
import type { ReactElement } from "react";
|
|
4
|
+
export interface MenuChoiceProps {
|
|
5
|
+
label: string;
|
|
6
|
+
icon?: LucideIcon;
|
|
7
|
+
role: "menuitemradio" | "menuitemcheckbox";
|
|
8
|
+
checked: boolean;
|
|
9
|
+
onChoose: () => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function MenuChoice({ label, icon: Icon, role, checked, onChoose, }: MenuChoiceProps): ReactElement;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// src/ui/MenuChoice.tsx
|
|
2
|
+
import { Check } from "lucide-react";
|
|
3
|
+
import { editorClassNames } from "../styles/classNames.js";
|
|
4
|
+
import { ICON_SIZE } from "./ToolbarButton.js";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
function MenuChoice({
|
|
7
|
+
label,
|
|
8
|
+
icon: Icon,
|
|
9
|
+
role,
|
|
10
|
+
checked,
|
|
11
|
+
onChoose
|
|
12
|
+
}) {
|
|
13
|
+
return /* @__PURE__ */ jsxs(
|
|
14
|
+
"button",
|
|
15
|
+
{
|
|
16
|
+
type: "button",
|
|
17
|
+
role,
|
|
18
|
+
className: editorClassNames.menuItem,
|
|
19
|
+
"aria-checked": checked,
|
|
20
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
21
|
+
onClick: onChoose,
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ jsx("span", { className: editorClassNames.menuCheck, children: checked && /* @__PURE__ */ jsx(Check, { size: ICON_SIZE, "aria-hidden": "true" }) }),
|
|
24
|
+
Icon && /* @__PURE__ */ jsx(Icon, { size: ICON_SIZE, "aria-hidden": "true" }),
|
|
25
|
+
label
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
MenuChoice
|
|
32
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/ui/NotesPanel.tsx
|
|
2
|
+
import { documentNotes } from "../editor/commands/noteQueries.js";
|
|
3
|
+
import { editorClassNames } from "../styles/classNames.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
function NotesPanel({
|
|
6
|
+
state,
|
|
7
|
+
pageWidth
|
|
8
|
+
}) {
|
|
9
|
+
const notes = documentNotes(state);
|
|
10
|
+
if (notes.length === 0) return null;
|
|
11
|
+
return /* @__PURE__ */ jsxs(
|
|
12
|
+
"section",
|
|
13
|
+
{
|
|
14
|
+
className: editorClassNames.notesPanel,
|
|
15
|
+
"aria-label": "Document notes",
|
|
16
|
+
style: { width: `${pageWidth}px` },
|
|
17
|
+
children: [
|
|
18
|
+
/* @__PURE__ */ jsx("h2", { className: editorClassNames.notesHeading, children: "Footnotes and endnotes" }),
|
|
19
|
+
/* @__PURE__ */ jsx("ol", { className: editorClassNames.notesList, children: notes.map((note) => /* @__PURE__ */ jsxs("li", { children: [
|
|
20
|
+
/* @__PURE__ */ jsxs("span", { className: editorClassNames.noteLabel, children: [
|
|
21
|
+
note.kind === "footnote" ? "Footnote" : "Endnote",
|
|
22
|
+
" ",
|
|
23
|
+
note.label
|
|
24
|
+
] }),
|
|
25
|
+
/* @__PURE__ */ jsx("p", { className: editorClassNames.noteBody, children: note.text })
|
|
26
|
+
] }, `${note.kind}:${note.id}`)) })
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
export {
|
|
32
|
+
NotesPanel
|
|
33
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Selects document-defined paragraph styles and clears explicit styles through the default entry. */
|
|
2
|
+
import type { ReactElement } from "react";
|
|
3
|
+
import type { ParagraphStyleOption } from "../docx/formatting";
|
|
4
|
+
import { type ActiveParagraphStyle } from "../editor/commands/paragraphCommands";
|
|
5
|
+
import type { RunCommand } from "./runCommand";
|
|
6
|
+
export interface ParagraphStyleSelectProps {
|
|
7
|
+
current: ActiveParagraphStyle;
|
|
8
|
+
styles: readonly ParagraphStyleOption[];
|
|
9
|
+
run: RunCommand;
|
|
10
|
+
}
|
|
11
|
+
export declare function ParagraphStyleSelect({ current, styles, run, }: ParagraphStyleSelectProps): ReactElement;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// src/ui/ParagraphStyleSelect.tsx
|
|
2
|
+
import {
|
|
3
|
+
setParagraphStyle
|
|
4
|
+
} from "../editor/commands/paragraphCommands.js";
|
|
5
|
+
import { editorClassNames } from "../styles/classNames.js";
|
|
6
|
+
import { Tooltip } from "./Tooltip.js";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
var LABEL = "Style";
|
|
9
|
+
var CLEAR = "default";
|
|
10
|
+
var BLANK = "";
|
|
11
|
+
var ID_PREFIX = "id:";
|
|
12
|
+
var styleValue = (id) => `${ID_PREFIX}${id}`;
|
|
13
|
+
function defaultName(styles) {
|
|
14
|
+
return styles.find((style) => style.isDefault)?.name ?? "Normal";
|
|
15
|
+
}
|
|
16
|
+
function namedStyles(styles) {
|
|
17
|
+
return styles.filter(
|
|
18
|
+
(style) => !style.isDefault && style.primary && !style.hidden
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
function selectedValue(styles, current) {
|
|
22
|
+
if (current.kind !== "shared") return BLANK;
|
|
23
|
+
if (current.styleId === null) return CLEAR;
|
|
24
|
+
const named = styles.find((style) => style.id === current.styleId);
|
|
25
|
+
if (!named || named.hidden || !named.isDefault && !named.primary) {
|
|
26
|
+
return BLANK;
|
|
27
|
+
}
|
|
28
|
+
return named?.isDefault ? CLEAR : styleValue(current.styleId);
|
|
29
|
+
}
|
|
30
|
+
function ParagraphStyleSelect({
|
|
31
|
+
current,
|
|
32
|
+
styles,
|
|
33
|
+
run
|
|
34
|
+
}) {
|
|
35
|
+
const value = selectedValue(styles, current);
|
|
36
|
+
return /* @__PURE__ */ jsx(Tooltip, { label: LABEL, children: /* @__PURE__ */ jsxs(
|
|
37
|
+
"select",
|
|
38
|
+
{
|
|
39
|
+
className: editorClassNames.toolbarSelect,
|
|
40
|
+
"aria-label": LABEL,
|
|
41
|
+
value,
|
|
42
|
+
disabled: current.kind === "none",
|
|
43
|
+
onChange: (event) => {
|
|
44
|
+
const chosen = event.target.value;
|
|
45
|
+
if (chosen === BLANK) return;
|
|
46
|
+
run(
|
|
47
|
+
setParagraphStyle(
|
|
48
|
+
chosen === CLEAR ? null : chosen.slice(ID_PREFIX.length)
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
},
|
|
52
|
+
children: [
|
|
53
|
+
value === BLANK && /* @__PURE__ */ jsx("option", { value: BLANK }),
|
|
54
|
+
/* @__PURE__ */ jsx("option", { value: CLEAR, children: defaultName(styles) }),
|
|
55
|
+
namedStyles(styles).map((style) => /* @__PURE__ */ jsx("option", { value: styleValue(style.id), children: style.name }, style.id))
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
) });
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
ParagraphStyleSelect
|
|
62
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toolbar-button popover. Keyboard activation moves focus inside and restores it on close;
|
|
3
|
+
* pointer activation leaves the current focus unchanged.
|
|
4
|
+
*/
|
|
5
|
+
import type { LucideIcon } from "lucide-react";
|
|
6
|
+
import { type ReactElement, type ReactNode } from "react";
|
|
7
|
+
/** Menus provide their own role; dialogs use the popover wrapper. */
|
|
8
|
+
export type PopoverPanel = "menu" | "dialog";
|
|
9
|
+
export interface PanelHandle {
|
|
10
|
+
close: () => void;
|
|
11
|
+
/** Whether keyboard activation requested focus inside the panel. */
|
|
12
|
+
takeFocus: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface PopoverProps {
|
|
15
|
+
label: string;
|
|
16
|
+
icon: LucideIcon;
|
|
17
|
+
indicatorColor?: string;
|
|
18
|
+
panel: PopoverPanel;
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
children: (handle: PanelHandle) => ReactNode;
|
|
21
|
+
}
|
|
22
|
+
export declare function Popover({ label, icon, indicatorColor, panel: kind, disabled, children, }: PopoverProps): ReactElement;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// src/ui/Popover.tsx
|
|
2
|
+
import {
|
|
3
|
+
useCallback,
|
|
4
|
+
useRef,
|
|
5
|
+
useState
|
|
6
|
+
} from "react";
|
|
7
|
+
import { editorClassNames } from "../styles/classNames.js";
|
|
8
|
+
import { usePanelUnderControl } from "./panelPlacement.js";
|
|
9
|
+
import { ToolbarButton } from "./ToolbarButton.js";
|
|
10
|
+
import { useDismiss } from "./useDismiss.js";
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
function Popover({
|
|
13
|
+
label,
|
|
14
|
+
icon,
|
|
15
|
+
indicatorColor,
|
|
16
|
+
panel: kind,
|
|
17
|
+
disabled,
|
|
18
|
+
children
|
|
19
|
+
}) {
|
|
20
|
+
const [open, setOpen] = useState(false);
|
|
21
|
+
const box = useRef(null);
|
|
22
|
+
const button = useRef(null);
|
|
23
|
+
const panel = useRef(null);
|
|
24
|
+
const holdsFocus = useRef(false);
|
|
25
|
+
const close = useCallback(() => {
|
|
26
|
+
setOpen(false);
|
|
27
|
+
if (holdsFocus.current) button.current?.focus({ preventScroll: true });
|
|
28
|
+
holdsFocus.current = false;
|
|
29
|
+
}, []);
|
|
30
|
+
useDismiss(box, open, close);
|
|
31
|
+
const position = usePanelUnderControl(panel, button, open);
|
|
32
|
+
const toggle = (source) => {
|
|
33
|
+
if (open) {
|
|
34
|
+
close();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
holdsFocus.current = source === "keyboard";
|
|
38
|
+
setOpen(true);
|
|
39
|
+
};
|
|
40
|
+
return /* @__PURE__ */ jsxs("div", { className: editorClassNames.popoverBox, ref: box, children: [
|
|
41
|
+
/* @__PURE__ */ jsx(
|
|
42
|
+
ToolbarButton,
|
|
43
|
+
{
|
|
44
|
+
ref: button,
|
|
45
|
+
label,
|
|
46
|
+
icon,
|
|
47
|
+
indicatorColor,
|
|
48
|
+
popup: kind,
|
|
49
|
+
expanded: open,
|
|
50
|
+
disabled,
|
|
51
|
+
onRun: toggle
|
|
52
|
+
}
|
|
53
|
+
),
|
|
54
|
+
open && /* @__PURE__ */ jsx(
|
|
55
|
+
"div",
|
|
56
|
+
{
|
|
57
|
+
ref: panel,
|
|
58
|
+
className: editorClassNames.popover,
|
|
59
|
+
role: kind === "dialog" ? "dialog" : void 0,
|
|
60
|
+
"aria-label": kind === "dialog" ? label : void 0,
|
|
61
|
+
style: {
|
|
62
|
+
left: position?.left,
|
|
63
|
+
top: position?.top,
|
|
64
|
+
// Hide until the panel has been measured.
|
|
65
|
+
visibility: position ? void 0 : "hidden"
|
|
66
|
+
},
|
|
67
|
+
children: children({ close, takeFocus: holdsFocus.current })
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
] });
|
|
71
|
+
}
|
|
72
|
+
export {
|
|
73
|
+
Popover
|
|
74
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { EditorState } from "prosemirror-state";
|
|
2
|
+
import { type ReactElement } from "react";
|
|
3
|
+
import { type LineSpacingOption } from "../styles/lineSpacings";
|
|
4
|
+
import type { RunCommand } from "./runCommand";
|
|
5
|
+
export interface SpacingMenuProps {
|
|
6
|
+
state: EditorState;
|
|
7
|
+
lineSpacings?: readonly LineSpacingOption[];
|
|
8
|
+
run: RunCommand;
|
|
9
|
+
close: () => void;
|
|
10
|
+
takeFocus: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function SpacingMenu({ state, lineSpacings, run, close, takeFocus, }: SpacingMenuProps): ReactElement;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// src/ui/SpacingMenu.tsx
|
|
2
|
+
import { useRef } from "react";
|
|
3
|
+
import {
|
|
4
|
+
activeLineSpacing,
|
|
5
|
+
setLineSpacing
|
|
6
|
+
} from "../editor/commands/spacingCommands.js";
|
|
7
|
+
import { editorClassNames } from "../styles/classNames.js";
|
|
8
|
+
import {
|
|
9
|
+
DEFAULT_LINE_SPACINGS
|
|
10
|
+
} from "../styles/lineSpacings.js";
|
|
11
|
+
import { MenuChoice } from "./MenuChoice.js";
|
|
12
|
+
import { useMenuKeyboard } from "./useMenuKeyboard.js";
|
|
13
|
+
import { jsx } from "react/jsx-runtime";
|
|
14
|
+
function isCurrentChoice(current, { spacing }) {
|
|
15
|
+
return current?.rule === "auto" && spacing.rule === "auto" && current.lines === spacing.lines;
|
|
16
|
+
}
|
|
17
|
+
function SpacingMenu({
|
|
18
|
+
state,
|
|
19
|
+
lineSpacings = DEFAULT_LINE_SPACINGS,
|
|
20
|
+
run,
|
|
21
|
+
close,
|
|
22
|
+
takeFocus
|
|
23
|
+
}) {
|
|
24
|
+
const current = activeLineSpacing(state);
|
|
25
|
+
const menu = useRef(null);
|
|
26
|
+
const keys = useMenuKeyboard({ menu, onClose: close, takeFocus });
|
|
27
|
+
const choose = (command) => {
|
|
28
|
+
run(command);
|
|
29
|
+
close();
|
|
30
|
+
};
|
|
31
|
+
return /* @__PURE__ */ jsx(
|
|
32
|
+
"div",
|
|
33
|
+
{
|
|
34
|
+
ref: menu,
|
|
35
|
+
className: editorClassNames.menuList,
|
|
36
|
+
role: "menu",
|
|
37
|
+
"aria-label": "Line and paragraph spacing",
|
|
38
|
+
...keys,
|
|
39
|
+
children: lineSpacings.map((option) => /* @__PURE__ */ jsx(
|
|
40
|
+
MenuChoice,
|
|
41
|
+
{
|
|
42
|
+
label: option.label,
|
|
43
|
+
role: "menuitemradio",
|
|
44
|
+
checked: isCurrentChoice(current, option),
|
|
45
|
+
onChoose: () => choose(setLineSpacing(option.spacing))
|
|
46
|
+
},
|
|
47
|
+
option.label
|
|
48
|
+
))
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
SpacingMenu
|
|
54
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Table context menu with an optional Unlock action for whole-cell locks. */
|
|
2
|
+
import type { EditorState } from "prosemirror-state";
|
|
3
|
+
import type { EditorView } from "prosemirror-view";
|
|
4
|
+
import { type ReactElement } from "react";
|
|
5
|
+
import { type TableMenuAnchor } from "../editor/plugins/tableContextMenu";
|
|
6
|
+
export interface TableMenuProps {
|
|
7
|
+
view: EditorView;
|
|
8
|
+
state: EditorState;
|
|
9
|
+
anchor: TableMenuAnchor;
|
|
10
|
+
allowLocking?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function TableMenu({ view, state, anchor, allowLocking, }: TableMenuProps): ReactElement;
|