@zephytiju/prism-main-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.
Files changed (69) hide show
  1. package/README.md +252 -0
  2. package/dist/CommentsPane.d.ts +32 -0
  3. package/dist/CommentsPane.d.ts.map +1 -0
  4. package/dist/CommentsPane.js +85 -0
  5. package/dist/MainEditor.d.ts +59 -0
  6. package/dist/MainEditor.d.ts.map +1 -0
  7. package/dist/MainEditor.js +102 -0
  8. package/dist/TitleBar.d.ts +28 -0
  9. package/dist/TitleBar.d.ts.map +1 -0
  10. package/dist/TitleBar.js +55 -0
  11. package/dist/blocks/AssessmentBlockView.d.ts +21 -0
  12. package/dist/blocks/AssessmentBlockView.d.ts.map +1 -0
  13. package/dist/blocks/AssessmentBlockView.js +34 -0
  14. package/dist/blocks/BlockRow.d.ts +33 -0
  15. package/dist/blocks/BlockRow.d.ts.map +1 -0
  16. package/dist/blocks/BlockRow.js +56 -0
  17. package/dist/blocks/BlockStack.d.ts +27 -0
  18. package/dist/blocks/BlockStack.d.ts.map +1 -0
  19. package/dist/blocks/BlockStack.js +75 -0
  20. package/dist/blocks/DragMenu.d.ts +22 -0
  21. package/dist/blocks/DragMenu.d.ts.map +1 -0
  22. package/dist/blocks/DragMenu.js +219 -0
  23. package/dist/blocks/EmbeddedBlockChrome.d.ts +34 -0
  24. package/dist/blocks/EmbeddedBlockChrome.d.ts.map +1 -0
  25. package/dist/blocks/EmbeddedBlockChrome.js +81 -0
  26. package/dist/blocks/EvidenceTableView.d.ts +25 -0
  27. package/dist/blocks/EvidenceTableView.d.ts.map +1 -0
  28. package/dist/blocks/EvidenceTableView.js +30 -0
  29. package/dist/blocks/GeovisionEmbedView.d.ts +28 -0
  30. package/dist/blocks/GeovisionEmbedView.d.ts.map +1 -0
  31. package/dist/blocks/GeovisionEmbedView.js +33 -0
  32. package/dist/blocks/InsertMenu.d.ts +22 -0
  33. package/dist/blocks/InsertMenu.d.ts.map +1 -0
  34. package/dist/blocks/InsertMenu.js +59 -0
  35. package/dist/blocks/InsertRail.d.ts +28 -0
  36. package/dist/blocks/InsertRail.d.ts.map +1 -0
  37. package/dist/blocks/InsertRail.js +29 -0
  38. package/dist/blocks/NarrativeBlockView.d.ts +22 -0
  39. package/dist/blocks/NarrativeBlockView.d.ts.map +1 -0
  40. package/dist/blocks/NarrativeBlockView.js +44 -0
  41. package/dist/blocks/NativeTableView.d.ts +12 -0
  42. package/dist/blocks/NativeTableView.d.ts.map +1 -0
  43. package/dist/blocks/NativeTableView.js +36 -0
  44. package/dist/blocks/SavedViewDropdown.d.ts +17 -0
  45. package/dist/blocks/SavedViewDropdown.d.ts.map +1 -0
  46. package/dist/blocks/SavedViewDropdown.js +85 -0
  47. package/dist/blocks/SelectionToolbar.d.ts +25 -0
  48. package/dist/blocks/SelectionToolbar.d.ts.map +1 -0
  49. package/dist/blocks/SelectionToolbar.js +175 -0
  50. package/dist/blocks/menuStyles.d.ts +32 -0
  51. package/dist/blocks/menuStyles.d.ts.map +1 -0
  52. package/dist/blocks/menuStyles.js +32 -0
  53. package/dist/index.d.ts +26 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +11 -0
  56. package/dist/locales/en.json +37 -0
  57. package/dist/locales/index.d.ts +105 -0
  58. package/dist/locales/index.d.ts.map +1 -0
  59. package/dist/locales/index.js +27 -0
  60. package/dist/locales/zh-CN.json +37 -0
  61. package/dist/tokens.d.ts +42 -0
  62. package/dist/tokens.d.ts.map +1 -0
  63. package/dist/tokens.js +43 -0
  64. package/dist/types.d.ts +207 -0
  65. package/dist/types.d.ts.map +1 -0
  66. package/dist/types.js +1 -0
  67. package/locales/en.json +37 -0
  68. package/locales/zh-CN.json +37 -0
  69. package/package.json +79 -0
