@stll/folio-core 0.4.0 → 0.5.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/dist/ai-edits/apply.d.ts +3 -9
- package/dist/ai-edits/apply.js +94 -14
- package/dist/ai-edits/blockRange.d.ts +33 -0
- package/dist/ai-edits/blockRange.js +58 -0
- package/dist/ai-edits/headless.d.ts +33 -4
- package/dist/ai-edits/headless.js +83 -15
- package/dist/ai-edits/index.d.ts +5 -3
- package/dist/ai-edits/index.js +3 -2
- package/dist/ai-edits/snapshot.d.ts +14 -2
- package/dist/ai-edits/snapshot.js +12 -1
- package/dist/ai-edits/types.d.ts +42 -3
- package/dist/compat/eigenpal.d.ts +3 -2
- package/dist/compat/eigenpal.js +6 -5
- package/dist/controller/layoutPipeline.d.ts +1 -0
- package/dist/controller/layoutPipeline.js +35 -137
- package/dist/controller/layoutScheduler.d.ts +2 -1
- package/dist/controller/layoutScheduler.js +6 -0
- package/dist/document-operations.d.ts +122 -0
- package/dist/document-operations.js +575 -0
- package/dist/docx/blockContentParser.js +17 -7
- package/dist/docx/encryption/agileDecryption.js +2 -1
- package/dist/docx/encryption/compoundFile.js +4 -2
- package/dist/docx/footnoteParser.d.ts +1 -17
- package/dist/docx/footnoteParser.js +1 -27
- package/dist/docx/groupDrawingParser.d.ts +8 -0
- package/dist/docx/groupDrawingParser.js +131 -0
- package/dist/docx/numberingParser.d.ts +3 -1
- package/dist/docx/numberingParser.js +8 -2
- package/dist/docx/paragraphParser.js +9 -3
- package/dist/docx/runParser.js +8 -1
- package/dist/docx/selectiveXmlPatch.js +4 -10
- package/dist/docx/serializer/numberingSerializer.js +3 -1
- package/dist/docx/settingsParser.d.ts +6 -3
- package/dist/docx/settingsParser.js +2 -0
- package/dist/docx/xmlParser.js +11 -4
- package/dist/index.d.ts +3 -2
- package/dist/index.js +6 -5
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +37 -1
- package/dist/layout-bridge/convert/footnoteLayout.js +138 -14
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +5 -7
- package/dist/layout-bridge/convert/headerFooterLayout.js +5 -7
- package/dist/layout-bridge/convert/toFlowBlocks.js +56 -19
- package/dist/layout-engine/index.d.ts +6 -5
- package/dist/layout-engine/index.js +89 -26
- package/dist/layout-engine/keep-together.d.ts +13 -8
- package/dist/layout-engine/keep-together.js +40 -25
- package/dist/layout-engine/layoutInstrumentation.d.ts +11 -1
- package/dist/layout-engine/layoutInstrumentation.js +10 -1
- package/dist/layout-engine/measure/measureBlocks.js +28 -18
- package/dist/layout-engine/measure/measureParagraph.js +61 -15
- package/dist/layout-engine/paginator.d.ts +2 -1
- package/dist/layout-engine/paginator.js +9 -3
- package/dist/layout-engine/textBoxGroup.d.ts +7 -0
- package/dist/layout-engine/textBoxGroup.js +8 -0
- package/dist/layout-engine/types.d.ts +30 -9
- package/dist/layout-engine/types.js +20 -2
- package/dist/layout-painter/renderPage.d.ts +15 -1
- package/dist/layout-painter/renderPage.js +27 -11
- package/dist/layout-painter/renderParagraph.js +18 -8
- package/dist/layout-painter/renderTable.js +10 -7
- package/dist/managers/DocumentLoaderManager.js +12 -5
- package/dist/managers/TableSelectionManager.js +1 -1
- package/dist/model.js +1 -1
- package/dist/paged-layout/pageText.d.ts +14 -0
- package/dist/paged-layout/pageText.js +21 -0
- package/dist/prosemirror/attrs/index.js +2 -0
- package/dist/prosemirror/commands/comments.js +75 -5
- package/dist/prosemirror/commands/hyperlink.js +4 -2
- package/dist/prosemirror/commands/image.js +2 -1
- package/dist/prosemirror/commands/index.js +1 -1
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +68 -0
- package/dist/prosemirror/commands/propertyChangeScope.js +242 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +14 -3
- package/dist/prosemirror/conversion/toProseDoc.js +29 -8
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +6 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.js +10 -11
- package/dist/prosemirror/findReplaceSelection.js +2 -1
- package/dist/prosemirror/index.js +1 -1
- package/dist/prosemirror/insertOperations.js +1 -1
- package/dist/prosemirror/schema/nodes.d.ts +10 -5
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/prosemirror/utils/tabCalculator.js +4 -2
- package/dist/redline.d.ts +20 -0
- package/dist/redline.js +127 -0
- package/dist/server.d.ts +7 -3
- package/dist/server.js +6 -2
- package/dist/symbols.d.ts +35 -0
- package/dist/symbols.js +512 -0
- package/dist/utils/clipboard.js +3 -3
- package/dist/utils/fontLoader.js +3 -0
- package/dist/utils/fontResolver.js +48 -1
- package/dist/utils/zoom.d.ts +21 -0
- package/dist/utils/zoom.js +21 -0
- package/dist/version-comparison.d.ts +92 -0
- package/dist/version-comparison.js +436 -0
- package/package.json +3 -3
- package/dist/paged-layout/headerFooterMargins.d.ts +0 -75
- package/dist/paged-layout/headerFooterMargins.js +0 -122
package/dist/redline.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { FolioDocxReviewer } from "./ai-edits/headless.js";
|
|
2
|
+
import { alignFolioBlocks } from "./version-comparison.js";
|
|
3
|
+
//#region src/redline.ts
|
|
4
|
+
/**
|
|
5
|
+
* Redline generator: compare two `.docx` buffers and produce a THIRD `.docx`
|
|
6
|
+
* whose differences are recorded as real Word tracked changes (`w:ins` /
|
|
7
|
+
* `w:del`), ready for review in Word or the folio editor — the
|
|
8
|
+
* document-producing counterpart to {@link compareDocxVersions}'s structured
|
|
9
|
+
* diff.
|
|
10
|
+
*
|
|
11
|
+
* The pipeline is a composition of existing machinery, not a new engine:
|
|
12
|
+
* the base buffer is opened in a headless {@link FolioDocxReviewer}, the two
|
|
13
|
+
* snapshots are aligned with {@link alignFolioBlocks} (the same three-pass
|
|
14
|
+
* alignment the comparer uses), each alignment event maps onto a
|
|
15
|
+
* tracked-changes {@link FolioAIEditOperation}, and the reviewer's shared
|
|
16
|
+
* apply path records them as redlines. Word-level minimality comes free:
|
|
17
|
+
* the apply engine word-diffs a `replaceBlock` and only marks the divergent
|
|
18
|
+
* tokens.
|
|
19
|
+
*
|
|
20
|
+
* ## Semantics and limitations
|
|
21
|
+
*
|
|
22
|
+
* - **As-accepted inputs.** Pending tracked changes in either input count as
|
|
23
|
+
* applied before comparison (mirroring {@link compareDocxVersions}): the
|
|
24
|
+
* base's own pending redlines are accepted in the output, so the tracked
|
|
25
|
+
* changes it carries are exactly base → revised. This is intentionally
|
|
26
|
+
* lossy about the inputs' own revision history and authorship.
|
|
27
|
+
* - **Text redlines only.** Format-only changes and relocated blocks are
|
|
28
|
+
* redlined as plain edits (a move becomes a delete + insert, like Word
|
|
29
|
+
* compare with move detection off); block-level formatting is carried via
|
|
30
|
+
* the revised block's `styleId` on inserted blocks.
|
|
31
|
+
* - **Anchoring.** Insertions anchor `before` the next surviving base block
|
|
32
|
+
* so consecutive additions keep their order; additions past the last base
|
|
33
|
+
* block anchor `after` it. A base document with no content blocks offers
|
|
34
|
+
* no anchor at all — such additions surface in `skipped` rather than
|
|
35
|
+
* silently vanishing.
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* For each event index, the base block id the next `revisedOnly` event
|
|
39
|
+
* should anchor before: the base side of the nearest later `pair` or
|
|
40
|
+
* `baseOnly` event, or `null` when only additions remain until the end of
|
|
41
|
+
* the document. One backward pass, so a long run of trailing additions
|
|
42
|
+
* (huge revised document vs. a small base) stays linear instead of
|
|
43
|
+
* re-scanning the tail per added block.
|
|
44
|
+
*/
|
|
45
|
+
const nextBaseBlockIdByIndex = (events) => {
|
|
46
|
+
const nextIds = Array.from({ length: events.length });
|
|
47
|
+
let nextId = null;
|
|
48
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
49
|
+
nextIds[i] = nextId;
|
|
50
|
+
const event = events[i];
|
|
51
|
+
if (event?.type === "pair") nextId = event.baseBlock.id;
|
|
52
|
+
else if (event?.type === "baseOnly") nextId = event.block.id;
|
|
53
|
+
}
|
|
54
|
+
return nextIds;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Compare `base` and `revised` and return the base document with every
|
|
58
|
+
* difference recorded as a tracked change. See the module doc comment for
|
|
59
|
+
* semantics and limitations; `skipped` reports any block the generator could
|
|
60
|
+
* not redline (e.g. additions with no anchor in an empty base document).
|
|
61
|
+
*/
|
|
62
|
+
const generateRedlineDocx = async (base, revised, options = {}) => {
|
|
63
|
+
const [baseReviewer, revisedReviewer] = await Promise.all([FolioDocxReviewer.fromBuffer(base, { author: options.author ?? "folio compare" }), FolioDocxReviewer.fromBuffer(revised)]);
|
|
64
|
+
baseReviewer.acceptAll();
|
|
65
|
+
const baseSnapshot = baseReviewer.snapshot();
|
|
66
|
+
const revisedBlocks = revisedReviewer.snapshot().blocks;
|
|
67
|
+
const events = alignFolioBlocks(baseSnapshot.blocks, revisedBlocks);
|
|
68
|
+
const anchorIds = nextBaseBlockIdByIndex(events);
|
|
69
|
+
const operations = [];
|
|
70
|
+
let operationSeq = 0;
|
|
71
|
+
const nextOperationId = () => `redline-${++operationSeq}`;
|
|
72
|
+
/** Additions past the last base block, inserted after it in reverse so the final order matches the revised document. */
|
|
73
|
+
const trailingAdditions = [];
|
|
74
|
+
const lastBaseBlockId = baseSnapshot.blocks.at(-1)?.id ?? null;
|
|
75
|
+
events.forEach((event, eventIndex) => {
|
|
76
|
+
if (event.type === "pair") {
|
|
77
|
+
if (event.baseBlock.text !== event.revisedBlock.text) operations.push({
|
|
78
|
+
id: nextOperationId(),
|
|
79
|
+
type: "replaceBlock",
|
|
80
|
+
blockId: event.baseBlock.id,
|
|
81
|
+
text: event.revisedBlock.text
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (event.type === "baseOnly") {
|
|
86
|
+
operations.push({
|
|
87
|
+
id: nextOperationId(),
|
|
88
|
+
type: "deleteBlock",
|
|
89
|
+
blockId: event.block.id
|
|
90
|
+
});
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const anchorId = anchorIds[eventIndex] ?? null;
|
|
94
|
+
if (anchorId === null) {
|
|
95
|
+
trailingAdditions.push({
|
|
96
|
+
text: event.block.text,
|
|
97
|
+
...event.block.styleId !== void 0 && { styleId: event.block.styleId }
|
|
98
|
+
});
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
operations.push({
|
|
102
|
+
id: nextOperationId(),
|
|
103
|
+
type: "insertBeforeBlock",
|
|
104
|
+
blockId: anchorId,
|
|
105
|
+
text: event.block.text,
|
|
106
|
+
...event.block.styleId !== void 0 && { styleId: event.block.styleId }
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
for (const addition of trailingAdditions.toReversed()) operations.push({
|
|
110
|
+
id: nextOperationId(),
|
|
111
|
+
type: "insertAfterBlock",
|
|
112
|
+
blockId: lastBaseBlockId ?? "redline-unanchored",
|
|
113
|
+
text: addition.text,
|
|
114
|
+
...addition.styleId !== void 0 && { styleId: addition.styleId }
|
|
115
|
+
});
|
|
116
|
+
const { applied, skipped } = baseReviewer.applyOperations(operations, {
|
|
117
|
+
mode: "tracked-changes",
|
|
118
|
+
snapshot: baseSnapshot
|
|
119
|
+
});
|
|
120
|
+
return {
|
|
121
|
+
buffer: await baseReviewer.toBuffer(),
|
|
122
|
+
applied,
|
|
123
|
+
skipped
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
//#endregion
|
|
127
|
+
export { generateRedlineDocx };
|
package/dist/server.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditSnapshot } from "./ai-edits/types.js";
|
|
1
|
+
import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditSnapshot, FolioAIInlineFormatting, FolioAITextRangeHandle } from "./ai-edits/types.js";
|
|
2
|
+
import { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationStatus, FolioDocumentOperationType, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "./document-operations.js";
|
|
2
3
|
import { FolioReviewChange, FolioReviewChangeKind } from "./ai-edits/read.js";
|
|
3
|
-
import { ApplyFolioAIEditsToBufferOptions, ApplyFolioAIEditsToBufferResult, FolioApplyOperationsOptions, FolioDocxReviewer, FolioDocxReviewerOptions, FolioReviewChangeFilter, FolioReviewComment, FolioReviewCommentFilter, FolioReviewCommentReply, FolioReviewReplyInput, applyFolioAIEditsToBuffer } from "./ai-edits/headless.js";
|
|
4
|
+
import { ApplyFolioAIEditsToBufferOptions, ApplyFolioAIEditsToBufferResult, FolioApplyDocumentOperationsOptions, FolioApplyOperationsOptions, FolioDocumentStory, FolioDocumentStoryHandle, FolioDocxReviewer, FolioDocxReviewerOptions, FolioReviewChangeFilter, FolioReviewComment, FolioReviewCommentFilter, FolioReviewCommentReply, FolioReviewReplyInput, applyFolioAIEditsToBuffer } from "./ai-edits/headless.js";
|
|
5
|
+
import { createFolioAITextRangeHandle } from "./ai-edits/snapshot.js";
|
|
4
6
|
import { DeriveBlockIdInput, FolioBlockId, deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
|
|
5
7
|
import { CreateEmptyDocumentOptions, createEmptyDocument } from "./utils/createDocument.js";
|
|
6
8
|
import { createDocx } from "./docx/rezip.js";
|
|
7
9
|
import { CreateCommentReplyInput, replyToComment } from "./docx/replyToComment.js";
|
|
8
|
-
|
|
10
|
+
import { GenerateRedlineDocxOptions, GenerateRedlineDocxResult, generateRedlineDocx } from "./redline.js";
|
|
11
|
+
import { FolioBlockDiff, FolioFormatProperty, FolioVersionDiff, FolioVersionDiffSegment, compareDocxVersions } from "./version-comparison.js";
|
|
12
|
+
export { type ApplyFolioAIEditsToBufferOptions, type ApplyFolioAIEditsToBufferResult, type CreateCommentReplyInput, type CreateEmptyDocumentOptions, type DeriveBlockIdInput, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIComment, type FolioAIEditApplyMode, type FolioAIEditApplyResult, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditSnapshot, type FolioAIInlineFormatting, type FolioAITextRangeHandle, type FolioApplyDocumentOperationsOptions, type FolioApplyOperationsOptions, type FolioBlockDiff, type FolioBlockId, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationStatus, type FolioDocumentOperationType, type FolioDocumentStory, type FolioDocumentStoryHandle, FolioDocxReviewer, type FolioDocxReviewerOptions, type FolioFormatProperty, type FolioReviewChange, type FolioReviewChangeFilter, type FolioReviewChangeKind, type FolioReviewComment, type FolioReviewCommentFilter, type FolioReviewCommentReply, type FolioReviewReplyInput, type FolioVersionDiff, type FolioVersionDiffSegment, type GenerateRedlineDocxOptions, type GenerateRedlineDocxResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioAIEditsToBuffer, assertSupportedFolioDocumentOperationVersion, compareDocxVersions, createDocx, createEmptyDocument, createFolioAITextRangeHandle, deriveBlockId, generateRedlineDocx, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch, replyToComment };
|
package/dist/server.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
|
|
2
|
+
import { createFolioAITextRangeHandle } from "./ai-edits/snapshot.js";
|
|
3
|
+
import { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "./document-operations.js";
|
|
1
4
|
import { createEmptyDocument } from "./utils/createDocument.js";
|
|
2
5
|
import { createDocx } from "./docx/rezip.js";
|
|
3
|
-
import { deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
|
|
4
6
|
import { replyToComment } from "./docx/replyToComment.js";
|
|
5
7
|
import { FolioDocxReviewer, applyFolioAIEditsToBuffer } from "./ai-edits/headless.js";
|
|
6
|
-
|
|
8
|
+
import { compareDocxVersions } from "./version-comparison.js";
|
|
9
|
+
import { generateRedlineDocx } from "./redline.js";
|
|
10
|
+
export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FolioDocxReviewer, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioAIEditsToBuffer, assertSupportedFolioDocumentOperationVersion, compareDocxVersions, createDocx, createEmptyDocument, createFolioAITextRangeHandle, deriveBlockId, generateRedlineDocx, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch, replyToComment };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/symbols.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Symbol catalog for the "Insert Symbol" dialog.
|
|
4
|
+
*
|
|
5
|
+
* Framework-neutral data + filtering shared by every folio adapter (React,
|
|
6
|
+
* Vue, ...), so the two never drift on which symbols they offer. Category
|
|
7
|
+
* display names are i18n keys (`dialogs.insertSymbol.categories.*`) resolved by
|
|
8
|
+
* each adapter's own translator; the `char`/`name` pairs are the raw catalog.
|
|
9
|
+
*/
|
|
10
|
+
type SymbolEntry = {
|
|
11
|
+
/** The character to insert. */char: string; /** English descriptive name, used for search matching. */
|
|
12
|
+
name: string;
|
|
13
|
+
};
|
|
14
|
+
/** i18n message keys for the symbol-category display labels. */
|
|
15
|
+
type SymbolCategoryNameKey = "dialogs.insertSymbol.categories.common" | "dialogs.insertSymbol.categories.arrows" | "dialogs.insertSymbol.categories.math" | "dialogs.insertSymbol.categories.greek" | "dialogs.insertSymbol.categories.currency" | "dialogs.insertSymbol.categories.shapes";
|
|
16
|
+
type SymbolCategory = {
|
|
17
|
+
/** Stable category id (also the default active tab). */name: string; /** i18n key for the category's display label. */
|
|
18
|
+
nameKey: SymbolCategoryNameKey;
|
|
19
|
+
symbols: SymbolEntry[];
|
|
20
|
+
};
|
|
21
|
+
/** A catalog entry tagged with the category it belongs to (search results). */
|
|
22
|
+
type SymbolSearchEntry = SymbolEntry & {
|
|
23
|
+
category: string;
|
|
24
|
+
};
|
|
25
|
+
declare const SYMBOL_CATEGORIES: SymbolCategory[];
|
|
26
|
+
/** Every catalog symbol, flattened and tagged with its category. */
|
|
27
|
+
declare const ALL_SYMBOLS: SymbolSearchEntry[];
|
|
28
|
+
/**
|
|
29
|
+
* Symbols whose descriptive name contains `query` (case-insensitive), or whose
|
|
30
|
+
* character is exactly `query`. An empty/whitespace query returns `[]` so
|
|
31
|
+
* callers fall back to the active category.
|
|
32
|
+
*/
|
|
33
|
+
declare function filterSymbols(query: string): SymbolSearchEntry[];
|
|
34
|
+
//#endregion
|
|
35
|
+
export { ALL_SYMBOLS, SYMBOL_CATEGORIES, SymbolCategory, SymbolCategoryNameKey, SymbolEntry, SymbolSearchEntry, filterSymbols };
|
package/dist/symbols.js
ADDED
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
//#region src/symbols.ts
|
|
2
|
+
const SYMBOL_CATEGORIES = [
|
|
3
|
+
{
|
|
4
|
+
name: "Common",
|
|
5
|
+
nameKey: "dialogs.insertSymbol.categories.common",
|
|
6
|
+
symbols: [
|
|
7
|
+
{
|
|
8
|
+
char: "©",
|
|
9
|
+
name: "Copyright"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
char: "®",
|
|
13
|
+
name: "Registered"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
char: "™",
|
|
17
|
+
name: "Trademark"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
char: "•",
|
|
21
|
+
name: "Bullet"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
char: "…",
|
|
25
|
+
name: "Ellipsis"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
char: "—",
|
|
29
|
+
name: "Em dash"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
char: "–",
|
|
33
|
+
name: "En dash"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
char: "±",
|
|
37
|
+
name: "Plus-minus"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
char: "×",
|
|
41
|
+
name: "Multiply"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
char: "÷",
|
|
45
|
+
name: "Divide"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
char: "≠",
|
|
49
|
+
name: "Not equal"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
char: "≈",
|
|
53
|
+
name: "Approximately"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
char: "≤",
|
|
57
|
+
name: "Less or equal"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
char: "≥",
|
|
61
|
+
name: "Greater or equal"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
char: "°",
|
|
65
|
+
name: "Degree"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
char: "µ",
|
|
69
|
+
name: "Micro"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
char: "¶",
|
|
73
|
+
name: "Pilcrow"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
char: "§",
|
|
77
|
+
name: "Section"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
char: "†",
|
|
81
|
+
name: "Dagger"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
char: "‡",
|
|
85
|
+
name: "Double dagger"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
char: "¿",
|
|
89
|
+
name: "Inverted question"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
char: "¡",
|
|
93
|
+
name: "Inverted exclamation"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
char: "‰",
|
|
97
|
+
name: "Per mille"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
char: "∞",
|
|
101
|
+
name: "Infinity"
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "Arrows",
|
|
107
|
+
nameKey: "dialogs.insertSymbol.categories.arrows",
|
|
108
|
+
symbols: [
|
|
109
|
+
{
|
|
110
|
+
char: "←",
|
|
111
|
+
name: "Left"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
char: "→",
|
|
115
|
+
name: "Right"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
char: "↑",
|
|
119
|
+
name: "Up"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
char: "↓",
|
|
123
|
+
name: "Down"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
char: "↔",
|
|
127
|
+
name: "Left-right"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
char: "↕",
|
|
131
|
+
name: "Up-down"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
char: "⇐",
|
|
135
|
+
name: "Double left"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
char: "⇒",
|
|
139
|
+
name: "Double right"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
char: "⇑",
|
|
143
|
+
name: "Double up"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
char: "⇓",
|
|
147
|
+
name: "Double down"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
char: "⇔",
|
|
151
|
+
name: "Double left-right"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
char: "➡",
|
|
155
|
+
name: "Heavy right"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
char: "↩",
|
|
159
|
+
name: "Return"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
char: "↪",
|
|
163
|
+
name: "Curved right"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
char: "↻",
|
|
167
|
+
name: "Clockwise"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
char: "↺",
|
|
171
|
+
name: "Counter-clockwise"
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: "Math",
|
|
177
|
+
nameKey: "dialogs.insertSymbol.categories.math",
|
|
178
|
+
symbols: [
|
|
179
|
+
{
|
|
180
|
+
char: "∑",
|
|
181
|
+
name: "Summation"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
char: "∏",
|
|
185
|
+
name: "Product"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
char: "∫",
|
|
189
|
+
name: "Integral"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
char: "√",
|
|
193
|
+
name: "Square root"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
char: "∂",
|
|
197
|
+
name: "Partial diff"
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
char: "∇",
|
|
201
|
+
name: "Nabla"
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
char: "∈",
|
|
205
|
+
name: "Element of"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
char: "∉",
|
|
209
|
+
name: "Not element"
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
char: "⊂",
|
|
213
|
+
name: "Subset"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
char: "⊃",
|
|
217
|
+
name: "Superset"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
char: "∪",
|
|
221
|
+
name: "Union"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
char: "∩",
|
|
225
|
+
name: "Intersection"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
char: "∧",
|
|
229
|
+
name: "And"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
char: "∨",
|
|
233
|
+
name: "Or"
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
char: "¬",
|
|
237
|
+
name: "Not"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
char: "∀",
|
|
241
|
+
name: "For all"
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
char: "∃",
|
|
245
|
+
name: "Exists"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
char: "∅",
|
|
249
|
+
name: "Empty set"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
char: "∝",
|
|
253
|
+
name: "Proportional"
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
char: "∠",
|
|
257
|
+
name: "Angle"
|
|
258
|
+
}
|
|
259
|
+
]
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
name: "Greek",
|
|
263
|
+
nameKey: "dialogs.insertSymbol.categories.greek",
|
|
264
|
+
symbols: [
|
|
265
|
+
{
|
|
266
|
+
char: "α",
|
|
267
|
+
name: "alpha"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
char: "β",
|
|
271
|
+
name: "beta"
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
char: "γ",
|
|
275
|
+
name: "gamma"
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
char: "δ",
|
|
279
|
+
name: "delta"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
char: "ε",
|
|
283
|
+
name: "epsilon"
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
char: "ζ",
|
|
287
|
+
name: "zeta"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
char: "η",
|
|
291
|
+
name: "eta"
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
char: "θ",
|
|
295
|
+
name: "theta"
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
char: "λ",
|
|
299
|
+
name: "lambda"
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
char: "μ",
|
|
303
|
+
name: "mu"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
char: "π",
|
|
307
|
+
name: "pi"
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
char: "ρ",
|
|
311
|
+
name: "rho"
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
char: "σ",
|
|
315
|
+
name: "sigma"
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
char: "τ",
|
|
319
|
+
name: "tau"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
char: "φ",
|
|
323
|
+
name: "phi"
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
char: "ψ",
|
|
327
|
+
name: "psi"
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
char: "ω",
|
|
331
|
+
name: "omega"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
char: "Δ",
|
|
335
|
+
name: "Delta"
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
char: "Σ",
|
|
339
|
+
name: "Sigma"
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
char: "Ω",
|
|
343
|
+
name: "Omega"
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
char: "Π",
|
|
347
|
+
name: "Pi"
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
char: "Φ",
|
|
351
|
+
name: "Phi"
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
char: "Ψ",
|
|
355
|
+
name: "Psi"
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
char: "Θ",
|
|
359
|
+
name: "Theta"
|
|
360
|
+
}
|
|
361
|
+
]
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
name: "Currency",
|
|
365
|
+
nameKey: "dialogs.insertSymbol.categories.currency",
|
|
366
|
+
symbols: [
|
|
367
|
+
{
|
|
368
|
+
char: "$",
|
|
369
|
+
name: "Dollar"
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
char: "€",
|
|
373
|
+
name: "Euro"
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
char: "£",
|
|
377
|
+
name: "Pound"
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
char: "¥",
|
|
381
|
+
name: "Yen"
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
char: "₹",
|
|
385
|
+
name: "Rupee"
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
char: "₽",
|
|
389
|
+
name: "Ruble"
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
char: "₩",
|
|
393
|
+
name: "Won"
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
char: "₿",
|
|
397
|
+
name: "Bitcoin"
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
char: "¢",
|
|
401
|
+
name: "Cent"
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
char: "₫",
|
|
405
|
+
name: "Dong"
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
char: "₺",
|
|
409
|
+
name: "Lira"
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
char: "₴",
|
|
413
|
+
name: "Hryvnia"
|
|
414
|
+
}
|
|
415
|
+
]
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
name: "Shapes",
|
|
419
|
+
nameKey: "dialogs.insertSymbol.categories.shapes",
|
|
420
|
+
symbols: [
|
|
421
|
+
{
|
|
422
|
+
char: "■",
|
|
423
|
+
name: "Black square"
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
char: "□",
|
|
427
|
+
name: "White square"
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
char: "▲",
|
|
431
|
+
name: "Up triangle"
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
char: "▼",
|
|
435
|
+
name: "Down triangle"
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
char: "●",
|
|
439
|
+
name: "Black circle"
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
char: "○",
|
|
443
|
+
name: "White circle"
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
char: "◆",
|
|
447
|
+
name: "Black diamond"
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
char: "◇",
|
|
451
|
+
name: "White diamond"
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
char: "★",
|
|
455
|
+
name: "Black star"
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
char: "☆",
|
|
459
|
+
name: "White star"
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
char: "♠",
|
|
463
|
+
name: "Spade"
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
char: "♥",
|
|
467
|
+
name: "Heart"
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
char: "♦",
|
|
471
|
+
name: "Diamond"
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
char: "♣",
|
|
475
|
+
name: "Club"
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
char: "✓",
|
|
479
|
+
name: "Check mark"
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
char: "✗",
|
|
483
|
+
name: "Ballot X"
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
char: "✦",
|
|
487
|
+
name: "Four pointed star"
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
char: "◌",
|
|
491
|
+
name: "Dotted circle"
|
|
492
|
+
}
|
|
493
|
+
]
|
|
494
|
+
}
|
|
495
|
+
];
|
|
496
|
+
/** Every catalog symbol, flattened and tagged with its category. */
|
|
497
|
+
const ALL_SYMBOLS = SYMBOL_CATEGORIES.flatMap((category) => category.symbols.map((symbol) => ({
|
|
498
|
+
...symbol,
|
|
499
|
+
category: category.name
|
|
500
|
+
})));
|
|
501
|
+
/**
|
|
502
|
+
* Symbols whose descriptive name contains `query` (case-insensitive), or whose
|
|
503
|
+
* character is exactly `query`. An empty/whitespace query returns `[]` so
|
|
504
|
+
* callers fall back to the active category.
|
|
505
|
+
*/
|
|
506
|
+
function filterSymbols(query) {
|
|
507
|
+
const q = query.trim().toLowerCase();
|
|
508
|
+
if (!q) return [];
|
|
509
|
+
return ALL_SYMBOLS.filter((symbol) => symbol.name.toLowerCase().includes(q) || symbol.char === q);
|
|
510
|
+
}
|
|
511
|
+
//#endregion
|
|
512
|
+
export { ALL_SYMBOLS, SYMBOL_CATEGORIES, filterSymbols };
|