@hwp-editor/react 1.0.0-rc.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/LICENSE +21 -0
- package/README.md +129 -0
- package/dist/index.cjs +1778 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +392 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +471 -0
- package/dist/index.d.ts +471 -0
- package/dist/index.js +1737 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { CSSProperties, JSX } from 'react';
|
|
3
|
+
import { HwpEngine, DocumentHandle, CatEnvelope, Segment, SegmentRef, DocumentSpecV2, EditorStore, EditorState, Capabilities, ValidationReport } from '@hwp-editor/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The editor's string table: one flat `<area>.<thing>` key map per locale,
|
|
7
|
+
* plus the `t()` factory that merges them.
|
|
8
|
+
*
|
|
9
|
+
* Contract (published API at 1.0.0 — a key rename is a breaking change):
|
|
10
|
+
*
|
|
11
|
+
* - `en` is canonical and is the default when no `locale` is given. It is
|
|
12
|
+
* declared WITHOUT `as const` so its values widen to `string` / function
|
|
13
|
+
* signatures; `const ko: MessageTable` then makes a key missing from
|
|
14
|
+
* EITHER table a `tsc` error (a missing key is a required-property error,
|
|
15
|
+
* an extra key an excess-property one). That two-way parity is the whole
|
|
16
|
+
* reason for the `typeof en` spelling — a plain `Record<..., string>`
|
|
17
|
+
* would widen every value to the union and lose per-key parameter types.
|
|
18
|
+
* - Count-bearing messages are FUNCTION values taking a single named-params
|
|
19
|
+
* object, never positional args and never a runtime `{count}` template.
|
|
20
|
+
* Interpolation happens inside the function body, so word order is a
|
|
21
|
+
* per-locale choice and English can carry a real plural branch.
|
|
22
|
+
* - Merge order is `en` -> locale table -> host `messages`. An override
|
|
23
|
+
* replaces exactly one key; every other key falls through to the locale
|
|
24
|
+
* default. Lookup is exact string equality with no normalization.
|
|
25
|
+
*
|
|
26
|
+
* NOT in this table, deliberately (I18N-05): font names, preset profiles,
|
|
27
|
+
* the `#FF0000` placeholder sample, and the engine's `{message}` error tail.
|
|
28
|
+
* Those are document data or engine-authored prose — translating them would
|
|
29
|
+
* change what hwp-cli receives or rewrite what the engine actually said.
|
|
30
|
+
*/
|
|
31
|
+
declare const en: {
|
|
32
|
+
"toolbar.toolsAria": string;
|
|
33
|
+
"toolbar.readOnly": string;
|
|
34
|
+
"toolbar.pendingEdits": (p: {
|
|
35
|
+
count: number;
|
|
36
|
+
}) => string;
|
|
37
|
+
"toolbar.revert": string;
|
|
38
|
+
"toolbar.apply": string;
|
|
39
|
+
"toolbar.applyWithCount": (p: {
|
|
40
|
+
count: number;
|
|
41
|
+
}) => string;
|
|
42
|
+
"toolbar.applying": string;
|
|
43
|
+
"toolbar.newDocument": string;
|
|
44
|
+
"validation.aria": string;
|
|
45
|
+
"validation.valid": string;
|
|
46
|
+
"validation.errors": (p: {
|
|
47
|
+
count: number;
|
|
48
|
+
}) => string;
|
|
49
|
+
"canvas.aria": string;
|
|
50
|
+
"canvas.empty": string;
|
|
51
|
+
"canvas.createCta": string;
|
|
52
|
+
"canvas.emptyPages": string;
|
|
53
|
+
"page.label": (p: {
|
|
54
|
+
page: number;
|
|
55
|
+
}) => string;
|
|
56
|
+
"side.panelAria": string;
|
|
57
|
+
"tabs.para": string;
|
|
58
|
+
"tabs.table": string;
|
|
59
|
+
"tabs.fields": string;
|
|
60
|
+
"error.prefix.load": string;
|
|
61
|
+
"error.prefix.apply": string;
|
|
62
|
+
"error.prefix.compose": string;
|
|
63
|
+
"error.kind.timeout": string;
|
|
64
|
+
"error.kind.unavailable": string;
|
|
65
|
+
"error.kind.protected": string;
|
|
66
|
+
"error.kind.generic": string;
|
|
67
|
+
"compose.title": string;
|
|
68
|
+
"compose.docType": string;
|
|
69
|
+
"compose.docTypeAria": string;
|
|
70
|
+
"compose.titleLabel": string;
|
|
71
|
+
"compose.titlePlaceholder": string;
|
|
72
|
+
"compose.authorLabel": string;
|
|
73
|
+
"compose.authorPlaceholder": string;
|
|
74
|
+
"compose.bodyLabel": string;
|
|
75
|
+
"compose.bodyPlaceholder": string;
|
|
76
|
+
"compose.cancel": string;
|
|
77
|
+
"compose.submit": string;
|
|
78
|
+
"compose.submitting": string;
|
|
79
|
+
/** Filename stem used when the compose form has no title. */
|
|
80
|
+
"compose.defaultFileStem": string;
|
|
81
|
+
"presets.official": string;
|
|
82
|
+
"presets.report": string;
|
|
83
|
+
"presets.plan": string;
|
|
84
|
+
"presets.notice": string;
|
|
85
|
+
"presets.minutes": string;
|
|
86
|
+
"presets.gaejosik": string;
|
|
87
|
+
"presets.press": string;
|
|
88
|
+
"segment.panelAria": string;
|
|
89
|
+
"segment.hint": string;
|
|
90
|
+
"segment.selectedPara": (p: {
|
|
91
|
+
section: number;
|
|
92
|
+
para: number;
|
|
93
|
+
}) => string;
|
|
94
|
+
"segment.emptyPara": string;
|
|
95
|
+
"segment.replaceLabel": string;
|
|
96
|
+
"segment.replacePlaceholder": string;
|
|
97
|
+
"segment.replaceSubmit": string;
|
|
98
|
+
"segment.insertLabel": string;
|
|
99
|
+
"segment.insertPlaceholder": string;
|
|
100
|
+
"segment.insertBefore": string;
|
|
101
|
+
"segment.insertAfter": string;
|
|
102
|
+
"segment.deletePara": string;
|
|
103
|
+
"segment.alignLabel": string;
|
|
104
|
+
"segment.alignGroupAria": string;
|
|
105
|
+
"segment.alignLeft": string;
|
|
106
|
+
"segment.alignCenter": string;
|
|
107
|
+
"segment.alignRight": string;
|
|
108
|
+
"segment.alignJustify": string;
|
|
109
|
+
"segment.formatLabel": string;
|
|
110
|
+
"segment.bold": string;
|
|
111
|
+
"segment.sizePlaceholder": string;
|
|
112
|
+
"segment.sizeAria": string;
|
|
113
|
+
"segment.colorAria": string;
|
|
114
|
+
"segment.formatSubmit": string;
|
|
115
|
+
"table.panelAria": string;
|
|
116
|
+
"table.hint": string;
|
|
117
|
+
"table.tableLabel": (p: {
|
|
118
|
+
index: number;
|
|
119
|
+
}) => string;
|
|
120
|
+
"table.cellLabel": (p: {
|
|
121
|
+
row: number;
|
|
122
|
+
col: number;
|
|
123
|
+
}) => string;
|
|
124
|
+
"table.setCell": string;
|
|
125
|
+
"table.mergeAnchor": string;
|
|
126
|
+
"table.mergeWithAnchor": string;
|
|
127
|
+
"table.splitCell": string;
|
|
128
|
+
"table.rowsCols": string;
|
|
129
|
+
"table.addRow": string;
|
|
130
|
+
"table.addCol": string;
|
|
131
|
+
"table.deleteRow": string;
|
|
132
|
+
"table.deleteCol": string;
|
|
133
|
+
"table.deleteTable": string;
|
|
134
|
+
"fields.panelAria": string;
|
|
135
|
+
"fields.hint": string;
|
|
136
|
+
"fields.valuePlaceholder": string;
|
|
137
|
+
"fields.fieldValueAria": (p: {
|
|
138
|
+
name: string;
|
|
139
|
+
}) => string;
|
|
140
|
+
"fields.setValue": string;
|
|
141
|
+
};
|
|
142
|
+
/** The shape both locale tables must satisfy, derived from canonical `en`. */
|
|
143
|
+
type MessageTable = typeof en;
|
|
144
|
+
/** Every valid `t()` key. */
|
|
145
|
+
type MessageKey = keyof MessageTable;
|
|
146
|
+
/** Host-supplied per-key overrides; unknown keys are a `tsc` error. */
|
|
147
|
+
type HwpEditorMessages = Partial<MessageTable>;
|
|
148
|
+
/** Supported UI locales. Mount-time only — runtime switching is not supported. */
|
|
149
|
+
type Locale = "en" | "ko";
|
|
150
|
+
/**
|
|
151
|
+
* Korean chrome. These are the literals that already shipped, carried over
|
|
152
|
+
* VERBATIM (including the `...` in-progress convention, where English uses
|
|
153
|
+
* a single `…`) — they are correct and the existing suite pins them.
|
|
154
|
+
*/
|
|
155
|
+
declare const ko: MessageTable;
|
|
156
|
+
/**
|
|
157
|
+
* Lookup function. Keys with a function value REQUIRE their params object;
|
|
158
|
+
* plain-string keys accept no second argument — both enforced per key by
|
|
159
|
+
* the conditional variadic below, so a missing or wrong params object is a
|
|
160
|
+
* compile error at the call site.
|
|
161
|
+
*/
|
|
162
|
+
type TFunction = <K extends MessageKey>(key: K, ...args: MessageTable[K] extends (p: infer P) => string ? [params: P] : []) => string;
|
|
163
|
+
/**
|
|
164
|
+
* Build a `t()` bound to one locale and one set of host overrides.
|
|
165
|
+
* Merge order: `en` -> locale table -> `messages` (last wins, per key).
|
|
166
|
+
*/
|
|
167
|
+
declare function createT(locale: Locale, messages?: HwpEditorMessages): TFunction;
|
|
168
|
+
|
|
169
|
+
interface HwpEditorProps {
|
|
170
|
+
/** Engine implementation (HTTP client, local adapter, mock in tests). */
|
|
171
|
+
engine: HwpEngine;
|
|
172
|
+
/** Document to open; null shows the empty state with the new-doc entry. */
|
|
173
|
+
file: DocumentHandle | null;
|
|
174
|
+
/**
|
|
175
|
+
* UI language for the editor chrome. Defaults to `"en"`. Read at mount and
|
|
176
|
+
* on change; also drives the root `lang` attribute. Document content and
|
|
177
|
+
* engine-authored error prose are never translated.
|
|
178
|
+
*/
|
|
179
|
+
locale?: Locale;
|
|
180
|
+
/**
|
|
181
|
+
* Per-key overrides applied on top of the locale table. A key not listed
|
|
182
|
+
* keeps its locale default; unknown keys are a compile error.
|
|
183
|
+
*/
|
|
184
|
+
messages?: HwpEditorMessages;
|
|
185
|
+
/**
|
|
186
|
+
* Force the editor read-only regardless of what the engine reports. A UI
|
|
187
|
+
* affordance, NOT an authorization boundary: a host that must actually
|
|
188
|
+
* prevent writes enforces that server-side (see the server package's
|
|
189
|
+
* `authorize` hook). Wins over an editable engine; never re-enables a
|
|
190
|
+
* document the engine reports as protected.
|
|
191
|
+
*/
|
|
192
|
+
readOnly?: boolean;
|
|
193
|
+
/**
|
|
194
|
+
* Called once per completed document load, after both the read and the
|
|
195
|
+
* render resolve, with the document that was loaded. Fires again on every
|
|
196
|
+
* `file` change; never fires for `file={null}` or a load cancelled by
|
|
197
|
+
* unmount.
|
|
198
|
+
*/
|
|
199
|
+
onReady?: (document: DocumentHandle) => void;
|
|
200
|
+
/**
|
|
201
|
+
* Called for every engine failure — load, apply, undo, refresh, and
|
|
202
|
+
* compose — with the caught value verbatim, so a host can branch on the
|
|
203
|
+
* stable `code` of a `HwpEngineError`. The inline alert renders either
|
|
204
|
+
* way; this is an addition to it, not a replacement.
|
|
205
|
+
*/
|
|
206
|
+
onError?: (error: unknown) => void;
|
|
207
|
+
/** Called whenever the document bytes change (applied edit, undo, compose). */
|
|
208
|
+
onChange?: (document: DocumentHandle) => void;
|
|
209
|
+
/** Called when the dirty flag (pending ops queued) changes. */
|
|
210
|
+
onDirtyChange?: (dirty: boolean) => void;
|
|
211
|
+
className?: string;
|
|
212
|
+
style?: CSSProperties;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Imperative surface a host reaches through `ref`. Exactly four methods at
|
|
216
|
+
* 1.0.0 and no state getters: hosts observe state through `onChange` /
|
|
217
|
+
* `onDirtyChange` / `onReady` / `onError`, which stay in sync with React
|
|
218
|
+
* rendering in a way a getter read from outside the render cycle cannot.
|
|
219
|
+
*/
|
|
220
|
+
interface HwpEditorHandle {
|
|
221
|
+
/**
|
|
222
|
+
* Apply the queued edit ops. Resolves without touching the engine when the
|
|
223
|
+
* queue is empty, no document is loaded, an apply is already in flight, or
|
|
224
|
+
* the editor is read-only.
|
|
225
|
+
*/
|
|
226
|
+
apply(): Promise<void>;
|
|
227
|
+
/**
|
|
228
|
+
* Undo the last applied edit. Resolves without touching the engine when the
|
|
229
|
+
* snapshot stack is empty.
|
|
230
|
+
*/
|
|
231
|
+
revert(): Promise<void>;
|
|
232
|
+
/**
|
|
233
|
+
* Re-read and re-render the current document after an external change.
|
|
234
|
+
* Rejects if the engine fails (after firing `onError` and showing the alert).
|
|
235
|
+
*/
|
|
236
|
+
refresh(): Promise<void>;
|
|
237
|
+
/** Open the new-document compose dialog. */
|
|
238
|
+
openCompose(): void;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Top-level embeddable editor. Layout: toolbar (apply/revert/validation
|
|
242
|
+
* badge/pending-ops count/protected notice) | PageCanvas | side panel
|
|
243
|
+
* (SegmentInspector / TableGrid / FieldsPanel tabs). The new-document entry
|
|
244
|
+
* point opens ComposePanel.
|
|
245
|
+
*/
|
|
246
|
+
declare const HwpEditor: react.ForwardRefExoticComponent<HwpEditorProps & react.RefAttributes<HwpEditorHandle>>;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Multi-page scroll of rendered pages. SVG pages render inline (sanitized);
|
|
250
|
+
* raster formats fall back to <img>. Clicks resolve to the nearest segment
|
|
251
|
+
* (see geometry.ts for the flow-model approximation), and selected/pending
|
|
252
|
+
* segments are highlighted with overlay bands.
|
|
253
|
+
*/
|
|
254
|
+
declare function PageCanvas(): JSX.Element;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Inspector for a selected paragraph segment: current text plus op builders
|
|
258
|
+
* (replace, insert before/after, delete, alignment, minimal char-format).
|
|
259
|
+
* All controls queue EditOps; nothing touches the engine until Apply.
|
|
260
|
+
*/
|
|
261
|
+
declare function SegmentInspector(): JSX.Element;
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Table-aware editor for a selected table segment. The cell grid comes from
|
|
265
|
+
* the GFM table in the read() envelope; addressing follows the CLI's
|
|
266
|
+
* 0-based "table:row:col" grammar (row 0 = header row).
|
|
267
|
+
*/
|
|
268
|
+
declare function TableGrid(): JSX.Element;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Lists `{{field}}` placeholder slots found in the read() envelope, with
|
|
272
|
+
* set-field editing and jump-to-segment on click. (The engine contract has
|
|
273
|
+
* no native field/bookmark listing; see fields.ts.)
|
|
274
|
+
*/
|
|
275
|
+
declare function FieldsPanel(): JSX.Element;
|
|
276
|
+
|
|
277
|
+
interface ComposePanelProps {
|
|
278
|
+
/** Called with the composed document once engine.compose() succeeds. */
|
|
279
|
+
onComposed: (document: DocumentHandle) => void;
|
|
280
|
+
/** Close without composing. */
|
|
281
|
+
onClose: () => void;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* New-document flow: preset picker + guided form (title, author,
|
|
285
|
+
* markdown-ish sections) → DocumentSpec v2 → engine.compose().
|
|
286
|
+
*/
|
|
287
|
+
declare function ComposePanel(props: ComposePanelProps): JSX.Element;
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Minimal SVG sanitizer for inline rendering of `hwp render --format svg`
|
|
291
|
+
* output. The CLI output is trusted, but hosts embedding arbitrary documents
|
|
292
|
+
* get script/foreignObject/event-handler removal for free.
|
|
293
|
+
*
|
|
294
|
+
* Returns "" when the payload does not parse as XML.
|
|
295
|
+
*/
|
|
296
|
+
declare function sanitizeSvg(svgText: string): string;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Plain-text extraction for segment markdown slices.
|
|
300
|
+
*
|
|
301
|
+
* `hwp edit` find/anchor arguments match against the document's paragraph
|
|
302
|
+
* text, not the markdown rendering of it — so markers like `#`, `**`, and
|
|
303
|
+
* link syntax must be stripped before a segment's text is used as an op
|
|
304
|
+
* target. This is intentionally conservative: anything unrecognized is kept
|
|
305
|
+
* verbatim (a longer anchor is still a valid anchor).
|
|
306
|
+
*/
|
|
307
|
+
declare function plainSegmentText(markdownSlice: string): string;
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Click hit-testing and highlight placement for PageCanvas.
|
|
311
|
+
*
|
|
312
|
+
* Neither the core segment envelope nor the hwp-cli SVG renderer carries
|
|
313
|
+
* per-paragraph page geometry, so positions are estimated with a linear
|
|
314
|
+
* text-flow model: paragraphs flow in document order across pages
|
|
315
|
+
* proportionally to their markdown length. Clicks map to a global flow
|
|
316
|
+
* fraction, then to the nearest segment via the core coordinate helpers;
|
|
317
|
+
* highlight bands use the exact inverse mapping, so the visual highlight
|
|
318
|
+
* always agrees with what a click would select.
|
|
319
|
+
*/
|
|
320
|
+
|
|
321
|
+
/** Resolve a page click to the nearest segment. */
|
|
322
|
+
declare function nearestSegment(envelope: CatEnvelope, pageIndex: number, yFraction: number, pageCount: number): Segment | undefined;
|
|
323
|
+
/** Global markdown offset for a click, in flow order. */
|
|
324
|
+
declare function clickOffset(envelope: CatEnvelope, pageIndex: number, yFraction: number, pageCount: number): number;
|
|
325
|
+
interface SegmentBand {
|
|
326
|
+
/** 0-based page index the band is drawn on. */
|
|
327
|
+
pageIndex: number;
|
|
328
|
+
/** Band top as a percentage of page height. */
|
|
329
|
+
top: number;
|
|
330
|
+
/** Band height as a percentage of page height. */
|
|
331
|
+
height: number;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Estimated overlay band for a segment — the inverse of {@link clickOffset},
|
|
335
|
+
* so bands and click hit-testing stay consistent.
|
|
336
|
+
*/
|
|
337
|
+
declare function segmentBand(envelope: CatEnvelope, segment: Segment, pageCount: number): SegmentBand | null;
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* GFM table extraction from the `hwp cat --with-segments` envelope.
|
|
341
|
+
*
|
|
342
|
+
* The CLI emits one para segment per table, covering the whole markdown
|
|
343
|
+
* table block. Table indices are 0-based in document order, matching the
|
|
344
|
+
* `hwp edit --set-cell "table:row:col=value"` coordinate grammar; within a
|
|
345
|
+
* table, row 0 is the header row and the `---` separator row is skipped.
|
|
346
|
+
*/
|
|
347
|
+
|
|
348
|
+
interface TableModel {
|
|
349
|
+
/** 0-based table index in document order (the CLI's `table` coordinate). */
|
|
350
|
+
tableIndex: number;
|
|
351
|
+
/** Segment covering the table block. */
|
|
352
|
+
segment: Segment;
|
|
353
|
+
/**
|
|
354
|
+
* Cell grid. Row 0 is the header row; the markdown separator row is not
|
|
355
|
+
* included. Merged cells cannot be represented in markdown, so spans are
|
|
356
|
+
* flattened to their anchor cell text.
|
|
357
|
+
*/
|
|
358
|
+
rows: string[][];
|
|
359
|
+
}
|
|
360
|
+
/** True when a segment's markdown slice is a GFM table block. */
|
|
361
|
+
declare function isTableSlice(slice: string): boolean;
|
|
362
|
+
/** Parse a GFM table slice into a cell grid; null when not a table. */
|
|
363
|
+
declare function parseMarkdownTable(slice: string): string[][] | null;
|
|
364
|
+
/** All tables in the envelope, in document order. */
|
|
365
|
+
declare function findTables(envelope: CatEnvelope): TableModel[];
|
|
366
|
+
/** The table whose segment sits at the given source coordinate, if any. */
|
|
367
|
+
declare function tableAtRef(envelope: CatEnvelope, ref: SegmentRef): TableModel | undefined;
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Field-slot extraction from the read() envelope.
|
|
371
|
+
*
|
|
372
|
+
* The engine contract exposes no field/bookmark registry (that would need
|
|
373
|
+
* `hwp fields` / `hwp bookmarks`), so the fields panel works with template
|
|
374
|
+
* placeholder slots — `{{name}}` markers in the markdown — which map
|
|
375
|
+
* directly onto `hwp edit --set-field "name=value"`.
|
|
376
|
+
*/
|
|
377
|
+
|
|
378
|
+
interface FieldSlot {
|
|
379
|
+
/** Placeholder name as written between the braces. */
|
|
380
|
+
name: string;
|
|
381
|
+
/** Segment containing the placeholder. */
|
|
382
|
+
segment: SegmentRef;
|
|
383
|
+
}
|
|
384
|
+
/** All `{{name}}` placeholder slots in the envelope, in document order. */
|
|
385
|
+
declare function extractFieldSlots(envelope: CatEnvelope): FieldSlot[];
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Compose-panel presets → DocumentSpec v2.
|
|
389
|
+
*
|
|
390
|
+
* Profile values mirror hwp-cli's official presets
|
|
391
|
+
* (crates/hwp-convert/src/official.rs): body font, size (1/100 pt there,
|
|
392
|
+
* plain pt here), line spacing percent, and page-number footer policy.
|
|
393
|
+
*/
|
|
394
|
+
|
|
395
|
+
type ComposePreset = "official" | "report" | "plan" | "notice" | "minutes" | "gaejosik" | "press";
|
|
396
|
+
declare const COMPOSE_PRESETS: ComposePreset[];
|
|
397
|
+
interface ComposeInput {
|
|
398
|
+
title: string;
|
|
399
|
+
author: string;
|
|
400
|
+
/**
|
|
401
|
+
* Markdown-ish body: blank lines separate paragraphs; a line starting
|
|
402
|
+
* with "# " becomes a heading-styled paragraph.
|
|
403
|
+
*/
|
|
404
|
+
body: string;
|
|
405
|
+
}
|
|
406
|
+
type ParagraphBlock = {
|
|
407
|
+
type: "paragraph";
|
|
408
|
+
style?: string;
|
|
409
|
+
runs: [{
|
|
410
|
+
type: "text";
|
|
411
|
+
text: string;
|
|
412
|
+
}];
|
|
413
|
+
};
|
|
414
|
+
/** Parse the guided-form body text into paragraph blocks. */
|
|
415
|
+
declare function bodyToBlocks(body: string): ParagraphBlock[];
|
|
416
|
+
/** Build the DocumentSpec v2 for a preset + guided form input. */
|
|
417
|
+
declare function buildDocumentSpec(preset: ComposePreset, input: ComposeInput): DocumentSpecV2;
|
|
418
|
+
|
|
419
|
+
interface HwpEditorContextValue {
|
|
420
|
+
engine: HwpEngine;
|
|
421
|
+
store: EditorStore;
|
|
422
|
+
/** Current store snapshot (from useSyncExternalStore). */
|
|
423
|
+
state: EditorState;
|
|
424
|
+
/** Last read() envelope for the current document; null before load. */
|
|
425
|
+
envelope: CatEnvelope | null;
|
|
426
|
+
capabilities: Capabilities | null;
|
|
427
|
+
/** False for protected/distribution documents: editing UI is disabled. */
|
|
428
|
+
editable: boolean;
|
|
429
|
+
validation: ValidationReport | null;
|
|
430
|
+
/** Queue of pending ops length convenience. */
|
|
431
|
+
applyPendingOps: () => void;
|
|
432
|
+
/** Re-read + re-render the current document after an external change. */
|
|
433
|
+
refresh: () => Promise<void>;
|
|
434
|
+
/** Open the compose panel (new-document flow). */
|
|
435
|
+
openCompose: () => void;
|
|
436
|
+
/**
|
|
437
|
+
* Message lookup bound to the active locale and host overrides. Every
|
|
438
|
+
* panel localizes through this one channel; a panel that cannot reach `t`
|
|
439
|
+
* cannot be localized at all.
|
|
440
|
+
*/
|
|
441
|
+
t: TFunction;
|
|
442
|
+
/**
|
|
443
|
+
* Host error callback, passed straight through from `HwpEditorProps`. A
|
|
444
|
+
* panel that owns its own error state (ComposePanel) has no other way to
|
|
445
|
+
* reach the host; the caught value travels verbatim.
|
|
446
|
+
*/
|
|
447
|
+
onError?: ((error: unknown) => void) | undefined;
|
|
448
|
+
}
|
|
449
|
+
declare function useHwpEditorContext(): HwpEditorContextValue;
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Engine error classification for distinct UI states, mapping a failure
|
|
453
|
+
* onto the four states the editor renders distinctly.
|
|
454
|
+
*
|
|
455
|
+
* The stable `HwpErrorCode` carried by `HwpEngineError` (@hwp-editor/core)
|
|
456
|
+
* is the preferred input: `engineErrorKind` consults it first and never
|
|
457
|
+
* reads the prose when it is present. Substring matching over the message
|
|
458
|
+
* is the documented FALLBACK for failures that carry no code — a pre-1.0
|
|
459
|
+
* server, or a maru/Tauri rejection that surfaces only a prefixed string
|
|
460
|
+
* ("hwped_read failed: cli_missing: ..."). The markers below are pinned by
|
|
461
|
+
* those engines; `classifyEngineError` stays exported for that path.
|
|
462
|
+
*
|
|
463
|
+
* This module classifies only. The human-readable badge LABELS live in the
|
|
464
|
+
* string table (`error.kind.*` in messages.ts) and are resolved by
|
|
465
|
+
* ErrorLine; nothing here renders text.
|
|
466
|
+
*/
|
|
467
|
+
|
|
468
|
+
type EngineErrorKind = "timeout" | "unavailable" | "protected" | "generic";
|
|
469
|
+
declare function classifyEngineError(message: string): EngineErrorKind;
|
|
470
|
+
|
|
471
|
+
export { COMPOSE_PRESETS, type ComposeInput, ComposePanel, type ComposePanelProps, type ComposePreset, type EngineErrorKind, type FieldSlot, FieldsPanel, HwpEditor, type HwpEditorContextValue, type HwpEditorHandle, type HwpEditorMessages, type HwpEditorProps, type Locale, type MessageKey, type MessageTable, PageCanvas, type SegmentBand, SegmentInspector, type TFunction, TableGrid, type TableModel, bodyToBlocks, buildDocumentSpec, classifyEngineError, clickOffset, createT, en, extractFieldSlots, findTables, isTableSlice, ko, nearestSegment, parseMarkdownTable, plainSegmentText, sanitizeSvg, segmentBand, tableAtRef, useHwpEditorContext };
|