@@ -0,0 +1,175 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { Box } from "@mantine/core";
4
+ import { emitPrismEvent } from "@zephytiju/prism-react";
5
+ import { stringsForLocale } from "../locales/index.js";
6
+ import { ACCENT, CARD, LINE, POPOVER_SHADOW, SELECTED_TINT, TEXT } from "../tokens.js";
7
+ /** Toolbar placement offsets (px) — above the selection, like Feishu. */
8
+ const TOOLBAR_OFFSET_ABOVE = 40;
9
+ const TOOLBAR_EDGE_MARGIN = 12;
10
+ /**
11
+ * The D11 text-selection toolbar: selecting text inside the editor's editable
12
+ * text surfaces (narrative heading/paragraph, analyst-judgment body) opens a
13
+ * floating toolbar at the selection. The style actions (bold / italic /
14
+ * underline / strikethrough) apply text-style mutations to the selection via
15
+ * document.execCommand — the DOM is the editing surface while the channel
16
+ * projection stays authoritative for content. The 💬 action wraps the
17
+ * selected range in a token-only highlight mark and emits
18
+ * "main-editor.comment-requested" {blockId, quote}, anchoring a new thread to
19
+ * that text range (the host creates the thread; the aligned comments rail
20
+ * stacks it under its block). The toolbar dismisses whenever the selection
21
+ * collapses (or scrolls away).
22
+ */
23
+ export function SelectionToolbar({ locale, containerRef }) {
24
+ const strings = stringsForLocale(locale);
25
+ const [selection, setSelection] = useState(null);
26
+ const lastRangeRef = useRef(null);
27
+ useEffect(() => {
28
+ const evaluate = () => {
29
+ const container = containerRef.current;
30
+ const active = document.getSelection();
31
+ if (container === null ||
32
+ active === null ||
33
+ active.rangeCount === 0 ||
34
+ active.isCollapsed ||
35
+ active.anchorNode === null ||
36
+ active.focusNode === null) {
37
+ lastRangeRef.current = null;
38
+ setSelection(null);
39
+ return;
40
+ }
41
+ const anchorElement = active.anchorNode.nodeType === Node.ELEMENT_NODE
42
+ ? active.anchorNode
43
+ : active.anchorNode.parentElement;
44
+ const focusElement = active.focusNode.nodeType === Node.ELEMENT_NODE
45
+ ? active.focusNode
46
+ : active.focusNode.parentElement;
47
+ const anchorEditable = anchorElement?.closest("[data-main-editor-editable]") ?? null;
48
+ const focusEditable = focusElement?.closest("[data-main-editor-editable]") ?? null;
49
+ if (anchorEditable === null ||
50
+ anchorEditable !== focusEditable ||
51
+ !container.contains(anchorEditable)) {
52
+ lastRangeRef.current = null;
53
+ setSelection(null);
54
+ return;
55
+ }
56
+ const range = active.getRangeAt(0);
57
+ lastRangeRef.current = range.cloneRange();
58
+ // jsdom's Range lacks geometry: fall back to the editable's rect there.
59
+ const rect = typeof range.getBoundingClientRect === "function"
60
+ ? range.getBoundingClientRect()
61
+ : anchorEditable.getBoundingClientRect();
62
+ setSelection({
63
+ blockId: anchorEditable.getAttribute("data-main-editor-editable") ?? "",
64
+ centerX: rect.left + rect.width / 2,
65
+ top: rect.top,
66
+ bottom: rect.bottom,
67
+ });
68
+ };
69
+ const dismiss = () => {
70
+ lastRangeRef.current = null;
71
+ setSelection(null);
72
+ };
73
+ document.addEventListener("selectionchange", evaluate);
74
+ // Any scroll invalidates the cached placement geometry — dismiss like Feishu.
75
+ document.addEventListener("scroll", dismiss, true);
76
+ return () => {
77
+ document.removeEventListener("selectionchange", evaluate);
78
+ document.removeEventListener("scroll", dismiss, true);
79
+ };
80
+ }, [containerRef]);
81
+ if (selection === null) {
82
+ return null;
83
+ }
84
+ /** Keeps the selection alive while a toolbar button is pressed. */
85
+ const keepSelection = (event) => {
86
+ event.preventDefault();
87
+ };
88
+ const applyStyle = (command) => {
89
+ if (typeof document.execCommand === "function") {
90
+ document.execCommand(command, false);
91
+ }
92
+ };
93
+ const commentOnSelection = () => {
94
+ const container = containerRef.current;
95
+ const editable = container?.querySelector(`[data-main-editor-editable="${selection.blockId}"]`);
96
+ const active = document.getSelection();
97
+ if (editable === null || editable === undefined || active === null || active.rangeCount === 0) {
98
+ return;
99
+ }
100
+ const quote = active.toString();
101
+ const range = lastRangeRef.current !== null && active.isCollapsed
102
+ ? lastRangeRef.current
103
+ : active.getRangeAt(0);
104
+ const mark = document.createElement("span");
105
+ mark.setAttribute("data-main-editor-quote", "true");
106
+ mark.style.background = SELECTED_TINT;
107
+ mark.style.borderRadius = "2px";
108
+ mark.style.padding = "1px 2px";
109
+ try {
110
+ range.surroundContents(mark);
111
+ }
112
+ catch {
113
+ // Selection crossing element boundaries: extract + reinsert instead.
114
+ mark.appendChild(range.extractContents());
115
+ range.insertNode(mark);
116
+ }
117
+ const request = { blockId: selection.blockId, quote };
118
+ emitPrismEvent("main-editor.comment-requested", request);
119
+ active.removeAllRanges();
120
+ setSelection(null);
121
+ };
122
+ const viewportWidth = typeof window === "undefined" ? 0 : window.innerWidth;
123
+ const left = Math.min(Math.max(selection.centerX, TOOLBAR_EDGE_MARGIN + 90), Math.max(viewportWidth - TOOLBAR_EDGE_MARGIN - 90, TOOLBAR_EDGE_MARGIN + 90));
124
+ const style = {
125
+ position: "fixed",
126
+ left,
127
+ top: selection.top >= TOOLBAR_OFFSET_ABOVE ? selection.top - TOOLBAR_OFFSET_ABOVE : selection.bottom + 8,
128
+ transform: "translateX(-50%)",
129
+ height: 34,
130
+ display: "flex",
131
+ alignItems: "center",
132
+ gap: 2,
133
+ padding: "0 6px",
134
+ background: CARD,
135
+ border: `1px solid ${LINE}`,
136
+ borderRadius: 8,
137
+ boxShadow: POPOVER_SHADOW,
138
+ zIndex: 40,
139
+ };
140
+ return (_jsxs(Box, { style: style, "data-testid": "main-editor-selection-toolbar", role: "toolbar", children: [_jsx("style", { children: ".prism-me-ttbtn:hover{background:var(--mantine-color-input-filled);}" }), _jsx(ToolbarButton, { testid: "main-editor-selection-bold", title: strings.boldTitle, bold: true, onPointerDown: keepSelection, onClick: () => {
141
+ applyStyle("bold");
142
+ }, children: "B" }), _jsx(ToolbarButton, { testid: "main-editor-selection-italic", title: strings.italicTitle, italic: true, onPointerDown: keepSelection, onClick: () => {
143
+ applyStyle("italic");
144
+ }, children: "I" }), _jsx(ToolbarButton, { testid: "main-editor-selection-underline", title: strings.underlineTitle, underline: true, onPointerDown: keepSelection, onClick: () => {
145
+ applyStyle("underline");
146
+ }, children: "U" }), _jsx(ToolbarButton, { testid: "main-editor-selection-strikethrough", title: strings.strikethroughTitle, strikethrough: true, onPointerDown: keepSelection, onClick: () => {
147
+ applyStyle("strikeThrough");
148
+ }, children: "S" }), _jsx("span", { style: { width: 1, height: 18, background: "var(--mantine-color-border-filled)", margin: "0 4px" }, "aria-hidden": "true" }), _jsx(ToolbarButton, { testid: "main-editor-selection-comment", title: strings.commentOnSelection, accent: true, onPointerDown: keepSelection, onClick: () => {
149
+ commentOnSelection();
150
+ }, children: "\uD83D\uDCAC" })] }));
151
+ }
152
+ function ToolbarButton({ children, testid, title, bold, italic, underline, strikethrough, accent, onPointerDown, onClick, }) {
153
+ return (_jsx("button", { type: "button", title: title, "aria-label": title, "data-testid": testid, className: "prism-me-ttbtn", style: {
154
+ minWidth: 26,
155
+ height: 26,
156
+ borderRadius: 5,
157
+ display: "inline-flex",
158
+ alignItems: "center",
159
+ justifyContent: "center",
160
+ fontSize: 12,
161
+ fontWeight: bold ? 700 : undefined,
162
+ fontStyle: italic ? "italic" : undefined,
163
+ textDecoration: [
164
+ underline ? "underline" : undefined,
165
+ strikethrough ? "line-through" : undefined,
166
+ ]
167
+ .filter(Boolean)
168
+ .join(" "),
169
+ color: accent ? ACCENT : TEXT,
170
+ background: "transparent",
171
+ border: "none",
172
+ cursor: "pointer",
173
+ padding: "0 4px",
174
+ }, onPointerDown: onPointerDown, onClick: onClick, children: children }));
175
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Shared styling of the editor's popover menus (the insert block-kind menu,
3
+ * the drag block-action menu, the saved-views dropdown): one option-row style
4
+ * and one mono header-row style, both token-only. Kept verbatim-shared so the
5
+ * split menu components render pixel-identically.
6
+ */
7
+ export declare const menuOptionStyle: {
8
+ width: string;
9
+ height: number;
10
+ display: string;
11
+ alignItems: string;
12
+ gap: number;
13
+ padding: string;
14
+ fontFamily: string;
15
+ fontSize: number;
16
+ color: string;
17
+ background: string;
18
+ border: string;
19
+ cursor: string;
20
+ textAlign: "left";
21
+ };
22
+ export declare const menuHeaderStyle: {
23
+ height: number;
24
+ display: string;
25
+ alignItems: string;
26
+ padding: string;
27
+ fontFamily: string;
28
+ fontSize: number;
29
+ color: string;
30
+ letterSpacing: string;
31
+ };
32
+ //# sourceMappingURL=menuStyles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menuStyles.d.ts","sourceRoot":"","sources":["../../src/blocks/menuStyles.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;CAc3B,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;CAS3B,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { MONO, MUTED, TEXT } from "../tokens.js";
2
+ /**
3
+ * Shared styling of the editor's popover menus (the insert block-kind menu,
4
+ * the drag block-action menu, the saved-views dropdown): one option-row style
5
+ * and one mono header-row style, both token-only. Kept verbatim-shared so the
6
+ * split menu components render pixel-identically.
7
+ */
8
+ export const menuOptionStyle = {
9
+ width: "100%",
10
+ height: 26,
11
+ display: "flex",
12
+ alignItems: "center",
13
+ gap: 8,
14
+ padding: "0 12px",
15
+ fontFamily: MONO,
16
+ fontSize: 8,
17
+ color: TEXT,
18
+ background: "transparent",
19
+ border: "none",
20
+ cursor: "pointer",
21
+ textAlign: "left",
22
+ };
23
+ export const menuHeaderStyle = {
24
+ height: 22,
25
+ display: "flex",
26
+ alignItems: "center",
27
+ padding: "0 12px",
28
+ fontFamily: MONO,
29
+ fontSize: 6,
30
+ color: MUTED,
31
+ letterSpacing: "0.07em",
32
+ };
@@ -0,0 +1,26 @@
1
+ export { MainEditor } from "./MainEditor.js";
2
+ export type { MainEditorProps } from "./MainEditor.js";
3
+ export { TitleBar } from "./TitleBar.js";
4
+ export type { TitleBarProps } from "./TitleBar.js";
5
+ export { CommentsPane } from "./CommentsPane.js";
6
+ export type { CommentsPaneProps } from "./CommentsPane.js";
7
+ export { BlockStack } from "./blocks/BlockStack.js";
8
+ export type { BlockStackProps } from "./blocks/BlockStack.js";
9
+ export { NarrativeBlockView } from "./blocks/NarrativeBlockView.js";
10
+ export type { NarrativeBlockViewProps } from "./blocks/NarrativeBlockView.js";
11
+ export { AssessmentBlockView } from "./blocks/AssessmentBlockView.js";
12
+ export type { AssessmentBlockViewProps } from "./blocks/AssessmentBlockView.js";
13
+ export { GeovisionEmbedView } from "./blocks/GeovisionEmbedView.js";
14
+ export type { GeovisionEmbedViewProps } from "./blocks/GeovisionEmbedView.js";
15
+ export { EvidenceTableView } from "./blocks/EvidenceTableView.js";
16
+ export type { EvidenceTableViewProps } from "./blocks/EvidenceTableView.js";
17
+ export { NativeTableView } from "./blocks/NativeTableView.js";
18
+ export type { NativeTableViewProps } from "./blocks/NativeTableView.js";
19
+ export { SelectionToolbar } from "./blocks/SelectionToolbar.js";
20
+ export type { SelectionToolbarProps } from "./blocks/SelectionToolbar.js";
21
+ export { en, zhCN, locales, stringsForLocale, formatMessage } from "./locales/index.js";
22
+ export type { MainEditorLocale, MainEditorStrings } from "./locales/index.js";
23
+ export type { MainEditorBlock, MainEditorBlockKind, MainEditorDossier, MainEditorCommentThread, MainEditorFocusedBlock, MainEditorInsertBlockRequest, MainEditorReorderBlockRequest, MainEditorDuplicateBlockRequest, MainEditorCommentRequest, MainEditorOpenViewRequest, MainEditorRemoveBlockRequest, MainEditorShareRequest, NarrativeBlock, NarrativeSpan, AssessmentBlock, GeovisionEmbedBlock, EvidenceTableBlock, NativeTableBlock, CommentThreadComment, DossierDoc, DossierDocBlock, } from "./types.js";
24
+ export type { GeovisionMapEngine, GeovisionViewDescriptor } from "@zephytiju/prism-geovision-embed-block";
25
+ export type { EvidenceAuditRef, EvidenceColumn, EvidenceSavedView, EvidenceTableRow, } from "@zephytiju/prism-evidence-table";
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,YAAY,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,YAAY,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,YAAY,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,YAAY,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,YAAY,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,YAAY,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxF,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,EAC5B,6BAA6B,EAC7B,+BAA+B,EAC/B,wBAAwB,EACxB,yBAAyB,EACzB,4BAA4B,EAC5B,sBAAsB,EACtB,cAAc,EACd,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,EACV,eAAe,GAChB,MAAM,YAAY,CAAC;AAIpB,YAAY,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AAC1G,YAAY,EACV,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,iCAAiC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ export { MainEditor } from "./MainEditor.js";
2
+ export { TitleBar } from "./TitleBar.js";
3
+ export { CommentsPane } from "./CommentsPane.js";
4
+ export { BlockStack } from "./blocks/BlockStack.js";
5
+ export { NarrativeBlockView } from "./blocks/NarrativeBlockView.js";
6
+ export { AssessmentBlockView } from "./blocks/AssessmentBlockView.js";
7
+ export { GeovisionEmbedView } from "./blocks/GeovisionEmbedView.js";
8
+ export { EvidenceTableView } from "./blocks/EvidenceTableView.js";
9
+ export { NativeTableView } from "./blocks/NativeTableView.js";
10
+ export { SelectionToolbar } from "./blocks/SelectionToolbar.js";
11
+ export { en, zhCN, locales, stringsForLocale, formatMessage } from "./locales/index.js";
@@ -0,0 +1,37 @@
1
+ {
2
+ "main-editor": {
3
+ "docPrefix": "DOSSIER",
4
+ "autosavedAt": "AUTOSAVED {time}",
5
+ "commentsButton": "COMMENTS",
6
+ "commentsButtonWithCount": "COMMENTS · {count}",
7
+ "openCommentsCount": "{count} OPEN COMMENTS",
8
+ "share": "SHARE",
9
+ "overflowTitle": "More dossier actions",
10
+ "blocksCount": "{count} BLOCKS",
11
+ "insertMenuTitle": "INSERT BLOCK",
12
+ "dragMenuTitle": "BLOCK ACTIONS",
13
+ "commentOnBlock": "Add comment on this block",
14
+ "moveUp": "MOVE UP",
15
+ "moveDown": "MOVE DOWN",
16
+ "duplicateBlock": "DUPLICATE",
17
+ "removeBlock": "REMOVE BLOCK",
18
+ "boldTitle": "Bold",
19
+ "italicTitle": "Italic",
20
+ "underlineTitle": "Underline",
21
+ "strikethroughTitle": "Strikethrough",
22
+ "commentOnSelection": "Comment on selection",
23
+ "kindNarrative": "NARRATIVE",
24
+ "kindAssessment": "ANALYST JUDGMENT",
25
+ "kindGeovision": "GEOVISION 3D",
26
+ "kindEvidenceTable": "EVIDENCE TABLE",
27
+ "kindNativeTable": "NATIVE TABLE",
28
+ "commentsTitle": "COMMENTS",
29
+ "commentsSubtitle": "BLOCK-ANCHORED · IN-EDITOR PANE",
30
+ "openThreads": "{count} OPEN",
31
+ "threadBlockMeta": "BLOCK {block} • {status}",
32
+ "statusOpen": "OPEN",
33
+ "statusDone": "DONE",
34
+ "emptyTitle": "No dossier open",
35
+ "emptyHint": "The editor renders once dossier data is published on the main-editor channels."
36
+ }
37
+ }
@@ -0,0 +1,105 @@
1
+ import enBundle from "./en.json";
2
+ /**
3
+ * Locales the main-editor micro-UI bundles. Every component-fixed UI string
4
+ * is resolved from these bundles (statically imported, resolveJsonModule); the
5
+ * component never hardcodes copy. Configuration-provided strings (breadcrumb
6
+ * segments, the doc meta line, block content, …) stay composition-authored
7
+ * and are localized by the composer.
8
+ */
9
+ export type MainEditorLocale = "en" | "zh-CN";
10
+ /**
11
+ * The per-locale string table — the keys of the en bundle. Declared widened
12
+ * (string values) so the zh-CN bundle is checked for exact key parity at
13
+ * compile time while keeping literal JSON types out of the public surface.
14
+ */
15
+ export type MainEditorStrings = {
16
+ readonly [K in keyof typeof enBundle["main-editor"]]: string;
17
+ };
18
+ /** Parsed en locale bundle (namespaced under the component id "main-editor"). */
19
+ export declare const en: {
20
+ "main-editor": {
21
+ docPrefix: string;
22
+ autosavedAt: string;
23
+ commentsButton: string;
24
+ commentsButtonWithCount: string;
25
+ openCommentsCount: string;
26
+ share: string;
27
+ overflowTitle: string;
28
+ blocksCount: string;
29
+ insertMenuTitle: string;
30
+ dragMenuTitle: string;
31
+ commentOnBlock: string;
32
+ moveUp: string;
33
+ moveDown: string;
34
+ duplicateBlock: string;
35
+ removeBlock: string;
36
+ boldTitle: string;
37
+ italicTitle: string;
38
+ underlineTitle: string;
39
+ strikethroughTitle: string;
40
+ commentOnSelection: string;
41
+ kindNarrative: string;
42
+ kindAssessment: string;
43
+ kindGeovision: string;
44
+ kindEvidenceTable: string;
45
+ kindNativeTable: string;
46
+ commentsTitle: string;
47
+ commentsSubtitle: string;
48
+ openThreads: string;
49
+ threadBlockMeta: string;
50
+ statusOpen: string;
51
+ statusDone: string;
52
+ emptyTitle: string;
53
+ emptyHint: string;
54
+ };
55
+ };
56
+ /** Parsed zh-CN locale bundle (namespaced under the component id "main-editor"). */
57
+ export declare const zhCN: {
58
+ "main-editor": {
59
+ docPrefix: string;
60
+ autosavedAt: string;
61
+ commentsButton: string;
62
+ commentsButtonWithCount: string;
63
+ openCommentsCount: string;
64
+ share: string;
65
+ overflowTitle: string;
66
+ blocksCount: string;
67
+ insertMenuTitle: string;
68
+ dragMenuTitle: string;
69
+ commentOnBlock: string;
70
+ moveUp: string;
71
+ moveDown: string;
72
+ duplicateBlock: string;
73
+ removeBlock: string;
74
+ boldTitle: string;
75
+ italicTitle: string;
76
+ underlineTitle: string;
77
+ strikethroughTitle: string;
78
+ commentOnSelection: string;
79
+ kindNarrative: string;
80
+ kindAssessment: string;
81
+ kindGeovision: string;
82
+ kindEvidenceTable: string;
83
+ kindNativeTable: string;
84
+ commentsTitle: string;
85
+ commentsSubtitle: string;
86
+ openThreads: string;
87
+ threadBlockMeta: string;
88
+ statusOpen: string;
89
+ statusDone: string;
90
+ emptyTitle: string;
91
+ emptyHint: string;
92
+ };
93
+ };
94
+ /** All bundled locale bundles keyed by locale id — for downstream deep-merge. */
95
+ export declare const locales: Record<MainEditorLocale, {
96
+ readonly "main-editor": MainEditorStrings;
97
+ }>;
98
+ /** Resolves the string table for a locale. */
99
+ export declare function stringsForLocale(locale: MainEditorLocale): MainEditorStrings;
100
+ /**
101
+ * Simple `{placeholder}` interpolation (e.g. `"{count} BLOCKS"` + count).
102
+ * Placeholder-for-value substitution only — no ICU, no regexes.
103
+ */
104
+ export declare function formatMessage(template: string, values: Readonly<Record<string, string | number>>): string;
105
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/locales/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,WAAW,CAAC;AAGjC;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAAC;AAE9C;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,CAAC,IAAI,MAAM,OAAO,QAAQ,CAAC,aAAa,CAAC,GAAG,MAAM;CAC7D,CAAC;AAOF,iFAAiF;AACjF,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAW,CAAC;AAE3B,oFAAoF;AACpF,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAa,CAAC;AAE/B,iFAAiF;AACjF,eAAO,MAAM,OAAO;4BAZ8C,iBAAiB;EAYrD,CAAC;AAE/B,8CAA8C;AAC9C,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB,CAE5E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,GAChD,MAAM,CAMR"}
@@ -0,0 +1,27 @@
1
+ import enBundle from "./en.json";
2
+ import zhCNBundle from "./zh-CN.json";
3
+ const bundles = {
4
+ en: enBundle,
5
+ "zh-CN": zhCNBundle,
6
+ };
7
+ /** Parsed en locale bundle (namespaced under the component id "main-editor"). */
8
+ export const en = enBundle;
9
+ /** Parsed zh-CN locale bundle (namespaced under the component id "main-editor"). */
10
+ export const zhCN = zhCNBundle;
11
+ /** All bundled locale bundles keyed by locale id — for downstream deep-merge. */
12
+ export const locales = bundles;
13
+ /** Resolves the string table for a locale. */
14
+ export function stringsForLocale(locale) {
15
+ return bundles[locale]["main-editor"];
16
+ }
17
+ /**
18
+ * Simple `{placeholder}` interpolation (e.g. `"{count} BLOCKS"` + count).
19
+ * Placeholder-for-value substitution only — no ICU, no regexes.
20
+ */
21
+ export function formatMessage(template, values) {
22
+ let result = template;
23
+ for (const [key, value] of Object.entries(values)) {
24
+ result = result.replaceAll(`{${key}}`, String(value));
25
+ }
26
+ return result;
27
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "main-editor": {
3
+ "docPrefix": "卷宗",
4
+ "autosavedAt": "已自动保存 {time}",
5
+ "commentsButton": "评论",
6
+ "commentsButtonWithCount": "评论 · {count}",
7
+ "openCommentsCount": "{count} 条未决评论",
8
+ "share": "共享",
9
+ "overflowTitle": "更多卷宗操作",
10
+ "blocksCount": "{count} 个区块",
11
+ "insertMenuTitle": "插入区块",
12
+ "dragMenuTitle": "区块操作",
13
+ "commentOnBlock": "对此区块添加评论",
14
+ "moveUp": "上移",
15
+ "moveDown": "下移",
16
+ "duplicateBlock": "复制区块",
17
+ "removeBlock": "移除区块",
18
+ "boldTitle": "加粗",
19
+ "italicTitle": "斜体",
20
+ "underlineTitle": "下划线",
21
+ "strikethroughTitle": "删除线",
22
+ "commentOnSelection": "对选中文字添加评论",
23
+ "kindNarrative": "叙述",
24
+ "kindAssessment": "分析判断",
25
+ "kindGeovision": "GEOVISION 3D",
26
+ "kindEvidenceTable": "证据表",
27
+ "kindNativeTable": "原生表格",
28
+ "commentsTitle": "评论",
29
+ "commentsSubtitle": "区块锚定 · 编辑器内面板",
30
+ "openThreads": "{count} 条未决",
31
+ "threadBlockMeta": "区块 {block} • {status}",
32
+ "statusOpen": "未决",
33
+ "statusDone": "已完成",
34
+ "emptyTitle": "未打开卷宗",
35
+ "emptyHint": "当卷宗数据发布到 main-editor 通道后,编辑器将开始渲染。"
36
+ }
37
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Shared semantic-token CSS-variable shorthands. NO component color is ever
3
+ * hardcoded: every color resolves to a semantic Mantine token (ok / threat /
4
+ * warn / signal / accent / card / card-dark / input / border / line / text /
5
+ * muted / deep / panel) supplied by the host's MantineProvider. Translucent
6
+ * surfaces (the amber highlight tint, the comments-pane backdrop) derive from
7
+ * the same tokens through color-mix — still token-only.
8
+ */
9
+ export declare const MONO = "var(--mantine-font-family-monospace)";
10
+ export declare const TEXT = "var(--mantine-color-text-filled)";
11
+ export declare const MUTED = "var(--mantine-color-muted-filled)";
12
+ export declare const CARD = "var(--mantine-color-card-filled)";
13
+ export declare const CARD_DARK = "var(--mantine-color-card-dark-filled)";
14
+ export declare const INPUT_BG = "var(--mantine-color-input-filled)";
15
+ export declare const BORDER = "var(--mantine-color-border-filled)";
16
+ export declare const LINE = "var(--mantine-color-line-filled)";
17
+ export declare const DEEP = "var(--mantine-color-deep-filled)";
18
+ export declare const PANEL = "var(--mantine-color-panel-filled)";
19
+ export declare const OK = "var(--mantine-color-ok-filled)";
20
+ export declare const ACCENT = "var(--mantine-color-accent-filled)";
21
+ export declare const THREAT = "var(--mantine-color-threat-filled)";
22
+ export declare const WARN = "var(--mantine-color-warn-filled)";
23
+ export declare const SIGNAL = "var(--mantine-color-signal-filled)";
24
+ /** The analyst-judgment highlight tint (D10): accent bar + tint only. */
25
+ export declare const HIGHLIGHT_TINT = "color-mix(in srgb, var(--mantine-color-warn-filled) 10%, transparent)";
26
+ /** The comments-pane backdrop: card-dark at 94% over the editor body. */
27
+ export declare const PANE_BACKDROP = "color-mix(in srgb, var(--mantine-color-card-dark-filled) 94%, transparent)";
28
+ /** Focused-block wash (interaction state, not an outlining box). */
29
+ export declare const FOCUS_WASH = "color-mix(in srgb, var(--mantine-color-accent-filled) 8%, transparent)";
30
+ /**
31
+ * Selection-comment highlight (D11): the quoted range a selection-anchored
32
+ * thread covers renders with the accent token at 32% — the v10 prototype's
33
+ * rgba(98,179,255,.32) as a token-only color-mix.
34
+ */
35
+ export declare const SELECTED_TINT = "color-mix(in srgb, var(--mantine-color-accent-filled) 32%, transparent)";
36
+ /** Popover/menu elevation shadow (menus, popovers, floating toolbars). */
37
+ export declare const POPOVER_SHADOW = "0 8px 24px rgba(0,0,0,.55)";
38
+ /** `{token}`-to-CSS-variable helper for per-block semantic colors. */
39
+ export declare function tokenColor(token: string): string;
40
+ /** Zero-pads block ordinals (BLOCK 01…). */
41
+ export declare const pad2: (value: number) => string;
42
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI,yCAAyC,CAAC;AAE3D,eAAO,MAAM,IAAI,qCAAqC,CAAC;AACvD,eAAO,MAAM,KAAK,sCAAsC,CAAC;AACzD,eAAO,MAAM,IAAI,qCAAqC,CAAC;AACvD,eAAO,MAAM,SAAS,0CAA0C,CAAC;AACjE,eAAO,MAAM,QAAQ,sCAAsC,CAAC;AAC5D,eAAO,MAAM,MAAM,uCAAuC,CAAC;AAC3D,eAAO,MAAM,IAAI,qCAAqC,CAAC;AACvD,eAAO,MAAM,IAAI,qCAAqC,CAAC;AACvD,eAAO,MAAM,KAAK,sCAAsC,CAAC;AAEzD,eAAO,MAAM,EAAE,mCAAmC,CAAC;AACnD,eAAO,MAAM,MAAM,uCAAuC,CAAC;AAC3D,eAAO,MAAM,MAAM,uCAAuC,CAAC;AAC3D,eAAO,MAAM,IAAI,qCAAqC,CAAC;AACvD,eAAO,MAAM,MAAM,uCAAuC,CAAC;AAE3D,yEAAyE;AACzE,eAAO,MAAM,cAAc,0EAA0E,CAAC;AAEtG,yEAAyE;AACzE,eAAO,MAAM,aAAa,+EAA+E,CAAC;AAE1G,oEAAoE;AACpE,eAAO,MAAM,UAAU,2EAA2E,CAAC;AAEnG;;;;GAIG;AACH,eAAO,MAAM,aAAa,4EAA4E,CAAC;AAEvG,0EAA0E;AAC1E,eAAO,MAAM,cAAc,+BAA+B,CAAC;AAE3D,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,4CAA4C;AAC5C,eAAO,MAAM,IAAI,GAAI,OAAO,MAAM,KAAG,MAA4D,CAAC"}
package/dist/tokens.js ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Shared semantic-token CSS-variable shorthands. NO component color is ever
3
+ * hardcoded: every color resolves to a semantic Mantine token (ok / threat /
4
+ * warn / signal / accent / card / card-dark / input / border / line / text /
5
+ * muted / deep / panel) supplied by the host's MantineProvider. Translucent
6
+ * surfaces (the amber highlight tint, the comments-pane backdrop) derive from
7
+ * the same tokens through color-mix — still token-only.
8
+ */
9
+ export const MONO = "var(--mantine-font-family-monospace)";
10
+ export const TEXT = "var(--mantine-color-text-filled)";
11
+ export const MUTED = "var(--mantine-color-muted-filled)";
12
+ export const CARD = "var(--mantine-color-card-filled)";
13
+ export const CARD_DARK = "var(--mantine-color-card-dark-filled)";
14
+ export const INPUT_BG = "var(--mantine-color-input-filled)";
15
+ export const BORDER = "var(--mantine-color-border-filled)";
16
+ export const LINE = "var(--mantine-color-line-filled)";
17
+ export const DEEP = "var(--mantine-color-deep-filled)";
18
+ export const PANEL = "var(--mantine-color-panel-filled)";
19
+ export const OK = "var(--mantine-color-ok-filled)";
20
+ export const ACCENT = "var(--mantine-color-accent-filled)";
21
+ export const THREAT = "var(--mantine-color-threat-filled)";
22
+ export const WARN = "var(--mantine-color-warn-filled)";
23
+ export const SIGNAL = "var(--mantine-color-signal-filled)";
24
+ /** The analyst-judgment highlight tint (D10): accent bar + tint only. */
25
+ export const HIGHLIGHT_TINT = "color-mix(in srgb, var(--mantine-color-warn-filled) 10%, transparent)";
26
+ /** The comments-pane backdrop: card-dark at 94% over the editor body. */
27
+ export const PANE_BACKDROP = "color-mix(in srgb, var(--mantine-color-card-dark-filled) 94%, transparent)";
28
+ /** Focused-block wash (interaction state, not an outlining box). */
29
+ export const FOCUS_WASH = "color-mix(in srgb, var(--mantine-color-accent-filled) 8%, transparent)";
30
+ /**
31
+ * Selection-comment highlight (D11): the quoted range a selection-anchored
32
+ * thread covers renders with the accent token at 32% — the v10 prototype's
33
+ * rgba(98,179,255,.32) as a token-only color-mix.
34
+ */
35
+ export const SELECTED_TINT = "color-mix(in srgb, var(--mantine-color-accent-filled) 32%, transparent)";
36
+ /** Popover/menu elevation shadow (menus, popovers, floating toolbars). */
37
+ export const POPOVER_SHADOW = "0 8px 24px rgba(0,0,0,.55)";
38
+ /** `{token}`-to-CSS-variable helper for per-block semantic colors. */
39
+ export function tokenColor(token) {
40
+ return `var(--mantine-color-${token}-filled)`;
41
+ }
42
+ /** Zero-pads block ordinals (BLOCK 01…). */
43
+ export const pad2 = (value) => (value < 10 ? `0${String(value)}` : String(value));