@hwp-editor/react 1.1.0 → 1.2.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/HwpEditor.tsx","../src/context.ts","../src/PageCanvas.tsx","../src/geometry.ts","../src/sanitize.ts","../src/text.ts","../src/SegmentInspector.tsx","../src/TableGrid.tsx","../src/tables.ts","../src/FieldsPanel.tsx","../src/fields.ts","../src/ComposePanel.tsx","../src/errors.ts","../src/ErrorLine.tsx","../src/presets.ts","../src/messages.ts"],"sourcesContent":["/**\n * @hwp-editor/react — embeddable React UI for HWP/HWPX documents.\n *\n * Styles are NOT auto-injected; hosts must import the extracted stylesheet:\n * import \"@hwp-editor/react/style.css\";\n * Theming is CSS-variable only (see theme.css / README for the contract).\n */\n\nimport \"./theme.css\";\nimport \"./editor.css\";\n\nexport { HwpEditor } from \"./HwpEditor.js\";\nexport type { HwpEditorHandle, HwpEditorProps } from \"./HwpEditor.js\";\nexport { PageCanvas } from \"./PageCanvas.js\";\nexport { SegmentInspector } from \"./SegmentInspector.js\";\nexport { TableGrid } from \"./TableGrid.js\";\nexport { FieldsPanel } from \"./FieldsPanel.js\";\nexport { ComposePanel } from \"./ComposePanel.js\";\nexport type { ComposePanelProps } from \"./ComposePanel.js\";\n\nexport { sanitizeSvg } from \"./sanitize.js\";\nexport { plainSegmentText } from \"./text.js\";\nexport { nearestSegment, segmentBand, clickOffset } from \"./geometry.js\";\nexport type { SegmentBand } from \"./geometry.js\";\nexport { findTables, tableAtRef, parseMarkdownTable, isTableSlice } from \"./tables.js\";\nexport type { TableModel } from \"./tables.js\";\nexport { extractFieldSlots } from \"./fields.js\";\nexport type { FieldSlot } from \"./fields.js\";\nexport { COMPOSE_PRESETS, buildDocumentSpec, bodyToBlocks } from \"./presets.js\";\nexport type { ComposePreset, ComposeInput } from \"./presets.js\";\nexport { useHwpEditorContext } from \"./context.js\";\nexport type { HwpEditorContextValue } from \"./context.js\";\nexport { classifyEngineError } from \"./errors.js\";\nexport type { EngineErrorKind } from \"./errors.js\";\n// The locale tables are public: a host writing `messages` overrides needs\n// them to discover which keys exist and what the defaults say.\nexport { en, ko, createT } from \"./messages.js\";\nexport type {\n MessageTable,\n MessageKey,\n HwpEditorMessages,\n Locale,\n TFunction,\n} from \"./messages.js\";\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport type { CSSProperties, JSX, KeyboardEvent } from \"react\";\nimport type {\n Capabilities,\n CatEnvelope,\n DocumentHandle,\n HwpEngine,\n ValidationReport,\n} from \"@hwp-editor/core\";\nimport { createStore, segmentAtRef } from \"@hwp-editor/core\";\nimport type { EditorError, EditorStore } from \"@hwp-editor/core\";\nimport { HwpEditorContext } from \"./context.js\";\nimport type { HwpEditorContextValue } from \"./context.js\";\nimport { PageCanvas } from \"./PageCanvas.js\";\nimport { SegmentInspector } from \"./SegmentInspector.js\";\nimport { TableGrid } from \"./TableGrid.js\";\nimport { FieldsPanel } from \"./FieldsPanel.js\";\nimport { ComposePanel } from \"./ComposePanel.js\";\nimport { isTableSlice } from \"./tables.js\";\nimport { ErrorLine } from \"./ErrorLine.js\";\nimport { toEditorError } from \"./errors.js\";\nimport { createT } from \"./messages.js\";\nimport type { HwpEditorMessages, Locale } from \"./messages.js\";\nimport { segmentText } from \"@hwp-editor/core\";\n\nexport interface HwpEditorProps {\n /** Engine implementation (HTTP client, local adapter, mock in tests). */\n engine: HwpEngine;\n /** Document to open; null shows the empty state with the new-doc entry. */\n file: DocumentHandle | null;\n /**\n * UI language for the editor chrome. Defaults to `\"en\"`. Read at mount and\n * on change; also drives the root `lang` attribute. Document content and\n * engine-authored error prose are never translated.\n */\n locale?: Locale;\n /**\n * Per-key overrides applied on top of the locale table. A key not listed\n * keeps its locale default; unknown keys are a compile error.\n */\n messages?: HwpEditorMessages;\n /**\n * Force the editor read-only regardless of what the engine reports. A UI\n * affordance, NOT an authorization boundary: a host that must actually\n * prevent writes enforces that server-side (see the server package's\n * `authorize` hook). Wins over an editable engine; never re-enables a\n * document the engine reports as protected.\n */\n readOnly?: boolean;\n /**\n * Called once per completed document load, after both the read and the\n * render resolve, with the document that was loaded. Fires again on every\n * `file` change; never fires for `file={null}` or a load cancelled by\n * unmount.\n */\n onReady?: (document: DocumentHandle) => void;\n /**\n * Called for every engine failure — load, apply, undo, refresh, and\n * compose — with the caught value verbatim, so a host can branch on the\n * stable `code` of a `HwpEngineError`. The inline alert renders either\n * way; this is an addition to it, not a replacement.\n */\n onError?: (error: unknown) => void;\n /** Called whenever the document bytes change (applied edit, undo, compose). */\n onChange?: (document: DocumentHandle) => void;\n /** Called when the dirty flag (pending ops queued) changes. */\n onDirtyChange?: (dirty: boolean) => void;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * Imperative surface a host reaches through `ref`. Exactly four methods at\n * 1.0.0 and no state getters: hosts observe state through `onChange` /\n * `onDirtyChange` / `onReady` / `onError`, which stay in sync with React\n * rendering in a way a getter read from outside the render cycle cannot.\n */\nexport interface HwpEditorHandle {\n /**\n * Apply the queued edit ops. Resolves without touching the engine when the\n * queue is empty, no document is loaded, an apply is already in flight, or\n * the editor is read-only.\n */\n apply(): Promise<void>;\n /**\n * Undo the last applied edit. Resolves without touching the engine when the\n * snapshot stack is empty.\n */\n revert(): Promise<void>;\n /**\n * Re-read and re-render the current document after an external change.\n * Rejects if the engine fails (after firing `onError` and showing the alert).\n */\n refresh(): Promise<void>;\n /** Open the new-document compose dialog. */\n openCompose(): void;\n}\n\ntype SideTab = \"para\" | \"table\" | \"fields\";\n\n/**\n * Every render goes straight to the engine. The former client-side\n * SVG-to-PNG catch-all turned a timeout, a missing binary, or a network\n * error into a second full CLI render and masked which one it was\n * (BUG-01). The one legitimate retry lives in the engine, gated on a real\n * format failure: CliEngine at cli-engine.ts:445-451 (`reason === \"failed\"`)\n * and maru at hwped.rs:485-486 (the `hwp_failed:` prefix).\n */\nconst RENDER_SVG = { format: \"svg\" } as const;\n\n/**\n * Top-level embeddable editor. Layout: toolbar (apply/revert/validation\n * badge/pending-ops count/protected notice) | PageCanvas | side panel\n * (SegmentInspector / TableGrid / FieldsPanel tabs). The new-document entry\n * point opens ComposePanel.\n */\nexport const HwpEditor = forwardRef<HwpEditorHandle, HwpEditorProps>(\n function HwpEditor(props, ref): JSX.Element {\n const {\n engine,\n file,\n locale = \"en\",\n messages,\n readOnly = false,\n onReady,\n onError,\n onChange,\n onDirtyChange,\n className,\n style,\n } = props;\n\n /**\n * Host callbacks are deliberately NON-REACTIVE. They live in this one\n * bundle ref and reach the component only through the stable dispatchers\n * below. Putting any of them back into a dependency array turns an\n * ordinary host re-render — the inline-arrow idiom every React host\n * writes — into a full engine round trip (capabilities + read + render +\n * validate) against the same document, which is worst on exactly the\n * multi-megabyte documents BUG-06's chunked codec was added to serve.\n */\n const cbRef = useRef({ onReady, onError, onChange, onDirtyChange });\n // No dependency array on purpose: this runs after EVERY render, so a\n // dispatcher fired later always reaches the host's latest identity rather\n // than a mount-time closure. Declared above the load effect because React\n // runs a component's effects in declaration order.\n useEffect(() => {\n cbRef.current = { onReady, onError, onChange, onDirtyChange };\n });\n\n // Forward-only dispatchers, stable for the component's lifetime. They\n // pass the argument by reference and return nothing: no wrapping, no\n // re-throwing, no synthesized code (03-CONTEXT D-09).\n const emitReady = useCallback((document: DocumentHandle): void => {\n cbRef.current.onReady?.(document);\n }, []);\n const emitError = useCallback((error: unknown): void => {\n cbRef.current.onError?.(error);\n }, []);\n const emitChange = useCallback((document: DocumentHandle): void => {\n cbRef.current.onChange?.(document);\n }, []);\n const emitDirty = useCallback((dirty: boolean): void => {\n cbRef.current.onDirtyChange?.(dirty);\n }, []);\n\n const t = useMemo(() => createT(locale, messages), [locale, messages]);\n\n const [store] = useState<EditorStore>(() => createStore());\n // getServerSnapshot is required for SSR hosts (Next.js); a fresh store's\n // state is always initialState server-side.\n const state = useSyncExternalStore(store.subscribe, store.getState, store.getState);\n\n const [envelope, setEnvelope] = useState<CatEnvelope | null>(null);\n const [capabilities, setCapabilities] = useState<Capabilities | null>(null);\n const [validation, setValidation] = useState<ValidationReport | null>(null);\n // `code` is deliberately optional: a host-supplied engine, a mock, or a\n // React-internal throw legitimately has none, and synthesizing `internal`\n // would be indistinguishable from a real `internal`.\n const [loadError, setLoadError] = useState<EditorError | null>(null);\n const [tab, setTab] = useState<SideTab>(\"para\");\n const [composing, setComposing] = useState(false);\n\n // Load the document whenever the engine/file pair changes.\n useEffect(() => {\n let cancelled = false;\n if (file === null) {\n setEnvelope(null);\n setValidation(null);\n setLoadError(null);\n return;\n }\n (async () => {\n try {\n const caps = await engine.capabilities();\n const [nextEnvelope, pages, report] = await Promise.all([\n engine.read(file),\n engine.render(file, RENDER_SVG),\n engine.validate(file).catch(() => null),\n ]);\n if (cancelled) return;\n setCapabilities(caps);\n setEnvelope(nextEnvelope);\n setValidation(report);\n setLoadError(null);\n store.dispatch({ type: \"load\", document: file, pages });\n // Once per completed load, from THIS effect only: a second effect\n // keyed on envelope/pages would re-fire after every apply and undo.\n emitReady(file);\n } catch (e) {\n if (cancelled) return;\n setLoadError(toEditorError(e));\n emitError(e);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [engine, file, store]);\n\n // Single fan-out point: every panel, both toolbar buttons and the\n // applyPendingOps guard read `editable`, so `readOnly` works everywhere\n // because it is applied here and nowhere else.\n const editable = !readOnly && (capabilities?.editable ?? true);\n\n // Follow selection to the relevant tab.\n useEffect(() => {\n if (envelope === null || state.selection === null) return;\n const segment = segmentAtRef(envelope, state.selection);\n if (segment === undefined) return;\n setTab(\n isTableSlice(segmentText(envelope, segment)) ? \"table\" : \"para\",\n );\n }, [envelope, state.selection]);\n\n // Dirty-change callback.\n const dirty = state.pendingOps.length > 0;\n useEffect(() => {\n emitDirty(dirty);\n }, [dirty]);\n\n const applyPendingOps = useCallback((): Promise<void> => {\n const snapshot = store.getState();\n if (\n snapshot.document === null ||\n snapshot.pendingOps.length === 0 ||\n snapshot.status === \"applying\" ||\n !editable\n ) {\n return Promise.resolve();\n }\n store.dispatch({ type: \"applyStarted\" });\n return (async () => {\n try {\n const next = await engine.edit(snapshot.document!, snapshot.pendingOps, {\n verify: true,\n });\n const [nextEnvelope, pages, report] = await Promise.all([\n engine.read(next),\n engine.render(next, RENDER_SVG),\n engine.validate(next).catch(() => null),\n ]);\n setEnvelope(nextEnvelope);\n setValidation(report);\n store.dispatch({ type: \"applySucceeded\", document: next, pages });\n emitChange(next);\n } catch (e) {\n store.dispatch({ type: \"applyFailed\", error: toEditorError(e) });\n emitError(e);\n }\n })();\n }, [editable, engine, store]);\n\n const revert = useCallback((): Promise<void> => {\n const snapshot = store.getState();\n const previous = snapshot.snapshots[snapshot.snapshots.length - 1];\n if (previous === undefined) return Promise.resolve();\n return (async () => {\n try {\n // BUG-02: the badge described the document being undone away, so\n // re-validate the restored one. Same shape as applyPendingOps; a\n // validate failure leaves the previous badge rather than clearing it.\n const [nextEnvelope, pages, report] = await Promise.all([\n engine.read(previous),\n engine.render(previous, RENDER_SVG),\n engine.validate(previous).catch(() => null),\n ]);\n // Dispatch only after the engine succeeds: popping the snapshot\n // first and failing mid-undo left the canvas showing the pre-undo\n // envelope while the store claimed the previous document. A second\n // revert may have consumed this snapshot while we awaited; if so,\n // leave the newer transition alone.\n const now = store.getState();\n if (now.snapshots[now.snapshots.length - 1] !== previous) return;\n store.dispatch({ type: \"undo\" });\n setEnvelope(nextEnvelope);\n if (report !== null) setValidation(report);\n store.dispatch({ type: \"setPages\", pages });\n emitChange(previous);\n } catch (e) {\n // The store was never touched, so store and canvas stay consistent;\n // without this destination the rejection was unhandled.\n setLoadError(toEditorError(e));\n emitError(e);\n }\n })();\n }, [engine, store]);\n\n const refresh = useCallback(async () => {\n const snapshot = store.getState();\n if (snapshot.document === null) return;\n try {\n const [nextEnvelope, pages, report] = await Promise.all([\n engine.read(snapshot.document),\n engine.render(snapshot.document, RENDER_SVG),\n engine.validate(snapshot.document).catch(() => null),\n ]);\n setEnvelope(nextEnvelope);\n setValidation(report);\n store.dispatch({ type: \"setPages\", pages });\n } catch (e) {\n // A no-op resolves quietly (above); a FAILURE must be observable to\n // the awaiting host, so surface it three ways and reject.\n setLoadError(toEditorError(e));\n emitError(e);\n throw e;\n }\n }, [engine, store]);\n\n const openCompose = useCallback(() => setComposing(true), []);\n\n useImperativeHandle(\n ref,\n () => ({ apply: applyPendingOps, revert, refresh, openCompose }),\n [applyPendingOps, revert, refresh, openCompose],\n );\n\n const contextValue: HwpEditorContextValue = useMemo(\n () => ({\n engine,\n store,\n state,\n envelope,\n capabilities,\n editable,\n validation,\n applyPendingOps,\n refresh,\n openCompose,\n t,\n // Always defined now, and stable: a widening, since every consumer\n // already calls it as `onError?.(e)` and it no-ops when the host\n // supplied no callback. The payload is unchanged.\n onError: emitError,\n }),\n [\n engine,\n store,\n state,\n envelope,\n capabilities,\n editable,\n validation,\n applyPendingOps,\n refresh,\n openCompose,\n t,\n ],\n );\n\n const onKeyDown = (e: KeyboardEvent<HTMLDivElement>): void => {\n if (e.key === \"Escape\") {\n store.dispatch({ type: \"select\", selection: null });\n } else if ((e.metaKey || e.ctrlKey) && e.key === \"Enter\") {\n e.preventDefault();\n void applyPendingOps();\n }\n };\n\n const rootClass =\n \"hwped hwped-root\" + (className !== undefined ? ` ${className}` : \"\");\n\n return (\n <HwpEditorContext.Provider value={contextValue}>\n <div\n className={rootClass}\n style={style}\n onKeyDown={onKeyDown}\n data-status={state.status}\n // No `dir`: both supported locales are ltr.\n lang={locale}\n >\n <header\n className=\"hwped-toolbar\"\n role=\"toolbar\"\n aria-label={t(\"toolbar.toolsAria\")}\n >\n <span className=\"hwped-title\">\n {state.document?.name ?? \"hwp-editor\"}\n </span>\n {!editable && (\n <span\n className=\"hwped-notice\"\n role=\"note\"\n // The full engine prose stays reachable on hover once the\n // toolbar clamp truncates a long reason (UI-DEBT-01).\n {...(capabilities?.reason !== undefined\n ? { title: capabilities.reason }\n : {})}\n >\n {t(\"toolbar.readOnly\")}\n {/* Suffix only when the ENGINE refused: a host-forced\n read-only has no reason, and inventing one would claim the\n document is protected when it isn't. The engine's reason is\n its own prose, shown verbatim under either locale. */}\n {capabilities?.editable === false &&\n (capabilities.reason !== undefined\n ? `: ${capabilities.reason}`\n : ` (${t(\"error.kind.protected\")})`)}\n </span>\n )}\n <span className=\"hwped-spacer\" />\n {validation !== null && (\n <span\n className={\n validation.valid\n ? \"hwped-badge hwped-badge-ok\"\n : \"hwped-badge hwped-badge-err\"\n }\n role=\"status\"\n aria-label={t(\"validation.aria\")}\n >\n {validation.valid\n ? t(\"validation.valid\")\n : t(\"validation.errors\", { count: validation.errors.length })}\n </span>\n )}\n <span\n className=\"hwped-count\"\n aria-label={t(\"toolbar.pendingEdits\", {\n count: state.pendingOps.length,\n })}\n >\n {t(\"toolbar.pendingEdits\", { count: state.pendingOps.length })}\n </span>\n <button\n type=\"button\"\n className=\"hwped-btn\"\n onClick={() => void revert()}\n disabled={state.snapshots.length === 0 || state.status === \"applying\"}\n >\n {t(\"toolbar.revert\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-primary\"\n onClick={() => void applyPendingOps()}\n disabled={!dirty || !editable || state.status === \"applying\"}\n >\n {state.status === \"applying\"\n ? t(\"toolbar.applying\")\n : t(\"toolbar.applyWithCount\", {\n count: state.pendingOps.length,\n })}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn\"\n onClick={() => setComposing(true)}\n >\n {t(\"toolbar.newDocument\")}\n </button>\n </header>\n\n {state.status === \"error\" && state.error !== null && (\n <ErrorLine prefix={t(\"error.prefix.apply\")} {...state.error} />\n )}\n {loadError !== null && (\n <ErrorLine prefix={t(\"error.prefix.load\")} {...loadError} />\n )}\n\n <div className=\"hwped-main\">\n {state.document === null ? (\n <div\n className=\"hwped-canvas\"\n role=\"main\"\n aria-label={t(\"canvas.aria\")}\n >\n <div className=\"hwped-empty\">\n <p>{t(\"canvas.empty\")}</p>\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-primary\"\n onClick={() => setComposing(true)}\n >\n {t(\"canvas.createCta\")}\n </button>\n </div>\n </div>\n ) : (\n <PageCanvas />\n )}\n <aside className=\"hwped-side\" aria-label={t(\"side.panelAria\")}>\n <div className=\"hwped-tabs\" role=\"tablist\">\n {(\n [\n [\"para\", t(\"tabs.para\")],\n [\"table\", t(\"tabs.table\")],\n [\"fields\", t(\"tabs.fields\")],\n ] as [SideTab, string][]\n ).map(([value, label]) => (\n <button\n key={value}\n type=\"button\"\n role=\"tab\"\n aria-selected={tab === value}\n className={\n \"hwped-tab\" + (tab === value ? \" hwped-tab-active\" : \"\")\n }\n onClick={() => setTab(value)}\n >\n {label}\n </button>\n ))}\n </div>\n {tab === \"para\" && <SegmentInspector />}\n {tab === \"table\" && <TableGrid />}\n {tab === \"fields\" && <FieldsPanel />}\n </aside>\n </div>\n\n {composing && (\n <ComposePanel\n onClose={() => setComposing(false)}\n onComposed={(document) => {\n setComposing(false);\n emitChange(document);\n // The host passes the composed document back via `file`; load\n // it directly so the flow also works when the host doesn't.\n void (async () => {\n try {\n const [nextEnvelope, pages] = await Promise.all([\n engine.read(document),\n engine.render(document, RENDER_SVG),\n ]);\n setEnvelope(nextEnvelope);\n store.dispatch({ type: \"load\", document, pages });\n } catch (e) {\n // Covers the render AFTER a successful compose; the\n // compose call itself fails inside ComposePanel.\n setLoadError(toEditorError(e));\n emitError(e);\n }\n })();\n }}\n />\n )}\n </div>\n </HwpEditorContext.Provider>\n );\n },\n);\n","/**\n * Internal React context shared by HwpEditor's panels.\n */\n\nimport { createContext, useContext } from \"react\";\nimport type {\n Capabilities,\n CatEnvelope,\n EditorState,\n EditorStore,\n HwpEngine,\n ValidationReport,\n} from \"@hwp-editor/core\";\nimport type { TFunction } from \"./messages.js\";\n\nexport interface HwpEditorContextValue {\n engine: HwpEngine;\n store: EditorStore;\n /** Current store snapshot (from useSyncExternalStore). */\n state: EditorState;\n /** Last read() envelope for the current document; null before load. */\n envelope: CatEnvelope | null;\n capabilities: Capabilities | null;\n /** False for protected/distribution documents: editing UI is disabled. */\n editable: boolean;\n validation: ValidationReport | null;\n /** Queue of pending ops length convenience. */\n applyPendingOps: () => void;\n /** Re-read + re-render the current document after an external change. */\n refresh: () => Promise<void>;\n /** Open the compose panel (new-document flow). */\n openCompose: () => void;\n /**\n * Message lookup bound to the active locale and host overrides. Every\n * panel localizes through this one channel; a panel that cannot reach `t`\n * cannot be localized at all.\n */\n t: TFunction;\n /**\n * Host error callback, passed straight through from `HwpEditorProps`. A\n * panel that owns its own error state (ComposePanel) has no other way to\n * reach the host; the caught value travels verbatim.\n */\n // `| undefined` is load-bearing under exactOptionalPropertyTypes: the\n // provider spreads the prop through whether or not the host passed one.\n onError?: ((error: unknown) => void) | undefined;\n}\n\nexport const HwpEditorContext = createContext<HwpEditorContextValue | null>(\n null,\n);\n\nexport function useHwpEditorContext(): HwpEditorContextValue {\n const value = useContext(HwpEditorContext);\n if (value === null) {\n throw new Error(\"hwp-editor panels must be rendered inside <HwpEditor>\");\n }\n return value;\n}\n","import { useMemo } from \"react\";\nimport type { JSX, MouseEvent } from \"react\";\nimport type { PageImage, Segment } from \"@hwp-editor/core\";\nimport { base64, segmentAtRef, segmentRef, segmentText } from \"@hwp-editor/core\";\nimport { nearestSegment, segmentBand } from \"./geometry.js\";\nimport { sanitizeSvg } from \"./sanitize.js\";\nimport { plainSegmentText } from \"./text.js\";\nimport { useHwpEditorContext } from \"./context.js\";\n\n/**\n * Multi-page scroll of rendered pages. SVG pages render inline (sanitized);\n * raster formats fall back to <img>. Clicks resolve to the nearest segment\n * (see geometry.ts for the flow-model approximation), and selected/pending\n * segments are highlighted with overlay bands.\n */\nexport function PageCanvas(): JSX.Element {\n const { state, store, envelope, t } = useHwpEditorContext();\n const { pages, selection, pendingOps } = state;\n\n // Segments covered by queued text-targeting ops, highlighted as pending.\n const pendingSegments = useMemo(() => {\n if (envelope === null) return new Set<string>();\n const keys = new Set<string>();\n for (const op of pendingOps) {\n const target = opSearchText(op);\n if (target === null || target === \"\") continue;\n for (const segment of envelope.segments) {\n const plain = plainSegmentText(segmentText(envelope, segment));\n if (plain.includes(target)) {\n keys.add(`${segment.section}:${segment.para}`);\n }\n }\n }\n return keys;\n }, [envelope, pendingOps]);\n\n const selectedSegment =\n envelope !== null && selection !== null\n ? segmentAtRef(envelope, selection)\n : undefined;\n\n if (pages.length === 0) {\n return (\n <div className=\"hwped-canvas\" role=\"main\" aria-label={t(\"canvas.aria\")}>\n <div className=\"hwped-empty\">{t(\"canvas.emptyPages\")}</div>\n </div>\n );\n }\n\n const selectAt = (pageIndex: number, yFraction: number): void => {\n if (envelope === null) return;\n const segment = nearestSegment(envelope, pageIndex, yFraction, pages.length);\n if (segment !== undefined) {\n store.dispatch({ type: \"select\", selection: segmentRef(segment) });\n }\n };\n\n return (\n <div className=\"hwped-canvas\" role=\"main\" aria-label={t(\"canvas.aria\")}>\n {pages.map((page, pageIndex) => (\n <PageView\n key={page.page}\n page={page}\n onClick={(e: MouseEvent<HTMLDivElement>) => {\n const rect = e.currentTarget.getBoundingClientRect();\n selectAt(\n pageIndex,\n rect.height > 0 ? (e.clientY - rect.top) / rect.height : 0.5,\n );\n }}\n onActivate={() => selectAt(pageIndex, 0.5)}\n bands={bandsForPage(\n envelope,\n pageIndex,\n pages.length,\n selectedSegment,\n pendingSegments,\n )}\n />\n ))}\n </div>\n );\n}\n\ninterface Band {\n key: string;\n className: string;\n top: number;\n height: number;\n}\n\nfunction bandsForPage(\n envelope: ReturnType<typeof useHwpEditorContext>[\"envelope\"],\n pageIndex: number,\n pageCount: number,\n selected: Segment | undefined,\n pendingKeys: Set<string>,\n): Band[] {\n if (envelope === null) return [];\n const bands: Band[] = [];\n for (const segment of envelope.segments) {\n const key = `${segment.section}:${segment.para}`;\n const isSelected = selected === segment;\n const isPending = !isSelected && pendingKeys.has(key);\n if (!isSelected && !isPending) continue;\n const band = segmentBand(envelope, segment, pageCount);\n if (band === null || band.pageIndex !== pageIndex) continue;\n bands.push({\n key: `${isSelected ? \"sel\" : \"pend\"}-${key}`,\n className: isSelected\n ? \"hwped-band hwped-band-selected\"\n : \"hwped-band hwped-band-pending\",\n top: band.top,\n height: band.height,\n });\n }\n return bands;\n}\n\nfunction PageView(props: {\n page: PageImage;\n onClick: (e: MouseEvent<HTMLDivElement>) => void;\n onActivate: () => void;\n bands: Band[];\n}): JSX.Element {\n const { page, onClick, onActivate, bands } = props;\n // PageView is only ever rendered inside <HwpEditor>, so it reaches `t`\n // through the context rather than threading a label prop down.\n const { t } = useHwpEditorContext();\n const label = t(\"page.label\", { page: page.page });\n const svgHtml = useMemo(\n () =>\n page.format === \"svg\"\n ? sanitizeSvg(new TextDecoder().decode(page.data))\n : null,\n [page],\n );\n const imgSrc = useMemo(() => {\n if (page.format === \"svg\") return null;\n const mime = page.format === \"jpeg\" ? \"image/jpeg\" : `image/${page.format}`;\n return `data:${mime};base64,${base64.encode(page.data)}`;\n }, [page]);\n\n return (\n <div\n className=\"hwped-page\"\n role=\"button\"\n tabIndex={0}\n aria-label={label}\n style={{ aspectRatio: `${page.width} / ${page.height}` }}\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onActivate();\n }\n }}\n >\n {svgHtml !== null ? (\n <div\n className=\"hwped-page-svg\"\n // Sanitized by sanitizeSvg: script/foreignObject/event handlers removed.\n dangerouslySetInnerHTML={{ __html: svgHtml }}\n />\n ) : (\n <img\n className=\"hwped-page-img\"\n src={imgSrc ?? \"\"}\n alt={label}\n width={page.width}\n height={page.height}\n />\n )}\n {bands.map((band) => (\n <div\n key={band.key}\n className={band.className}\n style={{ top: `${band.top}%`, height: `${band.height}%` }}\n />\n ))}\n </div>\n );\n}\n\n/** The free-text target of an op, when it has one (find/anchor/text). */\nfunction opSearchText(op: {\n kind: string;\n find?: string;\n anchor?: string;\n text?: string;\n}): string | null {\n if (\"find\" in op && typeof op.find === \"string\") return op.find;\n if (\"anchor\" in op && typeof op.anchor === \"string\") return op.anchor;\n if (op.kind === \"delete-para\" && typeof op.text === \"string\") return op.text;\n return null;\n}\n","/**\n * Click hit-testing and highlight placement for PageCanvas.\n *\n * Neither the core segment envelope nor the hwp-cli SVG renderer carries\n * per-paragraph page geometry, so positions are estimated with a linear\n * text-flow model: paragraphs flow in document order across pages\n * proportionally to their markdown length. Clicks map to a global flow\n * fraction, then to the nearest segment via the core coordinate helpers;\n * highlight bands use the exact inverse mapping, so the visual highlight\n * always agrees with what a click would select.\n */\n\nimport type { CatEnvelope, Segment } from \"@hwp-editor/core\";\nimport { segmentAtOffset } from \"@hwp-editor/core\";\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** Resolve a page click to the nearest segment. */\nexport function nearestSegment(\n envelope: CatEnvelope,\n pageIndex: number,\n yFraction: number,\n pageCount: number,\n): Segment | undefined {\n if (envelope.segments.length === 0) return undefined;\n const offset = clickOffset(envelope, pageIndex, yFraction, pageCount);\n const hit = segmentAtOffset(envelope, offset);\n if (hit !== undefined) return hit;\n // Between segments (blank spacing): pick the nearest by start offset.\n let best: Segment | undefined;\n let bestDistance = Number.POSITIVE_INFINITY;\n for (const segment of envelope.segments) {\n const distance = Math.abs(segment.start - offset);\n if (distance < bestDistance) {\n best = segment;\n bestDistance = distance;\n }\n }\n return best;\n}\n\n/** Global markdown offset for a click, in flow order. */\nexport function clickOffset(\n envelope: CatEnvelope,\n pageIndex: number,\n yFraction: number,\n pageCount: number,\n): number {\n const total = Math.max(pageCount, 1);\n const fraction = clamp(\n (clamp(pageIndex, 0, total - 1) + clamp(yFraction, 0, 1)) / total,\n 0,\n 1,\n );\n return Math.round(fraction * envelope.markdown.length);\n}\n\nexport interface SegmentBand {\n /** 0-based page index the band is drawn on. */\n pageIndex: number;\n /** Band top as a percentage of page height. */\n top: number;\n /** Band height as a percentage of page height. */\n height: number;\n}\n\n/**\n * Estimated overlay band for a segment — the inverse of {@link clickOffset},\n * so bands and click hit-testing stay consistent.\n */\nexport function segmentBand(\n envelope: CatEnvelope,\n segment: Segment,\n pageCount: number,\n): SegmentBand | null {\n const length = envelope.markdown.length;\n if (length === 0) return null;\n const total = Math.max(pageCount, 1);\n const center = (segment.start + segment.end) / 2;\n const position = (center / length) * total;\n const pageIndex = clamp(Math.floor(position), 0, total - 1);\n const height = clamp(((segment.end - segment.start) / length) * total * 100, 2, 100);\n const top = clamp((position - pageIndex) * 100 - height / 2, 0, 100 - height);\n return { pageIndex, top, height };\n}\n","/**\n * Minimal SVG sanitizer for inline rendering of `hwp render --format svg`\n * output. The CLI output is trusted, but hosts embedding arbitrary documents\n * get script/foreignObject/event-handler removal for free.\n *\n * Returns \"\" when the payload does not parse as XML.\n */\nexport function sanitizeSvg(svgText: string): string {\n const doc = new DOMParser().parseFromString(svgText, \"image/svg+xml\");\n const root = doc.documentElement;\n if (\n root === null ||\n root.nodeName === \"parsererror\" ||\n doc.getElementsByTagName(\"parsererror\").length > 0\n ) {\n return \"\";\n }\n const dangerous = root.querySelectorAll(\"script, foreignObject\");\n for (const node of Array.from(dangerous)) node.remove();\n scrubElement(root);\n return root.outerHTML;\n}\n\nfunction scrubElement(el: Element): void {\n for (const attr of Array.from(el.attributes)) {\n const name = attr.name.toLowerCase();\n const value = attr.value.trim().toLowerCase();\n if (name.startsWith(\"on\")) {\n el.removeAttribute(attr.name);\n } else if (\n (name === \"href\" || name === \"xlink:href\") &&\n value.startsWith(\"javascript:\")\n ) {\n el.removeAttribute(attr.name);\n }\n }\n for (const child of Array.from(el.children)) scrubElement(child);\n}\n","/**\n * Plain-text extraction for segment markdown slices.\n *\n * `hwp edit` find/anchor arguments match against the document's paragraph\n * text, not the markdown rendering of it — so markers like `#`, `**`, and\n * link syntax must be stripped before a segment's text is used as an op\n * target. This is intentionally conservative: anything unrecognized is kept\n * verbatim (a longer anchor is still a valid anchor).\n */\nexport function plainSegmentText(markdownSlice: string): string {\n return markdownSlice\n .split(\"\\n\")\n .map(stripLine)\n .join(\"\\n\")\n .trim();\n}\n\nfunction stripLine(line: string): string {\n let out = line.trimEnd();\n // ATX heading markers.\n out = out.replace(/^#{1,6}\\s+/, \"\");\n // Links and images: keep the visible label.\n out = out.replace(/!\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\");\n out = out.replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\");\n // Emphasis markers (strong first, then em).\n out = out.replace(/(\\*\\*|__)(.*?)\\1/g, \"$2\");\n out = out.replace(/(\\*|_)(.*?)\\1/g, \"$2\");\n // Inline code backticks.\n out = out.replace(/`([^`]*)`/g, \"$1\");\n return out;\n}\n","import { useEffect, useState } from \"react\";\nimport type { JSX } from \"react\";\nimport type { ParagraphAlignment } from \"@hwp-editor/core\";\nimport { segmentAtRef, segmentText } from \"@hwp-editor/core\";\nimport { plainSegmentText } from \"./text.js\";\nimport { useHwpEditorContext } from \"./context.js\";\nimport type { MessageKey } from \"./messages.js\";\n\n/**\n * Alignment buttons. The array stays at module scope but now carries message\n * KEYS instead of label literals, so the labels resolve through `t()` at\n * render time without reallocating the array on every render.\n */\nconst ALIGNMENTS: { value: ParagraphAlignment; key: MessageKey }[] = [\n { value: \"left\", key: \"segment.alignLeft\" },\n { value: \"center\", key: \"segment.alignCenter\" },\n { value: \"right\", key: \"segment.alignRight\" },\n { value: \"justify\", key: \"segment.alignJustify\" },\n];\n\n/**\n * Inspector for a selected paragraph segment: current text plus op builders\n * (replace, insert before/after, delete, alignment, minimal char-format).\n * All controls queue EditOps; nothing touches the engine until Apply.\n */\nexport function SegmentInspector(): JSX.Element {\n const { state, store, envelope, editable, t } = useHwpEditorContext();\n const { selection } = state;\n\n const segment =\n envelope !== null && selection !== null\n ? segmentAtRef(envelope, selection)\n : undefined;\n const currentText =\n envelope !== null && segment !== undefined\n ? plainSegmentText(segmentText(envelope, segment))\n : \"\";\n\n const [replaceWith, setReplaceWith] = useState(\"\");\n const [insertText, setInsertText] = useState(\"\");\n const [bold, setBold] = useState(false);\n const [fontSize, setFontSize] = useState(\"\");\n const [color, setColor] = useState(\"\");\n\n // Reset drafts when the selection moves.\n useEffect(() => {\n setReplaceWith(\"\");\n setInsertText(\"\");\n setBold(false);\n setFontSize(\"\");\n setColor(\"\");\n }, [selection]);\n\n if (segment === undefined || selection === null) {\n return (\n <div\n className=\"hwped-panel\"\n role=\"region\"\n aria-label={t(\"segment.panelAria\")}\n >\n <p className=\"hwped-hint\">{t(\"segment.hint\")}</p>\n </div>\n );\n }\n\n const find = currentText;\n const disabled = !editable;\n\n return (\n <div\n className=\"hwped-panel\"\n role=\"region\"\n aria-label={t(\"segment.panelAria\")}\n >\n <div className=\"hwped-field\">\n <span className=\"hwped-label\">\n {t(\"segment.selectedPara\", {\n section: selection.section,\n para: selection.para,\n })}\n </span>\n <div className=\"hwped-quote\">\n {currentText || t(\"segment.emptyPara\")}\n </div>\n </div>\n\n <div className=\"hwped-field\">\n <label className=\"hwped-label\" htmlFor=\"hwped-replace\">\n {t(\"segment.replaceLabel\")}\n </label>\n <div className=\"hwped-row\">\n <input\n id=\"hwped-replace\"\n className=\"hwped-input\"\n type=\"text\"\n value={replaceWith}\n disabled={disabled}\n onChange={(e) => setReplaceWith(e.target.value)}\n placeholder={t(\"segment.replacePlaceholder\")}\n />\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled || replaceWith === \"\" || find === \"\"}\n onClick={() =>\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"replace\", find, replace: replaceWith },\n })\n }\n >\n {t(\"segment.replaceSubmit\")}\n </button>\n </div>\n </div>\n\n <div className=\"hwped-field\">\n <label className=\"hwped-label\" htmlFor=\"hwped-insert\">\n {t(\"segment.insertLabel\")}\n </label>\n <textarea\n id=\"hwped-insert\"\n className=\"hwped-textarea\"\n value={insertText}\n disabled={disabled}\n onChange={(e) => setInsertText(e.target.value)}\n placeholder={t(\"segment.insertPlaceholder\")}\n rows={2}\n />\n <div className=\"hwped-row\">\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled || insertText === \"\" || find === \"\"}\n onClick={() =>\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"insert-para-before\", anchor: find, text: insertText },\n })\n }\n >\n {t(\"segment.insertBefore\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled || insertText === \"\" || find === \"\"}\n onClick={() =>\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"insert-para\", anchor: find, text: insertText },\n })\n }\n >\n {t(\"segment.insertAfter\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-danger\"\n disabled={disabled || find === \"\"}\n onClick={() =>\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"delete-para\", text: find },\n })\n }\n >\n {t(\"segment.deletePara\")}\n </button>\n </div>\n </div>\n\n <div className=\"hwped-field\">\n <span className=\"hwped-label\">{t(\"segment.alignLabel\")}</span>\n <div\n className=\"hwped-row\"\n role=\"group\"\n aria-label={t(\"segment.alignGroupAria\")}\n >\n {ALIGNMENTS.map((align) => (\n <button\n key={align.value}\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled || find === \"\"}\n onClick={() =>\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"set-align\", find, alignment: align.value },\n })\n }\n >\n {t(align.key)}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"hwped-field\">\n <span className=\"hwped-label\">{t(\"segment.formatLabel\")}</span>\n <div className=\"hwped-row\">\n <label className=\"hwped-check\">\n <input\n type=\"checkbox\"\n checked={bold}\n disabled={disabled}\n onChange={(e) => setBold(e.target.checked)}\n />\n {t(\"segment.bold\")}\n </label>\n <input\n className=\"hwped-input hwped-input-narrow\"\n type=\"number\"\n min={1}\n value={fontSize}\n disabled={disabled}\n onChange={(e) => setFontSize(e.target.value)}\n placeholder={t(\"segment.sizePlaceholder\")}\n aria-label={t(\"segment.sizeAria\")}\n />\n <input\n className=\"hwped-input hwped-input-narrow\"\n type=\"text\"\n value={color}\n disabled={disabled}\n onChange={(e) => setColor(e.target.value)}\n // A sample hex value, not chrome: never a message key (I18N-05).\n placeholder=\"#FF0000\"\n aria-label={t(\"segment.colorAria\")}\n />\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={\n disabled ||\n find === \"\" ||\n (!bold && fontSize === \"\" && color === \"\")\n }\n onClick={() => {\n const props: Record<string, string> = {};\n if (bold) props[\"bold\"] = \"on\";\n if (fontSize !== \"\") props[\"size\"] = fontSize;\n if (color !== \"\") props[\"color\"] = color;\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"set-format\", find, props },\n });\n }}\n >\n {t(\"segment.formatSubmit\")}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import { useEffect, useState } from \"react\";\nimport type { JSX } from \"react\";\nimport { tableAtRef } from \"./tables.js\";\nimport { plainSegmentText } from \"./text.js\";\nimport { useHwpEditorContext } from \"./context.js\";\n\ninterface CellCoord {\n row: number;\n col: number;\n}\n\n/**\n * Table-aware editor for a selected table segment. The cell grid comes from\n * the GFM table in the read() envelope; addressing follows the CLI's\n * 0-based \"table:row:col\" grammar (row 0 = header row).\n */\nexport function TableGrid(): JSX.Element {\n const { state, store, envelope, editable, t } = useHwpEditorContext();\n const { selection } = state;\n\n const table =\n envelope !== null && selection !== null\n ? tableAtRef(envelope, selection)\n : undefined;\n\n const [cell, setCell] = useState<CellCoord | null>(null);\n const [mergeAnchor, setMergeAnchor] = useState<CellCoord | null>(null);\n const [cellValue, setCellValue] = useState(\"\");\n\n useEffect(() => {\n setCell(null);\n setMergeAnchor(null);\n setCellValue(\"\");\n }, [selection]);\n\n if (table === undefined) {\n return (\n <div\n className=\"hwped-panel\"\n role=\"region\"\n aria-label={t(\"table.panelAria\")}\n >\n <p className=\"hwped-hint\">{t(\"table.hint\")}</p>\n </div>\n );\n }\n\n const disabled = !editable;\n const tableIndex = table.tableIndex;\n const queue = store.dispatch.bind(store);\n\n return (\n <div className=\"hwped-panel\" role=\"region\" aria-label={t(\"table.panelAria\")}>\n <div className=\"hwped-field\">\n <span className=\"hwped-label\">\n {t(\"table.tableLabel\", { index: tableIndex })}\n </span>\n <table className=\"hwped-grid\">\n <tbody>\n {table.rows.map((row, rowIndex) => (\n <tr key={rowIndex}>\n {row.map((text, colIndex) => {\n const active =\n cell !== null &&\n cell.row === rowIndex &&\n cell.col === colIndex;\n const anchor =\n mergeAnchor !== null &&\n mergeAnchor.row === rowIndex &&\n mergeAnchor.col === colIndex;\n return (\n <td key={colIndex}>\n <button\n type=\"button\"\n className={\n \"hwped-cell\" +\n (active ? \" hwped-cell-selected\" : \"\") +\n (anchor ? \" hwped-cell-anchor\" : \"\")\n }\n onClick={() => {\n setCell({ row: rowIndex, col: colIndex });\n setCellValue(plainSegmentText(text));\n }}\n >\n {plainSegmentText(text) || \" \"}\n </button>\n </td>\n );\n })}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n\n {cell !== null && (\n <div className=\"hwped-field\">\n <label className=\"hwped-label\" htmlFor=\"hwped-cell\">\n {t(\"table.cellLabel\", { row: cell.row, col: cell.col })}\n </label>\n <div className=\"hwped-row\">\n <input\n id=\"hwped-cell\"\n className=\"hwped-input\"\n type=\"text\"\n value={cellValue}\n disabled={disabled}\n onChange={(e) => setCellValue(e.target.value)}\n />\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled}\n onClick={() =>\n queue({\n type: \"queueOp\",\n op: {\n kind: \"set-cell\",\n table: tableIndex,\n row: cell.row,\n col: cell.col,\n value: cellValue,\n },\n })\n }\n >\n {t(\"table.setCell\")}\n </button>\n </div>\n <div className=\"hwped-row\">\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled}\n onClick={() => setMergeAnchor({ ...cell })}\n >\n {t(\"table.mergeAnchor\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={\n disabled ||\n mergeAnchor === null ||\n (mergeAnchor.row === cell.row && mergeAnchor.col === cell.col)\n }\n onClick={() => {\n if (mergeAnchor === null) return;\n queue({\n type: \"queueOp\",\n op: {\n kind: \"merge-cells\",\n table: tableIndex,\n r1: Math.min(mergeAnchor.row, cell.row),\n c1: Math.min(mergeAnchor.col, cell.col),\n r2: Math.max(mergeAnchor.row, cell.row),\n c2: Math.max(mergeAnchor.col, cell.col),\n },\n });\n setMergeAnchor(null);\n }}\n >\n {t(\"table.mergeWithAnchor\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled}\n onClick={() =>\n queue({\n type: \"queueOp\",\n op: {\n kind: \"split-cell\",\n table: tableIndex,\n row: cell.row,\n col: cell.col,\n },\n })\n }\n >\n {t(\"table.splitCell\")}\n </button>\n </div>\n </div>\n )}\n\n <div className=\"hwped-field\">\n <span className=\"hwped-label\">{t(\"table.rowsCols\")}</span>\n <div className=\"hwped-row\">\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled}\n onClick={() =>\n queue({\n type: \"queueOp\",\n op:\n cell === null\n ? { kind: \"add-row\", table: tableIndex }\n : { kind: \"add-row\", table: tableIndex, at: cell.row + 1 },\n })\n }\n >\n {t(\"table.addRow\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled}\n onClick={() =>\n queue({\n type: \"queueOp\",\n op:\n cell === null\n ? { kind: \"add-col\", table: tableIndex }\n : { kind: \"add-col\", table: tableIndex, at: cell.col + 1 },\n })\n }\n >\n {t(\"table.addCol\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-danger\"\n disabled={disabled || cell === null}\n onClick={() => {\n if (cell === null) return;\n queue({\n type: \"queueOp\",\n op: { kind: \"delete-row\", table: tableIndex, row: cell.row },\n });\n }}\n >\n {t(\"table.deleteRow\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-danger\"\n disabled={disabled || cell === null}\n onClick={() => {\n if (cell === null) return;\n queue({\n type: \"queueOp\",\n op: { kind: \"delete-col\", table: tableIndex, col: cell.col },\n });\n }}\n >\n {t(\"table.deleteCol\")}\n </button>\n </div>\n </div>\n\n <div className=\"hwped-field\">\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-danger\"\n disabled={disabled}\n onClick={() =>\n queue({\n type: \"queueOp\",\n op: { kind: \"delete-table\", target: tableIndex },\n })\n }\n >\n {t(\"table.deleteTable\")}\n </button>\n </div>\n </div>\n );\n}\n","/**\n * GFM table extraction from the `hwp cat --with-segments` envelope.\n *\n * The CLI emits one para segment per table, covering the whole markdown\n * table block. Table indices are 0-based in document order, matching the\n * `hwp edit --set-cell \"table:row:col=value\"` coordinate grammar; within a\n * table, row 0 is the header row and the `---` separator row is skipped.\n */\n\nimport type { CatEnvelope, Segment, SegmentRef } from \"@hwp-editor/core\";\nimport { segmentText } from \"@hwp-editor/core\";\n\nexport interface TableModel {\n /** 0-based table index in document order (the CLI's `table` coordinate). */\n tableIndex: number;\n /** Segment covering the table block. */\n segment: Segment;\n /**\n * Cell grid. Row 0 is the header row; the markdown separator row is not\n * included. Merged cells cannot be represented in markdown, so spans are\n * flattened to their anchor cell text.\n */\n rows: string[][];\n}\n\n/** True when a segment's markdown slice is a GFM table block. */\nexport function isTableSlice(slice: string): boolean {\n return parseMarkdownTable(slice) !== null;\n}\n\n/** Parse a GFM table slice into a cell grid; null when not a table. */\nexport function parseMarkdownTable(slice: string): string[][] | null {\n const lines = slice\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.startsWith(\"|\") && line.endsWith(\"|\"));\n if (lines.length < 2) return null;\n const rows: string[][] = [];\n let sawSeparator = false;\n for (const line of lines) {\n const cells = line\n .slice(1, -1)\n .split(\"|\")\n .map((cell) => cell.trim());\n if (cells.every((cell) => /^:?-{2,}:?$/.test(cell))) {\n sawSeparator = true;\n continue;\n }\n rows.push(cells);\n }\n return sawSeparator && rows.length > 0 ? rows : null;\n}\n\n/** All tables in the envelope, in document order. */\nexport function findTables(envelope: CatEnvelope): TableModel[] {\n const tables: TableModel[] = [];\n for (const segment of envelope.segments) {\n const rows = parseMarkdownTable(segmentText(envelope, segment));\n if (rows !== null) {\n tables.push({ tableIndex: tables.length, segment, rows });\n }\n }\n return tables;\n}\n\n/** The table whose segment sits at the given source coordinate, if any. */\nexport function tableAtRef(\n envelope: CatEnvelope,\n ref: SegmentRef,\n): TableModel | undefined {\n return findTables(envelope).find(\n (table) =>\n table.segment.section === ref.section && table.segment.para === ref.para,\n );\n}\n","import { useMemo, useState } from \"react\";\nimport type { JSX } from \"react\";\nimport { segmentAtRef, segmentText } from \"@hwp-editor/core\";\nimport { extractFieldSlots } from \"./fields.js\";\nimport { useHwpEditorContext } from \"./context.js\";\n\n/**\n * Lists `{{field}}` placeholder slots found in the read() envelope, with\n * set-field editing and jump-to-segment on click. (The engine contract has\n * no native field/bookmark listing; see fields.ts.)\n */\nexport function FieldsPanel(): JSX.Element {\n const { store, envelope, editable, t } = useHwpEditorContext();\n const [drafts, setDrafts] = useState<Record<string, string>>({});\n\n const slots = useMemo(\n () => (envelope === null ? [] : extractFieldSlots(envelope)),\n [envelope],\n );\n\n if (envelope === null || slots.length === 0) {\n return (\n <div\n className=\"hwped-panel\"\n role=\"region\"\n aria-label={t(\"fields.panelAria\")}\n >\n {/* The `{{name}}` / `{{이름}}` template marker lives inside the\n message value: it is per-locale copy, not a runtime param. */}\n <p className=\"hwped-hint\">{t(\"fields.hint\")}</p>\n </div>\n );\n }\n\n return (\n <div\n className=\"hwped-panel\"\n role=\"region\"\n aria-label={t(\"fields.panelAria\")}\n >\n <ul className=\"hwped-fields\">\n {slots.map((slot) => {\n const segment = segmentAtRef(envelope, slot.segment);\n const snippet =\n segment === undefined\n ? \"\"\n : segmentText(envelope, segment).trim().slice(0, 40);\n const draft = drafts[slot.name] ?? \"\";\n return (\n <li key={slot.name} className=\"hwped-field-item\">\n <div className=\"hwped-row\">\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-link\"\n title={snippet}\n onClick={() =>\n store.dispatch({ type: \"select\", selection: slot.segment })\n }\n >\n {slot.name}\n </button>\n </div>\n <div className=\"hwped-row\">\n <input\n className=\"hwped-input\"\n type=\"text\"\n value={draft}\n disabled={!editable}\n placeholder={t(\"fields.valuePlaceholder\")}\n aria-label={t(\"fields.fieldValueAria\", { name: slot.name })}\n onChange={(e) =>\n setDrafts((prev) => ({ ...prev, [slot.name]: e.target.value }))\n }\n />\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={!editable || draft === \"\"}\n onClick={() =>\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"set-field\", name: slot.name, value: draft },\n })\n }\n >\n {t(\"fields.setValue\")}\n </button>\n </div>\n </li>\n );\n })}\n </ul>\n </div>\n );\n}\n","/**\n * Field-slot extraction from the read() envelope.\n *\n * The engine contract exposes no field/bookmark registry (that would need\n * `hwp fields` / `hwp bookmarks`), so the fields panel works with template\n * placeholder slots — `{{name}}` markers in the markdown — which map\n * directly onto `hwp edit --set-field \"name=value\"`.\n */\n\nimport type { CatEnvelope, Segment, SegmentRef } from \"@hwp-editor/core\";\nimport { segmentAtOffset } from \"@hwp-editor/core\";\n\nexport interface FieldSlot {\n /** Placeholder name as written between the braces. */\n name: string;\n /** Segment containing the placeholder. */\n segment: SegmentRef;\n}\n\nconst SLOT_PATTERN = /\\{\\{\\s*([^{}]+?)\\s*\\}\\}/g;\n\n/** All `{{name}}` placeholder slots in the envelope, in document order. */\nexport function extractFieldSlots(envelope: CatEnvelope): FieldSlot[] {\n const slots: FieldSlot[] = [];\n const seen = new Set<string>();\n for (const match of envelope.markdown.matchAll(SLOT_PATTERN)) {\n const name = match[1] ?? \"\";\n const offset = match.index ?? 0;\n const segment: Segment | undefined = segmentAtOffset(envelope, offset);\n if (segment === undefined || seen.has(name)) continue;\n seen.add(name);\n slots.push({\n name,\n segment: { section: segment.section, para: segment.para },\n });\n }\n return slots;\n}\n","import { useState } from \"react\";\nimport type { JSX } from \"react\";\nimport type { DocumentHandle, EditorError } from \"@hwp-editor/core\";\nimport { ErrorLine } from \"./ErrorLine.js\";\nimport { toEditorError } from \"./errors.js\";\nimport { COMPOSE_PRESETS, buildDocumentSpec } from \"./presets.js\";\nimport type { ComposePreset } from \"./presets.js\";\nimport type { MessageKey } from \"./messages.js\";\nimport { useHwpEditorContext } from \"./context.js\";\n\n/**\n * Preset key -> message key. A typed total Record rather than a\n * template-literal cast: adding an eighth preset must fail `tsc --noEmit`\n * here and force a label decision, which a cast would hide. The preset\n * PROFILES stay in presets.ts as document data (I18N-05).\n */\nconst PRESET_LABEL_KEYS: Record<ComposePreset, MessageKey> = {\n official: \"presets.official\",\n report: \"presets.report\",\n plan: \"presets.plan\",\n notice: \"presets.notice\",\n minutes: \"presets.minutes\",\n gaejosik: \"presets.gaejosik\",\n press: \"presets.press\",\n};\n\nexport interface ComposePanelProps {\n /** Called with the composed document once engine.compose() succeeds. */\n onComposed: (document: DocumentHandle) => void;\n /** Close without composing. */\n onClose: () => void;\n}\n\n/**\n * New-document flow: preset picker + guided form (title, author,\n * markdown-ish sections) → DocumentSpec v2 → engine.compose().\n */\nexport function ComposePanel(props: ComposePanelProps): JSX.Element {\n const { engine, t, onError } = useHwpEditorContext();\n const [preset, setPreset] = useState<ComposePreset>(\"official\");\n const [title, setTitle] = useState(\"\");\n const [author, setAuthor] = useState(\"\");\n const [body, setBody] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<EditorError | null>(null);\n\n const compose = async (): Promise<void> => {\n setBusy(true);\n setError(null);\n try {\n const spec = buildDocumentSpec(preset, { title, author, body });\n const stem =\n title.trim() === \"\" ? t(\"compose.defaultFileStem\") : title.trim();\n const result = await engine.compose(spec, `${stem}.hwpx`);\n props.onComposed(result.document);\n } catch (e) {\n // Compose is one of the two operations that can refuse with\n // `protected`, so this surface needs the code as much as the editor's.\n setError(toEditorError(e));\n // This panel owns its own error state, so the context passthrough is\n // the only channel by which a compose failure reaches the host.\n onError?.(e);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <div className=\"hwped-overlay\" role=\"presentation\" onClick={props.onClose}>\n <div\n className=\"hwped-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={t(\"compose.title\")}\n onClick={(e) => e.stopPropagation()}\n >\n <h2 className=\"hwped-dialog-title\">{t(\"compose.title\")}</h2>\n\n <div className=\"hwped-field\">\n <span className=\"hwped-label\">{t(\"compose.docType\")}</span>\n <div\n className=\"hwped-presets\"\n role=\"radiogroup\"\n aria-label={t(\"compose.docTypeAria\")}\n >\n {COMPOSE_PRESETS.map((value) => (\n <button\n key={value}\n type=\"button\"\n role=\"radio\"\n aria-checked={preset === value}\n className={\n \"hwped-preset\" +\n (preset === value ? \" hwped-preset-active\" : \"\")\n }\n onClick={() => setPreset(value)}\n >\n {t(PRESET_LABEL_KEYS[value])}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"hwped-field\">\n <label className=\"hwped-label\" htmlFor=\"hwped-compose-title\">\n {t(\"compose.titleLabel\")}\n </label>\n <input\n id=\"hwped-compose-title\"\n className=\"hwped-input\"\n type=\"text\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder={t(\"compose.titlePlaceholder\")}\n />\n </div>\n\n <div className=\"hwped-field\">\n <label className=\"hwped-label\" htmlFor=\"hwped-compose-author\">\n {t(\"compose.authorLabel\")}\n </label>\n <input\n id=\"hwped-compose-author\"\n className=\"hwped-input\"\n type=\"text\"\n value={author}\n onChange={(e) => setAuthor(e.target.value)}\n placeholder={t(\"compose.authorPlaceholder\")}\n />\n </div>\n\n <div className=\"hwped-field\">\n <label className=\"hwped-label\" htmlFor=\"hwped-compose-body\">\n {t(\"compose.bodyLabel\")}\n </label>\n <textarea\n id=\"hwped-compose-body\"\n className=\"hwped-textarea\"\n rows={8}\n value={body}\n onChange={(e) => setBody(e.target.value)}\n placeholder={t(\"compose.bodyPlaceholder\")}\n />\n </div>\n\n {error !== null && (\n <ErrorLine prefix={t(\"error.prefix.compose\")} {...error} />\n )}\n\n <div className=\"hwped-row hwped-dialog-actions\">\n <button\n type=\"button\"\n className=\"hwped-btn\"\n onClick={props.onClose}\n disabled={busy}\n >\n {t(\"compose.cancel\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-primary\"\n onClick={() => void compose()}\n disabled={busy}\n >\n {busy ? t(\"compose.submitting\") : t(\"compose.submit\")}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","/**\n * Engine error classification for distinct UI states, mapping a failure\n * onto the four states the editor renders distinctly.\n *\n * The stable `HwpErrorCode` carried by `HwpEngineError` (@hwp-editor/core)\n * is the preferred input: `engineErrorKind` consults it first and never\n * reads the prose when it is present. Substring matching over the message\n * is the documented FALLBACK for failures that carry no code — a pre-1.0\n * server, or a maru/Tauri rejection that surfaces only a prefixed string\n * (\"hwped_read failed: cli_missing: ...\"). The markers below are pinned by\n * those engines; `classifyEngineError` stays exported for that path.\n *\n * This module classifies only. The human-readable badge LABELS live in the\n * string table (`error.kind.*` in messages.ts) and are resolved by\n * ErrorLine; nothing here renders text.\n */\n\nimport type { EditorError, HwpErrorCode } from \"@hwp-editor/core\";\nimport { isHwpEngineError, isHwpErrorCode } from \"@hwp-editor/core\";\n\nexport type EngineErrorKind = \"timeout\" | \"unavailable\" | \"protected\" | \"generic\";\n\n/**\n * Build the store/load carrier from an arbitrary thrown value: the code\n * only when the thrower supplied one AND it is a known HwpErrorCode. A\n * duck-typed foreign error (e.g. a Node ErrnoException with code \"ENOENT\")\n * must not leak a non-union string into a field typed as the union; its\n * code is dropped, not remapped — synthesizing `internal` here would be\n * indistinguishable from a real `internal` (see state.ts in core).\n */\nexport function toEditorError(e: unknown): EditorError {\n return isHwpEngineError(e) && isHwpErrorCode(e.code)\n ? { code: e.code, message: e.message }\n : { message: e instanceof Error ? e.message : String(e) };\n}\n\n/**\n * Badge per code. A total Record on purpose, not a switch with a default:\n * adding a sixteenth HwpErrorCode must fail `tsc --noEmit` here and force\n * an explicit badge decision rather than silently rendering \"generic\".\n *\n * `version` maps to `unavailable`: a binary too old and a binary missing\n * are the same problem with the same remedy from the user's seat.\n */\nconst KIND_BY_CODE: Record<HwpErrorCode, EngineErrorKind> = {\n timeout: \"timeout\",\n unavailable: \"unavailable\",\n version: \"unavailable\",\n protected: \"protected\",\n failed: \"generic\",\n bad_request: \"generic\",\n unsupported_format: \"generic\",\n output_too_large: \"generic\",\n cancelled: \"generic\",\n method_not_allowed: \"generic\",\n not_found: \"generic\",\n session_not_found: \"generic\",\n path_traversal: \"generic\",\n forbidden: \"generic\",\n internal: \"generic\",\n};\n\n/**\n * Single entry point: the code wins whenever it is present and known;\n * otherwise fall back to reading the message.\n */\nexport function engineErrorKind(error: {\n code?: string;\n message: string;\n}): EngineErrorKind {\n if (error.code !== undefined && Object.hasOwn(KIND_BY_CODE, error.code)) {\n return KIND_BY_CODE[error.code as HwpErrorCode];\n }\n return classifyEngineError(error.message);\n}\n\nexport function classifyEngineError(message: string): EngineErrorKind {\n const m = message.toLowerCase();\n // CliEngine \"timed out after\", maru \"hwp_timeout:\", HTTP 504.\n if (m.includes(\"timed out\") || m.includes(\"hwp_timeout\") || m.includes(\"http 504\")) {\n return \"timeout\";\n }\n // CliEngine \"binary not found\"/\"is not executable\", maru \"cli_missing:\", HTTP 503.\n if (\n m.includes(\"binary not found\") ||\n m.includes(\"cli_missing\") ||\n m.includes(\"not executable\") ||\n m.includes(\"http 503\")\n ) {\n return \"unavailable\";\n }\n // Protected/distribution documents: the read-only banner covers the\n // capabilities path; this catches edit-time refusals from the CLI.\n if (\n m.includes(\"distribution\") ||\n m.includes(\"encrypted\") ||\n m.includes(\"protected\") ||\n m.includes(\"배포용\")\n ) {\n return \"protected\";\n }\n return \"generic\";\n}\n","/**\n * The one alert surface in this package. Every `role=\"alert\"` the editor\n * renders goes through here, which is what guarantees each of them carries\n * a `data-error-kind` — and gives a later redaction pass (Phase 4 SEC-06)\n * a single place to change.\n *\n * Deliberately NOT exported from index.ts: `packages/react/src/index.ts` is\n * published API at 1.0.0 and nothing outside this package needs it.\n */\n\nimport type { JSX } from \"react\";\nimport { engineErrorKind } from \"./errors.js\";\nimport type { EngineErrorKind } from \"./errors.js\";\nimport { useHwpEditorContext } from \"./context.js\";\nimport type { MessageKey } from \"./messages.js\";\n\n/**\n * Badge label key per kind. A total Record on purpose: a fifth kind must\n * fail `tsc --noEmit` here rather than render an undefined label. The label\n * TEXT lives in the string table; only this kind→key mapping is code.\n */\nconst LABEL_KEY_BY_KIND: Record<EngineErrorKind, MessageKey> = {\n timeout: \"error.kind.timeout\",\n unavailable: \"error.kind.unavailable\",\n protected: \"error.kind.protected\",\n generic: \"error.kind.generic\",\n};\n\n/** One alert line with a distinct kind badge for known engine failures. */\nexport function ErrorLine(props: {\n prefix: string;\n /** Stable HwpErrorCode when the failure carried one; drives the badge. */\n code?: string;\n message: string;\n}): JSX.Element {\n // ErrorLine is always rendered inside <HwpEditor>, so it reaches `t`\n // through the context instead of taking a label prop at both call sites.\n const { t } = useHwpEditorContext();\n const kind = engineErrorKind({\n // Conditional spread: exactOptionalPropertyTypes rejects an explicit\n // `code: undefined` against the optional field.\n ...(props.code !== undefined ? { code: props.code } : {}),\n message: props.message,\n });\n return (\n <p className=\"hwped-error\" role=\"alert\" data-error-kind={kind}>\n {kind !== \"generic\" && (\n <span className={`hwped-error-kind hwped-error-${kind}`}>\n {t(LABEL_KEY_BY_KIND[kind])}\n </span>\n )}\n {props.prefix}: {props.message}\n </p>\n );\n}\n","/**\n * Compose-panel presets → DocumentSpec v2.\n *\n * Profile values mirror hwp-cli's official presets\n * (crates/hwp-convert/src/official.rs): body font, size (1/100 pt there,\n * plain pt here), line spacing percent, and page-number footer policy.\n */\n\nimport type { DocumentSpecV2 } from \"@hwp-editor/core\";\n\nexport type ComposePreset =\n | \"official\"\n | \"report\"\n | \"plan\"\n | \"notice\"\n | \"minutes\"\n | \"gaejosik\"\n | \"press\";\n\nexport const COMPOSE_PRESETS: ComposePreset[] = [\n \"official\",\n \"report\",\n \"plan\",\n \"notice\",\n \"minutes\",\n \"gaejosik\",\n \"press\",\n];\n\ninterface PresetProfile {\n fontFamily: string;\n bodySizePt: number;\n lineHeightPercent: number;\n pageNumber: boolean;\n}\n\n/**\n * Document data, NOT chrome (I18N-05). These font names travel into the\n * composed DocumentSpec and are consumed by hwp-cli; translating them would\n * change what the engine receives, so they stay here and are structurally\n * unreachable from the string table. The picker's human-readable LABELS\n * live in messages.ts under `presets.*`.\n */\nconst MALGUN = \"맑은 고딕\";\nconst HCR_BATANG = \"함초롬바탕\";\n\nconst PRESET_PROFILES: Record<ComposePreset, PresetProfile> = {\n official: { fontFamily: MALGUN, bodySizePt: 12, lineHeightPercent: 160, pageNumber: false },\n report: { fontFamily: HCR_BATANG, bodySizePt: 15, lineHeightPercent: 160, pageNumber: true },\n plan: { fontFamily: HCR_BATANG, bodySizePt: 15, lineHeightPercent: 160, pageNumber: true },\n notice: { fontFamily: MALGUN, bodySizePt: 15, lineHeightPercent: 160, pageNumber: true },\n minutes: { fontFamily: HCR_BATANG, bodySizePt: 14, lineHeightPercent: 130, pageNumber: false },\n gaejosik: { fontFamily: MALGUN, bodySizePt: 15, lineHeightPercent: 160, pageNumber: true },\n press: { fontFamily: HCR_BATANG, bodySizePt: 14, lineHeightPercent: 160, pageNumber: true },\n};\n\nexport interface ComposeInput {\n title: string;\n author: string;\n /**\n * Markdown-ish body: blank lines separate paragraphs; a line starting\n * with \"# \" becomes a heading-styled paragraph.\n */\n body: string;\n}\n\ntype ParagraphBlock = {\n type: \"paragraph\";\n style?: string;\n runs: [{ type: \"text\"; text: string }];\n};\n\n/** Parse the guided-form body text into paragraph blocks. */\nexport function bodyToBlocks(body: string): ParagraphBlock[] {\n const blocks: ParagraphBlock[] = [];\n for (const chunk of body.split(/\\n\\s*\\n/)) {\n const text = chunk.trim();\n if (text === \"\") continue;\n if (text.startsWith(\"# \")) {\n blocks.push({\n type: \"paragraph\",\n style: \"heading\",\n runs: [{ type: \"text\", text: text.slice(2).trim() }],\n });\n } else {\n blocks.push({\n type: \"paragraph\",\n style: \"body\",\n runs: [{ type: \"text\", text }],\n });\n }\n }\n return blocks;\n}\n\n/** Build the DocumentSpec v2 for a preset + guided form input. */\nexport function buildDocumentSpec(\n preset: ComposePreset,\n input: ComposeInput,\n): DocumentSpecV2 {\n const profile = PRESET_PROFILES[preset];\n const blocks: ParagraphBlock[] = [];\n if (input.title.trim() !== \"\") {\n blocks.push({\n type: \"paragraph\",\n style: \"title\",\n runs: [{ type: \"text\", text: input.title.trim() }],\n });\n }\n blocks.push(...bodyToBlocks(input.body));\n if (blocks.length === 0) {\n blocks.push({\n type: \"paragraph\",\n style: \"body\",\n runs: [{ type: \"text\", text: \" \" }],\n });\n }\n const section = {\n ...(profile.pageNumber\n ? { page_number: { position: \"bottom_center\" as const } }\n : {}),\n blocks,\n };\n return {\n version: \"2.0\",\n document: {\n version: \"1.0\",\n metadata: {\n ...(input.title.trim() !== \"\" ? { title: input.title.trim() } : {}),\n ...(input.author.trim() !== \"\" ? { author: input.author.trim() } : {}),\n },\n styles: {\n body: {\n font_family: profile.fontFamily,\n font_size_pt: profile.bodySizePt,\n line_height_percent: profile.lineHeightPercent,\n align: \"justify\",\n },\n heading: {\n font_family: profile.fontFamily,\n font_size_pt: profile.bodySizePt + 3,\n bold: true,\n spacing_before_pt: 13,\n spacing_after_pt: 6,\n },\n title: {\n font_family: profile.fontFamily,\n font_size_pt: profile.bodySizePt + 6,\n bold: true,\n align: \"center\",\n spacing_after_pt: 18,\n },\n },\n sections: [section],\n },\n };\n}\n","/**\n * The editor's string table: one flat `<area>.<thing>` key map per locale,\n * plus the `t()` factory that merges them.\n *\n * Contract (published API at 1.0.0 — a key rename is a breaking change):\n *\n * - `en` is canonical and is the default when no `locale` is given. It is\n * declared WITHOUT `as const` so its values widen to `string` / function\n * signatures; `const ko: MessageTable` then makes a key missing from\n * EITHER table a `tsc` error (a missing key is a required-property error,\n * an extra key an excess-property one). That two-way parity is the whole\n * reason for the `typeof en` spelling — a plain `Record<..., string>`\n * would widen every value to the union and lose per-key parameter types.\n * - Count-bearing messages are FUNCTION values taking a single named-params\n * object, never positional args and never a runtime `{count}` template.\n * Interpolation happens inside the function body, so word order is a\n * per-locale choice and English can carry a real plural branch.\n * - Merge order is `en` -> locale table -> host `messages`. An override\n * replaces exactly one key; every other key falls through to the locale\n * default. Lookup is exact string equality with no normalization.\n *\n * NOT in this table, deliberately (I18N-05): font names, preset profiles,\n * the `#FF0000` placeholder sample, and the engine's `{message}` error tail.\n * Those are document data or engine-authored prose — translating them would\n * change what hwp-cli receives or rewrite what the engine actually said.\n */\n\nexport const en = {\n // Toolbar\n \"toolbar.toolsAria\": \"Editing tools\",\n \"toolbar.readOnly\": \"Read-only\",\n \"toolbar.pendingEdits\": (p: { count: number }): string =>\n p.count === 1 ? \"1 pending edit\" : `${p.count} pending edits`,\n \"toolbar.revert\": \"Undo edit\",\n \"toolbar.apply\": \"Apply\",\n \"toolbar.applyWithCount\": (p: { count: number }): string =>\n `Apply (${p.count})`,\n \"toolbar.applying\": \"Applying…\",\n \"toolbar.newDocument\": \"New document\",\n\n // Validation badge\n \"validation.aria\": \"Validation result\",\n \"validation.valid\": \"Valid\",\n \"validation.errors\": (p: { count: number }): string =>\n p.count === 1 ? \"1 error\" : `${p.count} errors`,\n\n // Canvas\n \"canvas.aria\": \"Document pages\",\n \"canvas.empty\": \"No document open.\",\n \"canvas.createCta\": \"Create a new document\",\n \"canvas.emptyPages\": \"No rendered pages.\",\n \"page.label\": (p: { page: number }): string => `Page ${p.page}`,\n\n // Side panel shell\n \"side.panelAria\": \"Editing panels\",\n \"tabs.para\": \"Paragraph\",\n \"tabs.table\": \"Table\",\n \"tabs.fields\": \"Fields\",\n\n // Error line — the prefix names which operation failed. The `{message}`\n // tail stays engine-authored and is never translated.\n \"error.prefix.load\": \"Failed to open document\",\n \"error.prefix.apply\": \"Failed to apply edits\",\n \"error.prefix.compose\": \"Failed to create document\",\n // Badge labels; \"generic\" renders no chip, hence the empty string.\n \"error.kind.timeout\": \"Engine timed out\",\n \"error.kind.unavailable\": \"hwp binary unavailable\",\n \"error.kind.protected\": \"Protected document\",\n \"error.kind.generic\": \"\",\n\n // Compose dialog\n \"compose.title\": \"Create a new document\",\n \"compose.docType\": \"Document type\",\n \"compose.docTypeAria\": \"Document type\",\n \"compose.titleLabel\": \"Title\",\n \"compose.titlePlaceholder\": \"Document title\",\n \"compose.authorLabel\": \"Author\",\n \"compose.authorPlaceholder\": \"Author (optional)\",\n \"compose.bodyLabel\": \"Body\",\n \"compose.bodyPlaceholder\":\n \"Blank lines separate paragraphs. Lines starting with '# ' become subheadings.\\n\\nExample:\\n# 1. Overview\\nBody text...\",\n \"compose.cancel\": \"Cancel\",\n \"compose.submit\": \"Create document\",\n \"compose.submitting\": \"Creating…\",\n /** Filename stem used when the compose form has no title. */\n \"compose.defaultFileStem\": \"New document\",\n\n // Compose preset labels. The preset PROFILES (font names, sizes) are\n // document data and stay in presets.ts, untranslated.\n \"presets.official\": \"Official document\",\n \"presets.report\": \"Report\",\n \"presets.plan\": \"Plan\",\n \"presets.notice\": \"Notice\",\n \"presets.minutes\": \"Minutes\",\n \"presets.gaejosik\": \"Outline document\",\n \"presets.press\": \"Press release\",\n\n // SegmentInspector\n \"segment.panelAria\": \"Paragraph editor\",\n \"segment.hint\": \"Click the page to select a paragraph to edit.\",\n \"segment.selectedPara\": (p: { section: number; para: number }): string =>\n `Selected paragraph (section ${p.section}, paragraph ${p.para})`,\n \"segment.emptyPara\": \"(empty paragraph)\",\n \"segment.replaceLabel\": \"Replace text\",\n \"segment.replacePlaceholder\": \"New text\",\n \"segment.replaceSubmit\": \"Replace\",\n \"segment.insertLabel\": \"Insert paragraph\",\n \"segment.insertPlaceholder\": \"Paragraph text to insert\",\n \"segment.insertBefore\": \"Insert before\",\n \"segment.insertAfter\": \"Insert after\",\n \"segment.deletePara\": \"Delete paragraph\",\n \"segment.alignLabel\": \"Alignment\",\n \"segment.alignGroupAria\": \"Paragraph alignment\",\n \"segment.alignLeft\": \"Left\",\n \"segment.alignCenter\": \"Center\",\n \"segment.alignRight\": \"Right\",\n \"segment.alignJustify\": \"Justify\",\n \"segment.formatLabel\": \"Character format\",\n \"segment.bold\": \"Bold\",\n \"segment.sizePlaceholder\": \"Size (pt)\",\n \"segment.sizeAria\": \"Font size (pt)\",\n \"segment.colorAria\": \"Font color\",\n \"segment.formatSubmit\": \"Apply format\",\n\n // TableGrid\n \"table.panelAria\": \"Table editor\",\n \"table.hint\":\n \"Select a region containing a table on the page. The current selection is not a table paragraph.\",\n \"table.tableLabel\": (p: { index: number }): string => `Table #${p.index}`,\n \"table.cellLabel\": (p: { row: number; col: number }): string =>\n `Cell (${p.row}, ${p.col})`,\n \"table.setCell\": \"Set cell\",\n \"table.mergeAnchor\": \"Set merge anchor\",\n \"table.mergeWithAnchor\": \"Merge with anchor\",\n \"table.splitCell\": \"Split cell\",\n \"table.rowsCols\": \"Rows / columns\",\n \"table.addRow\": \"Add row\",\n \"table.addCol\": \"Add column\",\n \"table.deleteRow\": \"Delete row\",\n \"table.deleteCol\": \"Delete column\",\n \"table.deleteTable\": \"Delete table\",\n\n // FieldsPanel\n \"fields.panelAria\": \"Fields\",\n \"fields.hint\": \"No {{name}} field placeholders were found in the document.\",\n \"fields.valuePlaceholder\": \"New value\",\n \"fields.fieldValueAria\": (p: { name: string }): string =>\n `Value for field ${p.name}`,\n \"fields.setValue\": \"Set value\",\n};\n\n/** The shape both locale tables must satisfy, derived from canonical `en`. */\nexport type MessageTable = typeof en;\n/** Every valid `t()` key. */\nexport type MessageKey = keyof MessageTable;\n/** Host-supplied per-key overrides; unknown keys are a `tsc` error. */\nexport type HwpEditorMessages = Partial<MessageTable>;\n/** Supported UI locales. Mount-time only — runtime switching is not supported. */\nexport type Locale = \"en\" | \"ko\";\n\n/**\n * Korean chrome. These are the literals that already shipped, carried over\n * VERBATIM (including the `...` in-progress convention, where English uses\n * a single `…`) — they are correct and the existing suite pins them.\n */\nexport const ko: MessageTable = {\n \"toolbar.toolsAria\": \"편집 도구\",\n \"toolbar.readOnly\": \"읽기 전용\",\n \"toolbar.pendingEdits\": (p) => `대기 편집 ${p.count}`,\n \"toolbar.revert\": \"되돌리기\",\n \"toolbar.apply\": \"적용\",\n \"toolbar.applyWithCount\": (p) => `적용 (${p.count})`,\n \"toolbar.applying\": \"적용 중...\",\n \"toolbar.newDocument\": \"새 문서\",\n\n \"validation.aria\": \"검증 결과\",\n \"validation.valid\": \"유효\",\n \"validation.errors\": (p) => `오류 ${p.count}건`,\n\n \"canvas.aria\": \"문서 페이지\",\n \"canvas.empty\": \"열린 문서가 없습니다.\",\n \"canvas.createCta\": \"새 문서 만들기\",\n \"canvas.emptyPages\": \"렌더링된 페이지가 없습니다.\",\n \"page.label\": (p) => `페이지 ${p.page}`,\n\n \"side.panelAria\": \"편집 패널\",\n \"tabs.para\": \"문단\",\n \"tabs.table\": \"표\",\n \"tabs.fields\": \"필드\",\n\n \"error.prefix.load\": \"문서 열기 실패\",\n \"error.prefix.apply\": \"편집 적용 실패\",\n \"error.prefix.compose\": \"문서 생성 실패\",\n \"error.kind.timeout\": \"엔진 시간 초과\",\n \"error.kind.unavailable\": \"hwp 실행 파일 없음\",\n \"error.kind.protected\": \"보호/배포 문서\",\n \"error.kind.generic\": \"\",\n\n \"compose.title\": \"새 문서 만들기\",\n \"compose.docType\": \"문서 유형\",\n \"compose.docTypeAria\": \"문서 유형\",\n \"compose.titleLabel\": \"제목\",\n \"compose.titlePlaceholder\": \"문서 제목\",\n \"compose.authorLabel\": \"작성자\",\n \"compose.authorPlaceholder\": \"작성자 (선택)\",\n \"compose.bodyLabel\": \"본문\",\n \"compose.bodyPlaceholder\":\n \"빈 줄로 문단을 구분합니다. '# '로 시작하는 줄은 소제목이 됩니다.\\n\\n예)\\n# 1. 개요\\n본문 내용...\",\n \"compose.cancel\": \"취소\",\n \"compose.submit\": \"문서 생성\",\n \"compose.submitting\": \"생성 중...\",\n \"compose.defaultFileStem\": \"새 문서\",\n\n \"presets.official\": \"공문\",\n \"presets.report\": \"보고서\",\n \"presets.plan\": \"계획서\",\n \"presets.notice\": \"안내문\",\n \"presets.minutes\": \"회의록\",\n \"presets.gaejosik\": \"개조식 문서\",\n \"presets.press\": \"보도자료\",\n\n \"segment.panelAria\": \"문단 편집\",\n \"segment.hint\": \"페이지를 클릭해 편집할 문단을 선택하세요.\",\n \"segment.selectedPara\": (p) => `선택 문단 (구역 ${p.section}, 문단 ${p.para})`,\n \"segment.emptyPara\": \"(빈 문단)\",\n \"segment.replaceLabel\": \"텍스트 교체\",\n \"segment.replacePlaceholder\": \"새 텍스트\",\n \"segment.replaceSubmit\": \"교체\",\n \"segment.insertLabel\": \"문단 삽입\",\n \"segment.insertPlaceholder\": \"삽입할 문단 텍스트\",\n \"segment.insertBefore\": \"앞에 삽입\",\n \"segment.insertAfter\": \"뒤에 삽입\",\n \"segment.deletePara\": \"문단 삭제\",\n \"segment.alignLabel\": \"정렬\",\n \"segment.alignGroupAria\": \"문단 정렬\",\n \"segment.alignLeft\": \"왼쪽\",\n \"segment.alignCenter\": \"가운데\",\n \"segment.alignRight\": \"오른쪽\",\n \"segment.alignJustify\": \"양쪽\",\n \"segment.formatLabel\": \"글자 서식\",\n \"segment.bold\": \"굵게\",\n \"segment.sizePlaceholder\": \"크기(pt)\",\n \"segment.sizeAria\": \"글자 크기(pt)\",\n \"segment.colorAria\": \"글자 색상\",\n \"segment.formatSubmit\": \"서식 적용\",\n\n \"table.panelAria\": \"표 편집\",\n \"table.hint\":\n \"표가 포함된 영역을 페이지에서 선택하세요. 표가 아닌 문단이 선택되어 있습니다.\",\n \"table.tableLabel\": (p) => `표 #${p.index}`,\n \"table.cellLabel\": (p) => `셀 (${p.row}, ${p.col})`,\n \"table.setCell\": \"셀 설정\",\n \"table.mergeAnchor\": \"병합 기준 지정\",\n \"table.mergeWithAnchor\": \"기준 셀과 병합\",\n \"table.splitCell\": \"셀 분할\",\n \"table.rowsCols\": \"행/열\",\n \"table.addRow\": \"행 추가\",\n \"table.addCol\": \"열 추가\",\n \"table.deleteRow\": \"행 삭제\",\n \"table.deleteCol\": \"열 삭제\",\n \"table.deleteTable\": \"표 삭제\",\n\n \"fields.panelAria\": \"필드\",\n \"fields.hint\": \"문서에서 {{이름}} 형태의 필드 자리표시자를 찾지 못했습니다.\",\n \"fields.valuePlaceholder\": \"새 값\",\n \"fields.fieldValueAria\": (p) => `필드 ${p.name} 값`,\n \"fields.setValue\": \"설정\",\n};\n\n/**\n * Lookup function. Keys with a function value REQUIRE their params object;\n * plain-string keys accept no second argument — both enforced per key by\n * the conditional variadic below, so a missing or wrong params object is a\n * compile error at the call site.\n */\nexport type TFunction = <K extends MessageKey>(\n key: K,\n ...args: MessageTable[K] extends (p: infer P) => string ? [params: P] : []\n) => string;\n\n/**\n * Build a `t()` bound to one locale and one set of host overrides.\n * Merge order: `en` -> locale table -> `messages` (last wins, per key).\n */\nexport function createT(\n locale: Locale,\n messages?: HwpEditorMessages,\n): TFunction {\n const table: MessageTable = {\n ...en,\n ...(locale === \"ko\" ? ko : {}),\n ...messages,\n };\n // The cast is contained here: the public TFunction signature still gives\n // call sites full per-key parameter checking.\n return ((key: MessageKey, params?: unknown): string => {\n const value = table[key];\n return typeof value === \"function\"\n ? (value as (p: unknown) => string)(params)\n : value;\n }) as TFunction;\n}\n"],"mappings":"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","names":["import_react","import_core","import_react","import_core","import_react","import_core","import_jsx_runtime","import_react","import_core","import_jsx_runtime","import_react","import_core","import_core","import_jsx_runtime","import_react","import_core","import_jsx_runtime","import_jsx_runtime","import_core","import_jsx_runtime","HwpEditor","dirty"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/HwpEditor.tsx","../src/context.ts","../src/PageCanvas.tsx","../src/geometry.ts","../src/sanitize.ts","../src/text.ts","../src/SegmentInspector.tsx","../src/TableGrid.tsx","../src/tables.ts","../src/FieldsPanel.tsx","../src/fields.ts","../src/ComposePanel.tsx","../src/errors.ts","../src/ErrorLine.tsx","../src/presets.ts","../src/messages.ts"],"sourcesContent":["/**\n * @hwp-editor/react — embeddable React UI for HWP/HWPX documents.\n *\n * Styles are NOT auto-injected; hosts must import the extracted stylesheet:\n * import \"@hwp-editor/react/style.css\";\n * Theming is CSS-variable only (see theme.css / README for the contract).\n */\n\nimport \"./theme.css\";\nimport \"./editor.css\";\n\nexport { HwpEditor } from \"./HwpEditor.js\";\nexport type { HwpEditorHandle, HwpEditorProps } from \"./HwpEditor.js\";\nexport { PageCanvas } from \"./PageCanvas.js\";\nexport { SegmentInspector } from \"./SegmentInspector.js\";\nexport { TableGrid } from \"./TableGrid.js\";\nexport { FieldsPanel } from \"./FieldsPanel.js\";\nexport { ComposePanel } from \"./ComposePanel.js\";\nexport type { ComposePanelProps } from \"./ComposePanel.js\";\n\nexport { sanitizeSvg } from \"./sanitize.js\";\nexport { plainSegmentText } from \"./text.js\";\nexport { nearestSegment, segmentBand, clickOffset } from \"./geometry.js\";\nexport type { SegmentBand } from \"./geometry.js\";\nexport { findTables, tableAtRef, parseMarkdownTable, isTableSlice } from \"./tables.js\";\nexport type { TableModel } from \"./tables.js\";\nexport { extractFieldSlots } from \"./fields.js\";\nexport type { FieldSlot } from \"./fields.js\";\nexport { COMPOSE_PRESETS, buildDocumentSpec, bodyToBlocks } from \"./presets.js\";\nexport type { ComposePreset, ComposeInput } from \"./presets.js\";\nexport { useHwpEditorContext } from \"./context.js\";\nexport type { HwpEditorContextValue } from \"./context.js\";\nexport { classifyEngineError } from \"./errors.js\";\nexport type { EngineErrorKind } from \"./errors.js\";\n// The locale tables are public: a host writing `messages` overrides needs\n// them to discover which keys exist and what the defaults say.\nexport { en, ko, createT } from \"./messages.js\";\nexport type {\n MessageTable,\n MessageKey,\n HwpEditorMessages,\n Locale,\n TFunction,\n} from \"./messages.js\";\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport type { CSSProperties, JSX, KeyboardEvent } from \"react\";\nimport type {\n Capabilities,\n CatEnvelope,\n DocumentHandle,\n HwpEngine,\n ValidationReport,\n} from \"@hwp-editor/core\";\nimport { createStore, segmentAtRef } from \"@hwp-editor/core\";\nimport type { EditorError, EditorStore } from \"@hwp-editor/core\";\nimport { HwpEditorContext } from \"./context.js\";\nimport type { HwpEditorContextValue } from \"./context.js\";\nimport { PageCanvas } from \"./PageCanvas.js\";\nimport { SegmentInspector } from \"./SegmentInspector.js\";\nimport { TableGrid } from \"./TableGrid.js\";\nimport { FieldsPanel } from \"./FieldsPanel.js\";\nimport { ComposePanel } from \"./ComposePanel.js\";\nimport { isTableSlice } from \"./tables.js\";\nimport { ErrorLine } from \"./ErrorLine.js\";\nimport { toEditorError } from \"./errors.js\";\nimport { createT } from \"./messages.js\";\nimport type { HwpEditorMessages, Locale } from \"./messages.js\";\nimport { segmentText } from \"@hwp-editor/core\";\n\nexport interface HwpEditorProps {\n /** Engine implementation (HTTP client, local adapter, mock in tests). */\n engine: HwpEngine;\n /** Document to open; null shows the empty state with the new-doc entry. */\n file: DocumentHandle | null;\n /**\n * UI language for the editor chrome. Defaults to `\"en\"`. Read at mount and\n * on change; also drives the root `lang` attribute. Document content and\n * engine-authored error prose are never translated.\n */\n locale?: Locale;\n /**\n * Per-key overrides applied on top of the locale table. A key not listed\n * keeps its locale default; unknown keys are a compile error.\n */\n messages?: HwpEditorMessages;\n /**\n * Force the editor read-only regardless of what the engine reports. A UI\n * affordance, NOT an authorization boundary: a host that must actually\n * prevent writes enforces that server-side (see the server package's\n * `authorize` hook). Wins over an editable engine; never re-enables a\n * document the engine reports as protected.\n */\n readOnly?: boolean;\n /**\n * Called once per completed document load, after both the read and the\n * render resolve, with the document that was loaded. Fires again on every\n * `file` change; never fires for `file={null}` or a load cancelled by\n * unmount.\n */\n onReady?: (document: DocumentHandle) => void;\n /**\n * Called for every engine failure — load, apply, undo, refresh, and\n * compose — with the caught value verbatim, so a host can branch on the\n * stable `code` of a `HwpEngineError`. The inline alert renders either\n * way; this is an addition to it, not a replacement.\n */\n onError?: (error: unknown) => void;\n /** Called whenever the document bytes change (applied edit, undo, compose). */\n onChange?: (document: DocumentHandle) => void;\n /** Called when the dirty flag (pending ops queued) changes. */\n onDirtyChange?: (dirty: boolean) => void;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * Imperative surface a host reaches through `ref`. Exactly four methods at\n * 1.0.0 and no state getters: hosts observe state through `onChange` /\n * `onDirtyChange` / `onReady` / `onError`, which stay in sync with React\n * rendering in a way a getter read from outside the render cycle cannot.\n */\nexport interface HwpEditorHandle {\n /**\n * Apply the queued edit ops. Resolves without touching the engine when the\n * queue is empty, no document is loaded, an apply is already in flight, or\n * the editor is read-only.\n */\n apply(): Promise<void>;\n /**\n * Undo the last applied edit. Resolves without touching the engine when the\n * snapshot stack is empty.\n */\n revert(): Promise<void>;\n /**\n * Re-read and re-render the current document after an external change.\n * Rejects if the engine fails (after firing `onError` and showing the alert).\n */\n refresh(): Promise<void>;\n /** Open the new-document compose dialog. */\n openCompose(): void;\n}\n\ntype SideTab = \"para\" | \"table\" | \"fields\";\n\n/**\n * Every render goes straight to the engine. The former client-side\n * SVG-to-PNG catch-all turned a timeout, a missing binary, or a network\n * error into a second full CLI render and masked which one it was\n * (BUG-01). The one legitimate retry lives in the engine, gated on a real\n * format failure: CliEngine at cli-engine.ts:445-451 (`reason === \"failed\"`)\n * and maru at hwped.rs:485-486 (the `hwp_failed:` prefix).\n */\nconst RENDER_SVG = { format: \"svg\" } as const;\n\n/**\n * Top-level embeddable editor. Layout: toolbar (apply/revert/validation\n * badge/pending-ops count/protected notice) | PageCanvas | side panel\n * (SegmentInspector / TableGrid / FieldsPanel tabs). The new-document entry\n * point opens ComposePanel.\n */\nexport const HwpEditor = forwardRef<HwpEditorHandle, HwpEditorProps>(\n function HwpEditor(props, ref): JSX.Element {\n const {\n engine,\n file,\n locale = \"en\",\n messages,\n readOnly = false,\n onReady,\n onError,\n onChange,\n onDirtyChange,\n className,\n style,\n } = props;\n\n /**\n * Host callbacks are deliberately NON-REACTIVE. They live in this one\n * bundle ref and reach the component only through the stable dispatchers\n * below. Putting any of them back into a dependency array turns an\n * ordinary host re-render — the inline-arrow idiom every React host\n * writes — into a full engine round trip (capabilities + read + render +\n * validate) against the same document, which is worst on exactly the\n * multi-megabyte documents BUG-06's chunked codec was added to serve.\n */\n const cbRef = useRef({ onReady, onError, onChange, onDirtyChange });\n // No dependency array on purpose: this runs after EVERY render, so a\n // dispatcher fired later always reaches the host's latest identity rather\n // than a mount-time closure. Declared above the load effect because React\n // runs a component's effects in declaration order.\n useEffect(() => {\n cbRef.current = { onReady, onError, onChange, onDirtyChange };\n });\n\n // Forward-only dispatchers, stable for the component's lifetime. They\n // pass the argument by reference and return nothing: no wrapping, no\n // re-throwing, no synthesized code (03-CONTEXT D-09).\n const emitReady = useCallback((document: DocumentHandle): void => {\n cbRef.current.onReady?.(document);\n }, []);\n const emitError = useCallback((error: unknown): void => {\n cbRef.current.onError?.(error);\n }, []);\n const emitChange = useCallback((document: DocumentHandle): void => {\n cbRef.current.onChange?.(document);\n }, []);\n const emitDirty = useCallback((dirty: boolean): void => {\n cbRef.current.onDirtyChange?.(dirty);\n }, []);\n\n const t = useMemo(() => createT(locale, messages), [locale, messages]);\n\n const [store] = useState<EditorStore>(() => createStore());\n // getServerSnapshot is required for SSR hosts (Next.js); a fresh store's\n // state is always initialState server-side.\n const state = useSyncExternalStore(store.subscribe, store.getState, store.getState);\n\n const [envelope, setEnvelope] = useState<CatEnvelope | null>(null);\n const [capabilities, setCapabilities] = useState<Capabilities | null>(null);\n const [validation, setValidation] = useState<ValidationReport | null>(null);\n // `code` is deliberately optional: a host-supplied engine, a mock, or a\n // React-internal throw legitimately has none, and synthesizing `internal`\n // would be indistinguishable from a real `internal`.\n const [loadError, setLoadError] = useState<EditorError | null>(null);\n const [tab, setTab] = useState<SideTab>(\"para\");\n const [composing, setComposing] = useState(false);\n\n // Load the document whenever the engine/file pair changes.\n useEffect(() => {\n let cancelled = false;\n if (file === null) {\n setEnvelope(null);\n setValidation(null);\n setLoadError(null);\n return;\n }\n (async () => {\n try {\n const caps = await engine.capabilities();\n const [nextEnvelope, pages, report] = await Promise.all([\n engine.read(file),\n engine.render(file, RENDER_SVG),\n engine.validate(file).catch(() => null),\n ]);\n if (cancelled) return;\n setCapabilities(caps);\n setEnvelope(nextEnvelope);\n setValidation(report);\n setLoadError(null);\n store.dispatch({ type: \"load\", document: file, pages });\n // Once per completed load, from THIS effect only: a second effect\n // keyed on envelope/pages would re-fire after every apply and undo.\n emitReady(file);\n } catch (e) {\n if (cancelled) return;\n setLoadError(toEditorError(e));\n emitError(e);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [engine, file, store]);\n\n // Single fan-out point: every panel, both toolbar buttons and the\n // applyPendingOps guard read `editable`, so `readOnly` works everywhere\n // because it is applied here and nowhere else.\n const editable = !readOnly && (capabilities?.editable ?? true);\n\n // Follow selection to the relevant tab.\n useEffect(() => {\n if (envelope === null || state.selection === null) return;\n const segment = segmentAtRef(envelope, state.selection);\n if (segment === undefined) return;\n setTab(\n isTableSlice(segmentText(envelope, segment)) ? \"table\" : \"para\",\n );\n }, [envelope, state.selection]);\n\n // Dirty-change callback.\n const dirty = state.pendingOps.length > 0;\n useEffect(() => {\n emitDirty(dirty);\n }, [dirty]);\n\n const applyPendingOps = useCallback((): Promise<void> => {\n const snapshot = store.getState();\n if (\n snapshot.document === null ||\n snapshot.pendingOps.length === 0 ||\n snapshot.status === \"applying\" ||\n !editable\n ) {\n return Promise.resolve();\n }\n store.dispatch({ type: \"applyStarted\" });\n return (async () => {\n try {\n const next = await engine.edit(snapshot.document!, snapshot.pendingOps, {\n verify: true,\n });\n const [nextEnvelope, pages, report] = await Promise.all([\n engine.read(next),\n engine.render(next, RENDER_SVG),\n engine.validate(next).catch(() => null),\n ]);\n setEnvelope(nextEnvelope);\n setValidation(report);\n store.dispatch({ type: \"applySucceeded\", document: next, pages });\n emitChange(next);\n } catch (e) {\n store.dispatch({ type: \"applyFailed\", error: toEditorError(e) });\n emitError(e);\n }\n })();\n }, [editable, engine, store]);\n\n const revert = useCallback((): Promise<void> => {\n const snapshot = store.getState();\n const previous = snapshot.snapshots[snapshot.snapshots.length - 1];\n if (previous === undefined) return Promise.resolve();\n return (async () => {\n try {\n // BUG-02: the badge described the document being undone away, so\n // re-validate the restored one. Same shape as applyPendingOps; a\n // validate failure leaves the previous badge rather than clearing it.\n const [nextEnvelope, pages, report] = await Promise.all([\n engine.read(previous),\n engine.render(previous, RENDER_SVG),\n engine.validate(previous).catch(() => null),\n ]);\n // Dispatch only after the engine succeeds: popping the snapshot\n // first and failing mid-undo left the canvas showing the pre-undo\n // envelope while the store claimed the previous document. A second\n // revert may have consumed this snapshot while we awaited; if so,\n // leave the newer transition alone.\n const now = store.getState();\n if (now.snapshots[now.snapshots.length - 1] !== previous) return;\n store.dispatch({ type: \"undo\" });\n setEnvelope(nextEnvelope);\n if (report !== null) setValidation(report);\n store.dispatch({ type: \"setPages\", pages });\n emitChange(previous);\n } catch (e) {\n // The store was never touched, so store and canvas stay consistent;\n // without this destination the rejection was unhandled.\n setLoadError(toEditorError(e));\n emitError(e);\n }\n })();\n }, [engine, store]);\n\n const refresh = useCallback(async () => {\n const snapshot = store.getState();\n if (snapshot.document === null) return;\n try {\n const [nextEnvelope, pages, report] = await Promise.all([\n engine.read(snapshot.document),\n engine.render(snapshot.document, RENDER_SVG),\n engine.validate(snapshot.document).catch(() => null),\n ]);\n setEnvelope(nextEnvelope);\n setValidation(report);\n store.dispatch({ type: \"setPages\", pages });\n } catch (e) {\n // A no-op resolves quietly (above); a FAILURE must be observable to\n // the awaiting host, so surface it three ways and reject.\n setLoadError(toEditorError(e));\n emitError(e);\n throw e;\n }\n }, [engine, store]);\n\n const openCompose = useCallback(() => setComposing(true), []);\n\n useImperativeHandle(\n ref,\n () => ({ apply: applyPendingOps, revert, refresh, openCompose }),\n [applyPendingOps, revert, refresh, openCompose],\n );\n\n const contextValue: HwpEditorContextValue = useMemo(\n () => ({\n engine,\n store,\n state,\n envelope,\n capabilities,\n editable,\n validation,\n applyPendingOps,\n refresh,\n openCompose,\n t,\n // Always defined now, and stable: a widening, since every consumer\n // already calls it as `onError?.(e)` and it no-ops when the host\n // supplied no callback. The payload is unchanged.\n onError: emitError,\n }),\n [\n engine,\n store,\n state,\n envelope,\n capabilities,\n editable,\n validation,\n applyPendingOps,\n refresh,\n openCompose,\n t,\n ],\n );\n\n const onKeyDown = (e: KeyboardEvent<HTMLDivElement>): void => {\n if (e.key === \"Escape\") {\n // With the compose dialog open, Escape belongs to the dialog (it\n // closes it); one press must not also drop the page selection.\n if (composing) return;\n store.dispatch({ type: \"select\", selection: null });\n } else if ((e.metaKey || e.ctrlKey) && e.key === \"Enter\") {\n e.preventDefault();\n void applyPendingOps();\n }\n };\n\n const rootClass =\n \"hwped hwped-root\" + (className !== undefined ? ` ${className}` : \"\");\n\n return (\n <HwpEditorContext.Provider value={contextValue}>\n <div\n className={rootClass}\n style={style}\n onKeyDown={onKeyDown}\n data-status={state.status}\n // No `dir`: both supported locales are ltr.\n lang={locale}\n >\n <header\n className=\"hwped-toolbar\"\n role=\"toolbar\"\n aria-label={t(\"toolbar.toolsAria\")}\n >\n <span className=\"hwped-title\">\n {state.document?.name ?? \"hwp-editor\"}\n </span>\n {!editable && (\n <span\n className=\"hwped-notice\"\n role=\"note\"\n // The full engine prose stays reachable on hover once the\n // toolbar clamp truncates a long reason (UI-DEBT-01).\n {...(capabilities?.reason !== undefined\n ? { title: capabilities.reason }\n : {})}\n >\n {t(\"toolbar.readOnly\")}\n {/* Suffix only when the ENGINE refused: a host-forced\n read-only has no reason, and inventing one would claim the\n document is protected when it isn't. The engine's reason is\n its own prose, shown verbatim under either locale. */}\n {capabilities?.editable === false &&\n (capabilities.reason !== undefined\n ? `: ${capabilities.reason}`\n : ` (${t(\"error.kind.protected\")})`)}\n </span>\n )}\n <span className=\"hwped-spacer\" />\n {validation !== null && (\n <span\n className={\n validation.valid\n ? \"hwped-badge hwped-badge-ok\"\n : \"hwped-badge hwped-badge-err\"\n }\n role=\"status\"\n aria-label={t(\"validation.aria\")}\n >\n {validation.valid\n ? t(\"validation.valid\")\n : t(\"validation.errors\", { count: validation.errors.length })}\n </span>\n )}\n <span\n className=\"hwped-count\"\n aria-label={t(\"toolbar.pendingEdits\", {\n count: state.pendingOps.length,\n })}\n >\n {t(\"toolbar.pendingEdits\", { count: state.pendingOps.length })}\n </span>\n <button\n type=\"button\"\n className=\"hwped-btn\"\n onClick={() => void revert()}\n disabled={state.snapshots.length === 0 || state.status === \"applying\"}\n >\n {t(\"toolbar.revert\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-primary\"\n onClick={() => void applyPendingOps()}\n disabled={!dirty || !editable || state.status === \"applying\"}\n >\n {state.status === \"applying\"\n ? t(\"toolbar.applying\")\n : t(\"toolbar.applyWithCount\", {\n count: state.pendingOps.length,\n })}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn\"\n onClick={() => setComposing(true)}\n >\n {t(\"toolbar.newDocument\")}\n </button>\n </header>\n\n {state.status === \"error\" && state.error !== null && (\n <ErrorLine prefix={t(\"error.prefix.apply\")} {...state.error} />\n )}\n {loadError !== null && (\n <ErrorLine prefix={t(\"error.prefix.load\")} {...loadError} />\n )}\n\n <div className=\"hwped-main\">\n {state.document === null ? (\n <div\n className=\"hwped-canvas\"\n role=\"main\"\n aria-label={t(\"canvas.aria\")}\n >\n <div className=\"hwped-empty\">\n <p>{t(\"canvas.empty\")}</p>\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-primary\"\n onClick={() => setComposing(true)}\n >\n {t(\"canvas.createCta\")}\n </button>\n </div>\n </div>\n ) : (\n <PageCanvas />\n )}\n <aside className=\"hwped-side\" aria-label={t(\"side.panelAria\")}>\n <div className=\"hwped-tabs\" role=\"tablist\">\n {(\n [\n [\"para\", t(\"tabs.para\")],\n [\"table\", t(\"tabs.table\")],\n [\"fields\", t(\"tabs.fields\")],\n ] as [SideTab, string][]\n ).map(([value, label]) => (\n <button\n key={value}\n type=\"button\"\n role=\"tab\"\n aria-selected={tab === value}\n className={\n \"hwped-tab\" + (tab === value ? \" hwped-tab-active\" : \"\")\n }\n onClick={() => setTab(value)}\n >\n {label}\n </button>\n ))}\n </div>\n {tab === \"para\" && <SegmentInspector />}\n {tab === \"table\" && <TableGrid />}\n {tab === \"fields\" && <FieldsPanel />}\n </aside>\n </div>\n\n {composing && (\n <ComposePanel\n onClose={() => setComposing(false)}\n onComposed={(document) => {\n setComposing(false);\n emitChange(document);\n // The host passes the composed document back via `file`; load\n // it directly so the flow also works when the host doesn't.\n void (async () => {\n try {\n const [nextEnvelope, pages] = await Promise.all([\n engine.read(document),\n engine.render(document, RENDER_SVG),\n ]);\n setEnvelope(nextEnvelope);\n store.dispatch({ type: \"load\", document, pages });\n } catch (e) {\n // Covers the render AFTER a successful compose; the\n // compose call itself fails inside ComposePanel.\n setLoadError(toEditorError(e));\n emitError(e);\n }\n })();\n }}\n />\n )}\n </div>\n </HwpEditorContext.Provider>\n );\n },\n);\n","/**\n * Internal React context shared by HwpEditor's panels.\n */\n\nimport { createContext, useContext } from \"react\";\nimport type {\n Capabilities,\n CatEnvelope,\n EditorState,\n EditorStore,\n HwpEngine,\n ValidationReport,\n} from \"@hwp-editor/core\";\nimport type { TFunction } from \"./messages.js\";\n\nexport interface HwpEditorContextValue {\n engine: HwpEngine;\n store: EditorStore;\n /** Current store snapshot (from useSyncExternalStore). */\n state: EditorState;\n /** Last read() envelope for the current document; null before load. */\n envelope: CatEnvelope | null;\n capabilities: Capabilities | null;\n /** False for protected/distribution documents: editing UI is disabled. */\n editable: boolean;\n validation: ValidationReport | null;\n /** Queue of pending ops length convenience. */\n applyPendingOps: () => void;\n /** Re-read + re-render the current document after an external change. */\n refresh: () => Promise<void>;\n /** Open the compose panel (new-document flow). */\n openCompose: () => void;\n /**\n * Message lookup bound to the active locale and host overrides. Every\n * panel localizes through this one channel; a panel that cannot reach `t`\n * cannot be localized at all.\n */\n t: TFunction;\n /**\n * Host error callback, passed straight through from `HwpEditorProps`. A\n * panel that owns its own error state (ComposePanel) has no other way to\n * reach the host; the caught value travels verbatim.\n */\n // `| undefined` is load-bearing under exactOptionalPropertyTypes: the\n // provider spreads the prop through whether or not the host passed one.\n onError?: ((error: unknown) => void) | undefined;\n}\n\nexport const HwpEditorContext = createContext<HwpEditorContextValue | null>(\n null,\n);\n\nexport function useHwpEditorContext(): HwpEditorContextValue {\n const value = useContext(HwpEditorContext);\n if (value === null) {\n throw new Error(\"hwp-editor panels must be rendered inside <HwpEditor>\");\n }\n return value;\n}\n","import { useMemo } from \"react\";\nimport type { JSX, MouseEvent } from \"react\";\nimport type { PageImage, Segment } from \"@hwp-editor/core\";\nimport { base64, segmentAtRef, segmentRef, segmentText } from \"@hwp-editor/core\";\nimport { nearestSegment, segmentBand } from \"./geometry.js\";\nimport { sanitizeSvg } from \"./sanitize.js\";\nimport { plainSegmentText } from \"./text.js\";\nimport { useHwpEditorContext } from \"./context.js\";\n\n/**\n * Multi-page scroll of rendered pages. SVG pages render inline (sanitized);\n * raster formats fall back to <img>. Clicks resolve to the nearest segment\n * (see geometry.ts for the flow-model approximation), and selected/pending\n * segments are highlighted with overlay bands.\n */\nexport function PageCanvas(): JSX.Element {\n const { state, store, envelope, t } = useHwpEditorContext();\n const { pages, selection, pendingOps } = state;\n\n // Segments covered by queued text-targeting ops, highlighted as pending.\n const pendingSegments = useMemo(() => {\n if (envelope === null) return new Set<string>();\n const keys = new Set<string>();\n for (const op of pendingOps) {\n const target = opSearchText(op);\n if (target === null || target === \"\") continue;\n for (const segment of envelope.segments) {\n const plain = plainSegmentText(segmentText(envelope, segment));\n if (plain.includes(target)) {\n keys.add(`${segment.section}:${segment.para}`);\n }\n }\n }\n return keys;\n }, [envelope, pendingOps]);\n\n const selectedSegment =\n envelope !== null && selection !== null\n ? segmentAtRef(envelope, selection)\n : undefined;\n\n if (pages.length === 0) {\n return (\n <div className=\"hwped-canvas\" role=\"main\" aria-label={t(\"canvas.aria\")}>\n <div className=\"hwped-empty\">{t(\"canvas.emptyPages\")}</div>\n </div>\n );\n }\n\n const selectAt = (pageIndex: number, yFraction: number): void => {\n if (envelope === null) return;\n const segment = nearestSegment(envelope, pageIndex, yFraction, pages.length);\n if (segment !== undefined) {\n store.dispatch({ type: \"select\", selection: segmentRef(segment) });\n }\n };\n\n return (\n <div className=\"hwped-canvas\" role=\"main\" aria-label={t(\"canvas.aria\")}>\n {pages.map((page, pageIndex) => (\n <PageView\n key={page.page}\n page={page}\n onClick={(e: MouseEvent<HTMLDivElement>) => {\n const rect = e.currentTarget.getBoundingClientRect();\n selectAt(\n pageIndex,\n rect.height > 0 ? (e.clientY - rect.top) / rect.height : 0.5,\n );\n }}\n onActivate={() => selectAt(pageIndex, 0.5)}\n bands={bandsForPage(\n envelope,\n pageIndex,\n pages.length,\n selectedSegment,\n pendingSegments,\n )}\n />\n ))}\n </div>\n );\n}\n\ninterface Band {\n key: string;\n className: string;\n top: number;\n height: number;\n}\n\nfunction bandsForPage(\n envelope: ReturnType<typeof useHwpEditorContext>[\"envelope\"],\n pageIndex: number,\n pageCount: number,\n selected: Segment | undefined,\n pendingKeys: Set<string>,\n): Band[] {\n if (envelope === null) return [];\n const bands: Band[] = [];\n for (const segment of envelope.segments) {\n const key = `${segment.section}:${segment.para}`;\n const isSelected = selected === segment;\n const isPending = !isSelected && pendingKeys.has(key);\n if (!isSelected && !isPending) continue;\n const band = segmentBand(envelope, segment, pageCount);\n if (band === null || band.pageIndex !== pageIndex) continue;\n bands.push({\n key: `${isSelected ? \"sel\" : \"pend\"}-${key}`,\n className: isSelected\n ? \"hwped-band hwped-band-selected\"\n : \"hwped-band hwped-band-pending\",\n top: band.top,\n height: band.height,\n });\n }\n return bands;\n}\n\nfunction PageView(props: {\n page: PageImage;\n onClick: (e: MouseEvent<HTMLDivElement>) => void;\n onActivate: () => void;\n bands: Band[];\n}): JSX.Element {\n const { page, onClick, onActivate, bands } = props;\n // PageView is only ever rendered inside <HwpEditor>, so it reaches `t`\n // through the context rather than threading a label prop down.\n const { t } = useHwpEditorContext();\n const label = t(\"page.label\", { page: page.page });\n const svgHtml = useMemo(\n () =>\n page.format === \"svg\"\n ? sanitizeSvg(new TextDecoder().decode(page.data))\n : null,\n [page],\n );\n const imgSrc = useMemo(() => {\n if (page.format === \"svg\") return null;\n const mime = page.format === \"jpeg\" ? \"image/jpeg\" : `image/${page.format}`;\n return `data:${mime};base64,${base64.encode(page.data)}`;\n }, [page]);\n\n return (\n <div\n className=\"hwped-page\"\n role=\"button\"\n tabIndex={0}\n aria-label={label}\n style={{ aspectRatio: `${page.width} / ${page.height}` }}\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onActivate();\n }\n }}\n >\n {svgHtml !== null ? (\n <div\n className=\"hwped-page-svg\"\n // Sanitized by sanitizeSvg: script/foreignObject/event handlers removed.\n dangerouslySetInnerHTML={{ __html: svgHtml }}\n />\n ) : (\n <img\n className=\"hwped-page-img\"\n src={imgSrc ?? \"\"}\n alt={label}\n width={page.width}\n height={page.height}\n />\n )}\n {bands.map((band) => (\n <div\n key={band.key}\n className={band.className}\n style={{ top: `${band.top}%`, height: `${band.height}%` }}\n />\n ))}\n </div>\n );\n}\n\n/** The free-text target of an op, when it has one (find/anchor/text). */\nfunction opSearchText(op: {\n kind: string;\n find?: string;\n anchor?: string;\n text?: string;\n}): string | null {\n if (\"find\" in op && typeof op.find === \"string\") return op.find;\n if (\"anchor\" in op && typeof op.anchor === \"string\") return op.anchor;\n if (op.kind === \"delete-para\" && typeof op.text === \"string\") return op.text;\n return null;\n}\n","/**\n * Click hit-testing and highlight placement for PageCanvas.\n *\n * Neither the core segment envelope nor the hwp-cli SVG renderer carries\n * per-paragraph page geometry, so positions are estimated with a linear\n * text-flow model: paragraphs flow in document order across pages\n * proportionally to their markdown length. Clicks map to a global flow\n * fraction, then to the nearest segment via the core coordinate helpers;\n * highlight bands use the exact inverse mapping, so the visual highlight\n * always agrees with what a click would select.\n */\n\nimport type { CatEnvelope, Segment } from \"@hwp-editor/core\";\nimport { segmentAtOffset } from \"@hwp-editor/core\";\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** Resolve a page click to the nearest segment. */\nexport function nearestSegment(\n envelope: CatEnvelope,\n pageIndex: number,\n yFraction: number,\n pageCount: number,\n): Segment | undefined {\n if (envelope.segments.length === 0) return undefined;\n const offset = clickOffset(envelope, pageIndex, yFraction, pageCount);\n const hit = segmentAtOffset(envelope, offset);\n if (hit !== undefined) return hit;\n // Between segments (blank spacing): pick the nearest by start offset.\n let best: Segment | undefined;\n let bestDistance = Number.POSITIVE_INFINITY;\n for (const segment of envelope.segments) {\n const distance = Math.abs(segment.start - offset);\n if (distance < bestDistance) {\n best = segment;\n bestDistance = distance;\n }\n }\n return best;\n}\n\n/** Global markdown offset for a click, in flow order. */\nexport function clickOffset(\n envelope: CatEnvelope,\n pageIndex: number,\n yFraction: number,\n pageCount: number,\n): number {\n const total = Math.max(pageCount, 1);\n const fraction = clamp(\n (clamp(pageIndex, 0, total - 1) + clamp(yFraction, 0, 1)) / total,\n 0,\n 1,\n );\n return Math.round(fraction * envelope.markdown.length);\n}\n\nexport interface SegmentBand {\n /** 0-based page index the band is drawn on. */\n pageIndex: number;\n /** Band top as a percentage of page height. */\n top: number;\n /** Band height as a percentage of page height. */\n height: number;\n}\n\n/**\n * Estimated overlay band for a segment — the inverse of {@link clickOffset},\n * so bands and click hit-testing stay consistent.\n */\nexport function segmentBand(\n envelope: CatEnvelope,\n segment: Segment,\n pageCount: number,\n): SegmentBand | null {\n const length = envelope.markdown.length;\n if (length === 0) return null;\n const total = Math.max(pageCount, 1);\n const center = (segment.start + segment.end) / 2;\n const position = (center / length) * total;\n const pageIndex = clamp(Math.floor(position), 0, total - 1);\n const height = clamp(((segment.end - segment.start) / length) * total * 100, 2, 100);\n const top = clamp((position - pageIndex) * 100 - height / 2, 0, 100 - height);\n return { pageIndex, top, height };\n}\n","/**\n * Minimal SVG sanitizer for inline rendering of `hwp render --format svg`\n * output. The CLI output is trusted, but hosts embedding arbitrary documents\n * get script/foreignObject/event-handler removal for free.\n *\n * Returns \"\" when the payload does not parse as XML.\n */\nexport function sanitizeSvg(svgText: string): string {\n const doc = new DOMParser().parseFromString(svgText, \"image/svg+xml\");\n const root = doc.documentElement;\n if (\n root === null ||\n root.nodeName === \"parsererror\" ||\n doc.getElementsByTagName(\"parsererror\").length > 0\n ) {\n return \"\";\n }\n const dangerous = root.querySelectorAll(\"script, foreignObject\");\n for (const node of Array.from(dangerous)) node.remove();\n scrubElement(root);\n return root.outerHTML;\n}\n\nfunction scrubElement(el: Element): void {\n for (const attr of Array.from(el.attributes)) {\n const name = attr.name.toLowerCase();\n const value = attr.value.trim().toLowerCase();\n if (name.startsWith(\"on\")) {\n el.removeAttribute(attr.name);\n } else if (\n (name === \"href\" || name === \"xlink:href\") &&\n value.startsWith(\"javascript:\")\n ) {\n el.removeAttribute(attr.name);\n }\n }\n for (const child of Array.from(el.children)) scrubElement(child);\n}\n","/**\n * Plain-text extraction for segment markdown slices.\n *\n * `hwp edit` find/anchor arguments match against the document's paragraph\n * text, not the markdown rendering of it — so markers like `#`, `**`, and\n * link syntax must be stripped before a segment's text is used as an op\n * target. This is intentionally conservative: anything unrecognized is kept\n * verbatim (a longer anchor is still a valid anchor).\n */\nexport function plainSegmentText(markdownSlice: string): string {\n return markdownSlice\n .split(\"\\n\")\n .map(stripLine)\n .join(\"\\n\")\n .trim();\n}\n\nfunction stripLine(line: string): string {\n let out = line.trimEnd();\n // ATX heading markers.\n out = out.replace(/^#{1,6}\\s+/, \"\");\n // Links and images: keep the visible label.\n out = out.replace(/!\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\");\n out = out.replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\");\n // Emphasis markers (strong first, then em).\n out = out.replace(/(\\*\\*|__)(.*?)\\1/g, \"$2\");\n out = out.replace(/(\\*|_)(.*?)\\1/g, \"$2\");\n // Inline code backticks.\n out = out.replace(/`([^`]*)`/g, \"$1\");\n return out;\n}\n","import { useEffect, useState } from \"react\";\nimport type { JSX } from \"react\";\nimport type { ParagraphAlignment } from \"@hwp-editor/core\";\nimport { segmentAtRef, segmentText } from \"@hwp-editor/core\";\nimport { plainSegmentText } from \"./text.js\";\nimport { useHwpEditorContext } from \"./context.js\";\nimport type { MessageKey } from \"./messages.js\";\n\n/**\n * Alignment buttons. The array stays at module scope but now carries message\n * KEYS instead of label literals, so the labels resolve through `t()` at\n * render time without reallocating the array on every render.\n */\nconst ALIGNMENTS: { value: ParagraphAlignment; key: MessageKey }[] = [\n { value: \"left\", key: \"segment.alignLeft\" },\n { value: \"center\", key: \"segment.alignCenter\" },\n { value: \"right\", key: \"segment.alignRight\" },\n { value: \"justify\", key: \"segment.alignJustify\" },\n];\n\n/**\n * Inspector for a selected paragraph segment: current text plus op builders\n * (replace, insert before/after, delete, alignment, minimal char-format).\n * All controls queue EditOps; nothing touches the engine until Apply.\n */\nexport function SegmentInspector(): JSX.Element {\n const { state, store, envelope, editable, t } = useHwpEditorContext();\n const { selection } = state;\n\n const segment =\n envelope !== null && selection !== null\n ? segmentAtRef(envelope, selection)\n : undefined;\n const currentText =\n envelope !== null && segment !== undefined\n ? plainSegmentText(segmentText(envelope, segment))\n : \"\";\n\n const [replaceWith, setReplaceWith] = useState(\"\");\n const [insertText, setInsertText] = useState(\"\");\n const [bold, setBold] = useState(false);\n const [fontSize, setFontSize] = useState(\"\");\n const [color, setColor] = useState(\"\");\n\n // Reset drafts when the selection moves.\n useEffect(() => {\n setReplaceWith(\"\");\n setInsertText(\"\");\n setBold(false);\n setFontSize(\"\");\n setColor(\"\");\n }, [selection]);\n\n if (segment === undefined || selection === null) {\n return (\n <div\n className=\"hwped-panel\"\n role=\"region\"\n aria-label={t(\"segment.panelAria\")}\n >\n <p className=\"hwped-hint\">{t(\"segment.hint\")}</p>\n </div>\n );\n }\n\n const find = currentText;\n const disabled = !editable;\n\n return (\n <div\n className=\"hwped-panel\"\n role=\"region\"\n aria-label={t(\"segment.panelAria\")}\n >\n <div className=\"hwped-field\">\n <span className=\"hwped-label\">\n {t(\"segment.selectedPara\", {\n section: selection.section,\n para: selection.para,\n })}\n </span>\n <div className=\"hwped-quote\">\n {currentText || t(\"segment.emptyPara\")}\n </div>\n </div>\n\n <div className=\"hwped-field\">\n <label className=\"hwped-label\" htmlFor=\"hwped-replace\">\n {t(\"segment.replaceLabel\")}\n </label>\n <div className=\"hwped-row\">\n <input\n id=\"hwped-replace\"\n className=\"hwped-input\"\n type=\"text\"\n value={replaceWith}\n disabled={disabled}\n onChange={(e) => setReplaceWith(e.target.value)}\n placeholder={t(\"segment.replacePlaceholder\")}\n />\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled || replaceWith === \"\" || find === \"\"}\n onClick={() =>\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"replace\", find, replace: replaceWith },\n })\n }\n >\n {t(\"segment.replaceSubmit\")}\n </button>\n </div>\n </div>\n\n <div className=\"hwped-field\">\n <label className=\"hwped-label\" htmlFor=\"hwped-insert\">\n {t(\"segment.insertLabel\")}\n </label>\n <textarea\n id=\"hwped-insert\"\n className=\"hwped-textarea\"\n value={insertText}\n disabled={disabled}\n onChange={(e) => setInsertText(e.target.value)}\n placeholder={t(\"segment.insertPlaceholder\")}\n rows={2}\n />\n <div className=\"hwped-row\">\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled || insertText === \"\" || find === \"\"}\n onClick={() =>\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"insert-para-before\", anchor: find, text: insertText },\n })\n }\n >\n {t(\"segment.insertBefore\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled || insertText === \"\" || find === \"\"}\n onClick={() =>\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"insert-para\", anchor: find, text: insertText },\n })\n }\n >\n {t(\"segment.insertAfter\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-danger\"\n disabled={disabled || find === \"\"}\n onClick={() =>\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"delete-para\", text: find },\n })\n }\n >\n {t(\"segment.deletePara\")}\n </button>\n </div>\n </div>\n\n <div className=\"hwped-field\">\n <span className=\"hwped-label\">{t(\"segment.alignLabel\")}</span>\n <div\n className=\"hwped-row\"\n role=\"group\"\n aria-label={t(\"segment.alignGroupAria\")}\n >\n {ALIGNMENTS.map((align) => (\n <button\n key={align.value}\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled || find === \"\"}\n onClick={() =>\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"set-align\", find, alignment: align.value },\n })\n }\n >\n {t(align.key)}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"hwped-field\">\n <span className=\"hwped-label\">{t(\"segment.formatLabel\")}</span>\n <div className=\"hwped-row\">\n <label className=\"hwped-check\">\n <input\n type=\"checkbox\"\n checked={bold}\n disabled={disabled}\n onChange={(e) => setBold(e.target.checked)}\n />\n {t(\"segment.bold\")}\n </label>\n <input\n className=\"hwped-input hwped-input-narrow\"\n type=\"number\"\n min={1}\n value={fontSize}\n disabled={disabled}\n onChange={(e) => setFontSize(e.target.value)}\n placeholder={t(\"segment.sizePlaceholder\")}\n aria-label={t(\"segment.sizeAria\")}\n />\n <input\n className=\"hwped-input hwped-input-narrow\"\n type=\"text\"\n value={color}\n disabled={disabled}\n onChange={(e) => setColor(e.target.value)}\n // A sample hex value, not chrome: never a message key (I18N-05).\n placeholder=\"#FF0000\"\n aria-label={t(\"segment.colorAria\")}\n />\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={\n disabled ||\n find === \"\" ||\n (!bold && fontSize === \"\" && color === \"\")\n }\n onClick={() => {\n const props: Record<string, string> = {};\n if (bold) props[\"bold\"] = \"on\";\n if (fontSize !== \"\") props[\"size\"] = fontSize;\n if (color !== \"\") props[\"color\"] = color;\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"set-format\", find, props },\n });\n }}\n >\n {t(\"segment.formatSubmit\")}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import { useEffect, useState } from \"react\";\nimport type { JSX } from \"react\";\nimport { tableAtRef } from \"./tables.js\";\nimport { plainSegmentText } from \"./text.js\";\nimport { useHwpEditorContext } from \"./context.js\";\n\ninterface CellCoord {\n row: number;\n col: number;\n}\n\n/**\n * Table-aware editor for a selected table segment. The cell grid comes from\n * the GFM table in the read() envelope; addressing follows the CLI's\n * 0-based \"table:row:col\" grammar (row 0 = header row).\n */\nexport function TableGrid(): JSX.Element {\n const { state, store, envelope, editable, t } = useHwpEditorContext();\n const { selection } = state;\n\n const table =\n envelope !== null && selection !== null\n ? tableAtRef(envelope, selection)\n : undefined;\n\n const [cell, setCell] = useState<CellCoord | null>(null);\n const [mergeAnchor, setMergeAnchor] = useState<CellCoord | null>(null);\n const [cellValue, setCellValue] = useState(\"\");\n\n useEffect(() => {\n setCell(null);\n setMergeAnchor(null);\n setCellValue(\"\");\n }, [selection]);\n\n if (table === undefined) {\n return (\n <div\n className=\"hwped-panel\"\n role=\"region\"\n aria-label={t(\"table.panelAria\")}\n >\n <p className=\"hwped-hint\">{t(\"table.hint\")}</p>\n </div>\n );\n }\n\n const disabled = !editable;\n const tableIndex = table.tableIndex;\n const queue = store.dispatch.bind(store);\n\n return (\n <div className=\"hwped-panel\" role=\"region\" aria-label={t(\"table.panelAria\")}>\n <div className=\"hwped-field\">\n <span className=\"hwped-label\">\n {t(\"table.tableLabel\", { index: tableIndex })}\n </span>\n <table className=\"hwped-grid\">\n <tbody>\n {table.rows.map((row, rowIndex) => (\n <tr key={rowIndex}>\n {row.map((text, colIndex) => {\n const active =\n cell !== null &&\n cell.row === rowIndex &&\n cell.col === colIndex;\n const anchor =\n mergeAnchor !== null &&\n mergeAnchor.row === rowIndex &&\n mergeAnchor.col === colIndex;\n return (\n <td key={colIndex}>\n <button\n type=\"button\"\n className={\n \"hwped-cell\" +\n (active ? \" hwped-cell-selected\" : \"\") +\n (anchor ? \" hwped-cell-anchor\" : \"\")\n }\n onClick={() => {\n setCell({ row: rowIndex, col: colIndex });\n setCellValue(plainSegmentText(text));\n }}\n >\n {plainSegmentText(text) || \" \"}\n </button>\n </td>\n );\n })}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n\n {cell !== null && (\n <div className=\"hwped-field\">\n <label className=\"hwped-label\" htmlFor=\"hwped-cell\">\n {t(\"table.cellLabel\", { row: cell.row, col: cell.col })}\n </label>\n <div className=\"hwped-row\">\n <input\n id=\"hwped-cell\"\n className=\"hwped-input\"\n type=\"text\"\n value={cellValue}\n disabled={disabled}\n onChange={(e) => setCellValue(e.target.value)}\n />\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled}\n onClick={() =>\n queue({\n type: \"queueOp\",\n op: {\n kind: \"set-cell\",\n table: tableIndex,\n row: cell.row,\n col: cell.col,\n value: cellValue,\n },\n })\n }\n >\n {t(\"table.setCell\")}\n </button>\n </div>\n <div className=\"hwped-row\">\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled}\n onClick={() => setMergeAnchor({ ...cell })}\n >\n {t(\"table.mergeAnchor\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={\n disabled ||\n mergeAnchor === null ||\n (mergeAnchor.row === cell.row && mergeAnchor.col === cell.col)\n }\n onClick={() => {\n if (mergeAnchor === null) return;\n queue({\n type: \"queueOp\",\n op: {\n kind: \"merge-cells\",\n table: tableIndex,\n r1: Math.min(mergeAnchor.row, cell.row),\n c1: Math.min(mergeAnchor.col, cell.col),\n r2: Math.max(mergeAnchor.row, cell.row),\n c2: Math.max(mergeAnchor.col, cell.col),\n },\n });\n setMergeAnchor(null);\n }}\n >\n {t(\"table.mergeWithAnchor\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled}\n onClick={() =>\n queue({\n type: \"queueOp\",\n op: {\n kind: \"split-cell\",\n table: tableIndex,\n row: cell.row,\n col: cell.col,\n },\n })\n }\n >\n {t(\"table.splitCell\")}\n </button>\n </div>\n </div>\n )}\n\n <div className=\"hwped-field\">\n <span className=\"hwped-label\">{t(\"table.rowsCols\")}</span>\n <div className=\"hwped-row\">\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled}\n onClick={() =>\n queue({\n type: \"queueOp\",\n op:\n cell === null\n ? { kind: \"add-row\", table: tableIndex }\n : { kind: \"add-row\", table: tableIndex, at: cell.row + 1 },\n })\n }\n >\n {t(\"table.addRow\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={disabled}\n onClick={() =>\n queue({\n type: \"queueOp\",\n op:\n cell === null\n ? { kind: \"add-col\", table: tableIndex }\n : { kind: \"add-col\", table: tableIndex, at: cell.col + 1 },\n })\n }\n >\n {t(\"table.addCol\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-danger\"\n disabled={disabled || cell === null}\n onClick={() => {\n if (cell === null) return;\n queue({\n type: \"queueOp\",\n op: { kind: \"delete-row\", table: tableIndex, row: cell.row },\n });\n }}\n >\n {t(\"table.deleteRow\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-danger\"\n disabled={disabled || cell === null}\n onClick={() => {\n if (cell === null) return;\n queue({\n type: \"queueOp\",\n op: { kind: \"delete-col\", table: tableIndex, col: cell.col },\n });\n }}\n >\n {t(\"table.deleteCol\")}\n </button>\n </div>\n </div>\n\n <div className=\"hwped-field\">\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-danger\"\n disabled={disabled}\n onClick={() =>\n queue({\n type: \"queueOp\",\n op: { kind: \"delete-table\", target: tableIndex },\n })\n }\n >\n {t(\"table.deleteTable\")}\n </button>\n </div>\n </div>\n );\n}\n","/**\n * GFM table extraction from the `hwp cat --with-segments` envelope.\n *\n * The CLI emits one para segment per table, covering the whole markdown\n * table block. Table indices are 0-based in document order, matching the\n * `hwp edit --set-cell \"table:row:col=value\"` coordinate grammar; within a\n * table, row 0 is the header row and the `---` separator row is skipped.\n */\n\nimport type { CatEnvelope, Segment, SegmentRef } from \"@hwp-editor/core\";\nimport { segmentText } from \"@hwp-editor/core\";\n\nexport interface TableModel {\n /** 0-based table index in document order (the CLI's `table` coordinate). */\n tableIndex: number;\n /** Segment covering the table block. */\n segment: Segment;\n /**\n * Cell grid. Row 0 is the header row; the markdown separator row is not\n * included. Merged cells cannot be represented in markdown, so spans are\n * flattened to their anchor cell text.\n */\n rows: string[][];\n}\n\n/** True when a segment's markdown slice is a GFM table block. */\nexport function isTableSlice(slice: string): boolean {\n return parseMarkdownTable(slice) !== null;\n}\n\n/** Parse a GFM table slice into a cell grid; null when not a table. */\nexport function parseMarkdownTable(slice: string): string[][] | null {\n const lines = slice\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.startsWith(\"|\") && line.endsWith(\"|\"));\n if (lines.length < 2) return null;\n const rows: string[][] = [];\n let sawSeparator = false;\n for (const line of lines) {\n const cells = line\n .slice(1, -1)\n .split(\"|\")\n .map((cell) => cell.trim());\n if (cells.every((cell) => /^:?-{2,}:?$/.test(cell))) {\n sawSeparator = true;\n continue;\n }\n rows.push(cells);\n }\n return sawSeparator && rows.length > 0 ? rows : null;\n}\n\n/** All tables in the envelope, in document order. */\nexport function findTables(envelope: CatEnvelope): TableModel[] {\n const tables: TableModel[] = [];\n for (const segment of envelope.segments) {\n const rows = parseMarkdownTable(segmentText(envelope, segment));\n if (rows !== null) {\n tables.push({ tableIndex: tables.length, segment, rows });\n }\n }\n return tables;\n}\n\n/** The table whose segment sits at the given source coordinate, if any. */\nexport function tableAtRef(\n envelope: CatEnvelope,\n ref: SegmentRef,\n): TableModel | undefined {\n return findTables(envelope).find(\n (table) =>\n table.segment.section === ref.section && table.segment.para === ref.para,\n );\n}\n","import { useMemo, useState } from \"react\";\nimport type { JSX } from \"react\";\nimport { segmentAtRef, segmentText } from \"@hwp-editor/core\";\nimport { extractFieldSlots } from \"./fields.js\";\nimport { useHwpEditorContext } from \"./context.js\";\n\n/**\n * Lists `{{field}}` placeholder slots found in the read() envelope, with\n * set-field editing and jump-to-segment on click. (The engine contract has\n * no native field/bookmark listing; see fields.ts.)\n */\nexport function FieldsPanel(): JSX.Element {\n const { store, envelope, editable, t } = useHwpEditorContext();\n const [drafts, setDrafts] = useState<Record<string, string>>({});\n\n const slots = useMemo(\n () => (envelope === null ? [] : extractFieldSlots(envelope)),\n [envelope],\n );\n\n if (envelope === null || slots.length === 0) {\n return (\n <div\n className=\"hwped-panel\"\n role=\"region\"\n aria-label={t(\"fields.panelAria\")}\n >\n {/* The `{{name}}` / `{{이름}}` template marker lives inside the\n message value: it is per-locale copy, not a runtime param. */}\n <p className=\"hwped-hint\">{t(\"fields.hint\")}</p>\n </div>\n );\n }\n\n return (\n <div\n className=\"hwped-panel\"\n role=\"region\"\n aria-label={t(\"fields.panelAria\")}\n >\n <ul className=\"hwped-fields\">\n {slots.map((slot) => {\n const segment = segmentAtRef(envelope, slot.segment);\n const snippet =\n segment === undefined\n ? \"\"\n : segmentText(envelope, segment).trim().slice(0, 40);\n const draft = drafts[slot.name] ?? \"\";\n return (\n <li key={slot.name} className=\"hwped-field-item\">\n <div className=\"hwped-row\">\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-link\"\n title={snippet}\n onClick={() =>\n store.dispatch({ type: \"select\", selection: slot.segment })\n }\n >\n {slot.name}\n </button>\n </div>\n <div className=\"hwped-row\">\n <input\n className=\"hwped-input\"\n type=\"text\"\n value={draft}\n disabled={!editable}\n placeholder={t(\"fields.valuePlaceholder\")}\n aria-label={t(\"fields.fieldValueAria\", { name: slot.name })}\n onChange={(e) =>\n setDrafts((prev) => ({ ...prev, [slot.name]: e.target.value }))\n }\n />\n <button\n type=\"button\"\n className=\"hwped-btn\"\n disabled={!editable || draft === \"\"}\n onClick={() =>\n store.dispatch({\n type: \"queueOp\",\n op: { kind: \"set-field\", name: slot.name, value: draft },\n })\n }\n >\n {t(\"fields.setValue\")}\n </button>\n </div>\n </li>\n );\n })}\n </ul>\n </div>\n );\n}\n","/**\n * Field-slot extraction from the read() envelope.\n *\n * The engine contract exposes no field/bookmark registry (that would need\n * `hwp fields` / `hwp bookmarks`), so the fields panel works with template\n * placeholder slots — `{{name}}` markers in the markdown — which map\n * directly onto `hwp edit --set-field \"name=value\"`.\n */\n\nimport type { CatEnvelope, Segment, SegmentRef } from \"@hwp-editor/core\";\nimport { segmentAtOffset } from \"@hwp-editor/core\";\n\nexport interface FieldSlot {\n /** Placeholder name as written between the braces. */\n name: string;\n /** Segment containing the placeholder. */\n segment: SegmentRef;\n}\n\nconst SLOT_PATTERN = /\\{\\{\\s*([^{}]+?)\\s*\\}\\}/g;\n\n/** All `{{name}}` placeholder slots in the envelope, in document order. */\nexport function extractFieldSlots(envelope: CatEnvelope): FieldSlot[] {\n const slots: FieldSlot[] = [];\n const seen = new Set<string>();\n for (const match of envelope.markdown.matchAll(SLOT_PATTERN)) {\n const name = match[1] ?? \"\";\n const offset = match.index ?? 0;\n const segment: Segment | undefined = segmentAtOffset(envelope, offset);\n if (segment === undefined || seen.has(name)) continue;\n seen.add(name);\n slots.push({\n name,\n segment: { section: segment.section, para: segment.para },\n });\n }\n return slots;\n}\n","import { useEffect, useState } from \"react\";\nimport type { JSX } from \"react\";\nimport type { DocumentHandle, EditorError } from \"@hwp-editor/core\";\nimport { ErrorLine } from \"./ErrorLine.js\";\nimport { toEditorError } from \"./errors.js\";\nimport { COMPOSE_PRESETS, buildDocumentSpec } from \"./presets.js\";\nimport type { ComposePreset } from \"./presets.js\";\nimport type { MessageKey } from \"./messages.js\";\nimport { useHwpEditorContext } from \"./context.js\";\n\n/**\n * Preset key -> message key. A typed total Record rather than a\n * template-literal cast: adding an eighth preset must fail `tsc --noEmit`\n * here and force a label decision, which a cast would hide. The preset\n * PROFILES stay in presets.ts as document data (I18N-05).\n */\nconst PRESET_LABEL_KEYS: Record<ComposePreset, MessageKey> = {\n official: \"presets.official\",\n report: \"presets.report\",\n plan: \"presets.plan\",\n notice: \"presets.notice\",\n minutes: \"presets.minutes\",\n gaejosik: \"presets.gaejosik\",\n press: \"presets.press\",\n};\n\nexport interface ComposePanelProps {\n /** Called with the composed document once engine.compose() succeeds. */\n onComposed: (document: DocumentHandle) => void;\n /** Close without composing. */\n onClose: () => void;\n}\n\n/**\n * New-document flow: preset picker + guided form (title, author,\n * markdown-ish sections) → DocumentSpec v2 → engine.compose().\n */\nexport function ComposePanel(props: ComposePanelProps): JSX.Element {\n const { engine, t, onError } = useHwpEditorContext();\n const [preset, setPreset] = useState<ComposePreset>(\"official\");\n const [title, setTitle] = useState(\"\");\n const [author, setAuthor] = useState(\"\");\n const [body, setBody] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<EditorError | null>(null);\n\n // Escape is the way out of a modal, like the Cancel button. It listens on\n // the document because focus is still on the trigger when the dialog\n // opens. It leaves alone an Escape that ends an IME composition (Korean\n // input), one another handler already consumed, and any press while a\n // compose is in flight, the same state that disables Cancel.\n const { onClose } = props;\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key !== \"Escape\" || event.isComposing || event.defaultPrevented) return;\n if (busy) return;\n event.preventDefault();\n onClose();\n };\n document.addEventListener(\"keydown\", onKeyDown);\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [busy, onClose]);\n\n const compose = async (): Promise<void> => {\n setBusy(true);\n setError(null);\n try {\n const spec = buildDocumentSpec(preset, { title, author, body });\n const stem =\n title.trim() === \"\" ? t(\"compose.defaultFileStem\") : title.trim();\n const result = await engine.compose(spec, `${stem}.hwpx`);\n props.onComposed(result.document);\n } catch (e) {\n // Compose is one of the two operations that can refuse with\n // `protected`, so this surface needs the code as much as the editor's.\n setError(toEditorError(e));\n // This panel owns its own error state, so the context passthrough is\n // the only channel by which a compose failure reaches the host.\n onError?.(e);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <div className=\"hwped-overlay\" role=\"presentation\" onClick={props.onClose}>\n <div\n className=\"hwped-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={t(\"compose.title\")}\n onClick={(e) => e.stopPropagation()}\n >\n <h2 className=\"hwped-dialog-title\">{t(\"compose.title\")}</h2>\n\n <div className=\"hwped-field\">\n <span className=\"hwped-label\">{t(\"compose.docType\")}</span>\n <div\n className=\"hwped-presets\"\n role=\"radiogroup\"\n aria-label={t(\"compose.docTypeAria\")}\n >\n {COMPOSE_PRESETS.map((value) => (\n <button\n key={value}\n type=\"button\"\n role=\"radio\"\n aria-checked={preset === value}\n className={\n \"hwped-preset\" +\n (preset === value ? \" hwped-preset-active\" : \"\")\n }\n onClick={() => setPreset(value)}\n >\n {t(PRESET_LABEL_KEYS[value])}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"hwped-field\">\n <label className=\"hwped-label\" htmlFor=\"hwped-compose-title\">\n {t(\"compose.titleLabel\")}\n </label>\n <input\n id=\"hwped-compose-title\"\n className=\"hwped-input\"\n type=\"text\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder={t(\"compose.titlePlaceholder\")}\n />\n </div>\n\n <div className=\"hwped-field\">\n <label className=\"hwped-label\" htmlFor=\"hwped-compose-author\">\n {t(\"compose.authorLabel\")}\n </label>\n <input\n id=\"hwped-compose-author\"\n className=\"hwped-input\"\n type=\"text\"\n value={author}\n onChange={(e) => setAuthor(e.target.value)}\n placeholder={t(\"compose.authorPlaceholder\")}\n />\n </div>\n\n <div className=\"hwped-field\">\n <label className=\"hwped-label\" htmlFor=\"hwped-compose-body\">\n {t(\"compose.bodyLabel\")}\n </label>\n <textarea\n id=\"hwped-compose-body\"\n className=\"hwped-textarea\"\n rows={8}\n value={body}\n onChange={(e) => setBody(e.target.value)}\n placeholder={t(\"compose.bodyPlaceholder\")}\n />\n </div>\n\n {error !== null && (\n <ErrorLine prefix={t(\"error.prefix.compose\")} {...error} />\n )}\n\n <div className=\"hwped-row hwped-dialog-actions\">\n <button\n type=\"button\"\n className=\"hwped-btn\"\n onClick={props.onClose}\n disabled={busy}\n >\n {t(\"compose.cancel\")}\n </button>\n <button\n type=\"button\"\n className=\"hwped-btn hwped-btn-primary\"\n onClick={() => void compose()}\n disabled={busy}\n >\n {busy ? t(\"compose.submitting\") : t(\"compose.submit\")}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","/**\n * Engine error classification for distinct UI states, mapping a failure\n * onto the four states the editor renders distinctly.\n *\n * The stable `HwpErrorCode` carried by `HwpEngineError` (@hwp-editor/core)\n * is the preferred input: `engineErrorKind` consults it first and never\n * reads the prose when it is present. Substring matching over the message\n * is the documented FALLBACK for failures that carry no code — a pre-1.0\n * server, or a maru/Tauri rejection that surfaces only a prefixed string\n * (\"hwped_read failed: cli_missing: ...\"). The markers below are pinned by\n * those engines; `classifyEngineError` stays exported for that path.\n *\n * This module classifies only. The human-readable badge LABELS live in the\n * string table (`error.kind.*` in messages.ts) and are resolved by\n * ErrorLine; nothing here renders text.\n */\n\nimport type { EditorError, HwpErrorCode } from \"@hwp-editor/core\";\nimport { isHwpEngineError, isHwpErrorCode } from \"@hwp-editor/core\";\n\nexport type EngineErrorKind = \"timeout\" | \"unavailable\" | \"protected\" | \"generic\";\n\n/**\n * Build the store/load carrier from an arbitrary thrown value: the code\n * only when the thrower supplied one AND it is a known HwpErrorCode. A\n * duck-typed foreign error (e.g. a Node ErrnoException with code \"ENOENT\")\n * must not leak a non-union string into a field typed as the union; its\n * code is dropped, not remapped — synthesizing `internal` here would be\n * indistinguishable from a real `internal` (see state.ts in core).\n */\nexport function toEditorError(e: unknown): EditorError {\n return isHwpEngineError(e) && isHwpErrorCode(e.code)\n ? { code: e.code, message: e.message }\n : { message: e instanceof Error ? e.message : String(e) };\n}\n\n/**\n * Badge per code. A total Record on purpose, not a switch with a default:\n * adding a sixteenth HwpErrorCode must fail `tsc --noEmit` here and force\n * an explicit badge decision rather than silently rendering \"generic\".\n *\n * `version` maps to `unavailable`: a binary too old and a binary missing\n * are the same problem with the same remedy from the user's seat.\n */\nconst KIND_BY_CODE: Record<HwpErrorCode, EngineErrorKind> = {\n timeout: \"timeout\",\n unavailable: \"unavailable\",\n version: \"unavailable\",\n protected: \"protected\",\n failed: \"generic\",\n bad_request: \"generic\",\n unsupported_format: \"generic\",\n output_too_large: \"generic\",\n cancelled: \"generic\",\n method_not_allowed: \"generic\",\n not_found: \"generic\",\n session_not_found: \"generic\",\n path_traversal: \"generic\",\n forbidden: \"generic\",\n internal: \"generic\",\n};\n\n/**\n * Single entry point: the code wins whenever it is present and known;\n * otherwise fall back to reading the message.\n */\nexport function engineErrorKind(error: {\n code?: string;\n message: string;\n}): EngineErrorKind {\n if (error.code !== undefined && Object.hasOwn(KIND_BY_CODE, error.code)) {\n return KIND_BY_CODE[error.code as HwpErrorCode];\n }\n return classifyEngineError(error.message);\n}\n\nexport function classifyEngineError(message: string): EngineErrorKind {\n const m = message.toLowerCase();\n // CliEngine \"timed out after\", maru \"hwp_timeout:\", HTTP 504.\n if (m.includes(\"timed out\") || m.includes(\"hwp_timeout\") || m.includes(\"http 504\")) {\n return \"timeout\";\n }\n // CliEngine \"binary not found\"/\"is not executable\", maru \"cli_missing:\", HTTP 503.\n if (\n m.includes(\"binary not found\") ||\n m.includes(\"cli_missing\") ||\n m.includes(\"not executable\") ||\n m.includes(\"http 503\")\n ) {\n return \"unavailable\";\n }\n // Protected/distribution documents: the read-only banner covers the\n // capabilities path; this catches edit-time refusals from the CLI.\n if (\n m.includes(\"distribution\") ||\n m.includes(\"encrypted\") ||\n m.includes(\"protected\") ||\n m.includes(\"배포용\")\n ) {\n return \"protected\";\n }\n return \"generic\";\n}\n","/**\n * The one alert surface in this package. Every `role=\"alert\"` the editor\n * renders goes through here, which is what guarantees each of them carries\n * a `data-error-kind` — and gives a later redaction pass (Phase 4 SEC-06)\n * a single place to change.\n *\n * Deliberately NOT exported from index.ts: `packages/react/src/index.ts` is\n * published API at 1.0.0 and nothing outside this package needs it.\n */\n\nimport type { JSX } from \"react\";\nimport { engineErrorKind } from \"./errors.js\";\nimport type { EngineErrorKind } from \"./errors.js\";\nimport { useHwpEditorContext } from \"./context.js\";\nimport type { MessageKey } from \"./messages.js\";\n\n/**\n * Badge label key per kind. A total Record on purpose: a fifth kind must\n * fail `tsc --noEmit` here rather than render an undefined label. The label\n * TEXT lives in the string table; only this kind→key mapping is code.\n */\nconst LABEL_KEY_BY_KIND: Record<EngineErrorKind, MessageKey> = {\n timeout: \"error.kind.timeout\",\n unavailable: \"error.kind.unavailable\",\n protected: \"error.kind.protected\",\n generic: \"error.kind.generic\",\n};\n\n/** One alert line with a distinct kind badge for known engine failures. */\nexport function ErrorLine(props: {\n prefix: string;\n /** Stable HwpErrorCode when the failure carried one; drives the badge. */\n code?: string;\n message: string;\n}): JSX.Element {\n // ErrorLine is always rendered inside <HwpEditor>, so it reaches `t`\n // through the context instead of taking a label prop at both call sites.\n const { t } = useHwpEditorContext();\n const kind = engineErrorKind({\n // Conditional spread: exactOptionalPropertyTypes rejects an explicit\n // `code: undefined` against the optional field.\n ...(props.code !== undefined ? { code: props.code } : {}),\n message: props.message,\n });\n return (\n <p className=\"hwped-error\" role=\"alert\" data-error-kind={kind}>\n {kind !== \"generic\" && (\n <span className={`hwped-error-kind hwped-error-${kind}`}>\n {t(LABEL_KEY_BY_KIND[kind])}\n </span>\n )}\n {props.prefix}: {props.message}\n </p>\n );\n}\n","/**\n * Compose-panel presets → DocumentSpec v2.\n *\n * Profile values mirror hwp-cli's official presets\n * (crates/hwp-convert/src/official.rs): body font, size (1/100 pt there,\n * plain pt here), line spacing percent, and page-number footer policy.\n */\n\nimport type { DocumentSpecV2 } from \"@hwp-editor/core\";\n\nexport type ComposePreset =\n | \"official\"\n | \"report\"\n | \"plan\"\n | \"notice\"\n | \"minutes\"\n | \"gaejosik\"\n | \"press\";\n\nexport const COMPOSE_PRESETS: ComposePreset[] = [\n \"official\",\n \"report\",\n \"plan\",\n \"notice\",\n \"minutes\",\n \"gaejosik\",\n \"press\",\n];\n\ninterface PresetProfile {\n fontFamily: string;\n bodySizePt: number;\n lineHeightPercent: number;\n pageNumber: boolean;\n}\n\n/**\n * Document data, NOT chrome (I18N-05). These font names travel into the\n * composed DocumentSpec and are consumed by hwp-cli; translating them would\n * change what the engine receives, so they stay here and are structurally\n * unreachable from the string table. The picker's human-readable LABELS\n * live in messages.ts under `presets.*`.\n */\nconst MALGUN = \"맑은 고딕\";\nconst HCR_BATANG = \"함초롬바탕\";\n\nconst PRESET_PROFILES: Record<ComposePreset, PresetProfile> = {\n official: { fontFamily: MALGUN, bodySizePt: 12, lineHeightPercent: 160, pageNumber: false },\n report: { fontFamily: HCR_BATANG, bodySizePt: 15, lineHeightPercent: 160, pageNumber: true },\n plan: { fontFamily: HCR_BATANG, bodySizePt: 15, lineHeightPercent: 160, pageNumber: true },\n notice: { fontFamily: MALGUN, bodySizePt: 15, lineHeightPercent: 160, pageNumber: true },\n minutes: { fontFamily: HCR_BATANG, bodySizePt: 14, lineHeightPercent: 130, pageNumber: false },\n gaejosik: { fontFamily: MALGUN, bodySizePt: 15, lineHeightPercent: 160, pageNumber: true },\n press: { fontFamily: HCR_BATANG, bodySizePt: 14, lineHeightPercent: 160, pageNumber: true },\n};\n\nexport interface ComposeInput {\n title: string;\n author: string;\n /**\n * Markdown-ish body: blank lines separate paragraphs; a line starting\n * with \"# \" becomes a heading-styled paragraph.\n */\n body: string;\n}\n\ntype ParagraphBlock = {\n type: \"paragraph\";\n style?: string;\n runs: [{ type: \"text\"; text: string }];\n};\n\n/** Parse the guided-form body text into paragraph blocks. */\nexport function bodyToBlocks(body: string): ParagraphBlock[] {\n const blocks: ParagraphBlock[] = [];\n for (const chunk of body.split(/\\n\\s*\\n/)) {\n const text = chunk.trim();\n if (text === \"\") continue;\n if (text.startsWith(\"# \")) {\n blocks.push({\n type: \"paragraph\",\n style: \"heading\",\n runs: [{ type: \"text\", text: text.slice(2).trim() }],\n });\n } else {\n blocks.push({\n type: \"paragraph\",\n style: \"body\",\n runs: [{ type: \"text\", text }],\n });\n }\n }\n return blocks;\n}\n\n/** Build the DocumentSpec v2 for a preset + guided form input. */\nexport function buildDocumentSpec(\n preset: ComposePreset,\n input: ComposeInput,\n): DocumentSpecV2 {\n const profile = PRESET_PROFILES[preset];\n const blocks: ParagraphBlock[] = [];\n if (input.title.trim() !== \"\") {\n blocks.push({\n type: \"paragraph\",\n style: \"title\",\n runs: [{ type: \"text\", text: input.title.trim() }],\n });\n }\n blocks.push(...bodyToBlocks(input.body));\n if (blocks.length === 0) {\n blocks.push({\n type: \"paragraph\",\n style: \"body\",\n runs: [{ type: \"text\", text: \" \" }],\n });\n }\n const section = {\n ...(profile.pageNumber\n ? { page_number: { position: \"bottom_center\" as const } }\n : {}),\n blocks,\n };\n return {\n version: \"2.0\",\n document: {\n version: \"1.0\",\n metadata: {\n ...(input.title.trim() !== \"\" ? { title: input.title.trim() } : {}),\n ...(input.author.trim() !== \"\" ? { author: input.author.trim() } : {}),\n },\n styles: {\n body: {\n font_family: profile.fontFamily,\n font_size_pt: profile.bodySizePt,\n line_height_percent: profile.lineHeightPercent,\n align: \"justify\",\n },\n heading: {\n font_family: profile.fontFamily,\n font_size_pt: profile.bodySizePt + 3,\n bold: true,\n spacing_before_pt: 13,\n spacing_after_pt: 6,\n },\n title: {\n font_family: profile.fontFamily,\n font_size_pt: profile.bodySizePt + 6,\n bold: true,\n align: \"center\",\n spacing_after_pt: 18,\n },\n },\n sections: [section],\n },\n };\n}\n","/**\n * The editor's string table: one flat `<area>.<thing>` key map per locale,\n * plus the `t()` factory that merges them.\n *\n * Contract (published API at 1.0.0 — a key rename is a breaking change):\n *\n * - `en` is canonical and is the default when no `locale` is given. It is\n * declared WITHOUT `as const` so its values widen to `string` / function\n * signatures; `const ko: MessageTable` then makes a key missing from\n * EITHER table a `tsc` error (a missing key is a required-property error,\n * an extra key an excess-property one). That two-way parity is the whole\n * reason for the `typeof en` spelling — a plain `Record<..., string>`\n * would widen every value to the union and lose per-key parameter types.\n * - Count-bearing messages are FUNCTION values taking a single named-params\n * object, never positional args and never a runtime `{count}` template.\n * Interpolation happens inside the function body, so word order is a\n * per-locale choice and English can carry a real plural branch.\n * - Merge order is `en` -> locale table -> host `messages`. An override\n * replaces exactly one key; every other key falls through to the locale\n * default. Lookup is exact string equality with no normalization.\n *\n * NOT in this table, deliberately (I18N-05): font names, preset profiles,\n * the `#FF0000` placeholder sample, and the engine's `{message}` error tail.\n * Those are document data or engine-authored prose — translating them would\n * change what hwp-cli receives or rewrite what the engine actually said.\n */\n\nexport const en = {\n // Toolbar\n \"toolbar.toolsAria\": \"Editing tools\",\n \"toolbar.readOnly\": \"Read-only\",\n \"toolbar.pendingEdits\": (p: { count: number }): string =>\n p.count === 1 ? \"1 pending edit\" : `${p.count} pending edits`,\n \"toolbar.revert\": \"Undo edit\",\n \"toolbar.apply\": \"Apply\",\n \"toolbar.applyWithCount\": (p: { count: number }): string =>\n `Apply (${p.count})`,\n \"toolbar.applying\": \"Applying…\",\n \"toolbar.newDocument\": \"New document\",\n\n // Validation badge\n \"validation.aria\": \"Validation result\",\n \"validation.valid\": \"Valid\",\n \"validation.errors\": (p: { count: number }): string =>\n p.count === 1 ? \"1 error\" : `${p.count} errors`,\n\n // Canvas\n \"canvas.aria\": \"Document pages\",\n \"canvas.empty\": \"No document open.\",\n \"canvas.createCta\": \"Create a new document\",\n \"canvas.emptyPages\": \"No rendered pages.\",\n \"page.label\": (p: { page: number }): string => `Page ${p.page}`,\n\n // Side panel shell\n \"side.panelAria\": \"Editing panels\",\n \"tabs.para\": \"Paragraph\",\n \"tabs.table\": \"Table\",\n \"tabs.fields\": \"Fields\",\n\n // Error line — the prefix names which operation failed. The `{message}`\n // tail stays engine-authored and is never translated.\n \"error.prefix.load\": \"Failed to open document\",\n \"error.prefix.apply\": \"Failed to apply edits\",\n \"error.prefix.compose\": \"Failed to create document\",\n // Badge labels; \"generic\" renders no chip, hence the empty string.\n \"error.kind.timeout\": \"Engine timed out\",\n \"error.kind.unavailable\": \"hwp binary unavailable\",\n \"error.kind.protected\": \"Protected document\",\n \"error.kind.generic\": \"\",\n\n // Compose dialog\n \"compose.title\": \"Create a new document\",\n \"compose.docType\": \"Document type\",\n \"compose.docTypeAria\": \"Document type\",\n \"compose.titleLabel\": \"Title\",\n \"compose.titlePlaceholder\": \"Document title\",\n \"compose.authorLabel\": \"Author\",\n \"compose.authorPlaceholder\": \"Author (optional)\",\n \"compose.bodyLabel\": \"Body\",\n \"compose.bodyPlaceholder\":\n \"Blank lines separate paragraphs. Lines starting with '# ' become subheadings.\\n\\nExample:\\n# 1. Overview\\nBody text...\",\n \"compose.cancel\": \"Cancel\",\n \"compose.submit\": \"Create document\",\n \"compose.submitting\": \"Creating…\",\n /** Filename stem used when the compose form has no title. */\n \"compose.defaultFileStem\": \"New document\",\n\n // Compose preset labels. The preset PROFILES (font names, sizes) are\n // document data and stay in presets.ts, untranslated.\n \"presets.official\": \"Official document\",\n \"presets.report\": \"Report\",\n \"presets.plan\": \"Plan\",\n \"presets.notice\": \"Notice\",\n \"presets.minutes\": \"Minutes\",\n \"presets.gaejosik\": \"Outline document\",\n \"presets.press\": \"Press release\",\n\n // SegmentInspector\n \"segment.panelAria\": \"Paragraph editor\",\n \"segment.hint\": \"Click the page to select a paragraph to edit.\",\n \"segment.selectedPara\": (p: { section: number; para: number }): string =>\n `Selected paragraph (section ${p.section}, paragraph ${p.para})`,\n \"segment.emptyPara\": \"(empty paragraph)\",\n \"segment.replaceLabel\": \"Replace text\",\n \"segment.replacePlaceholder\": \"New text\",\n \"segment.replaceSubmit\": \"Replace\",\n \"segment.insertLabel\": \"Insert paragraph\",\n \"segment.insertPlaceholder\": \"Paragraph text to insert\",\n \"segment.insertBefore\": \"Insert before\",\n \"segment.insertAfter\": \"Insert after\",\n \"segment.deletePara\": \"Delete paragraph\",\n \"segment.alignLabel\": \"Alignment\",\n \"segment.alignGroupAria\": \"Paragraph alignment\",\n \"segment.alignLeft\": \"Left\",\n \"segment.alignCenter\": \"Center\",\n \"segment.alignRight\": \"Right\",\n \"segment.alignJustify\": \"Justify\",\n \"segment.formatLabel\": \"Character format\",\n \"segment.bold\": \"Bold\",\n \"segment.sizePlaceholder\": \"Size (pt)\",\n \"segment.sizeAria\": \"Font size (pt)\",\n \"segment.colorAria\": \"Font color\",\n \"segment.formatSubmit\": \"Apply format\",\n\n // TableGrid\n \"table.panelAria\": \"Table editor\",\n \"table.hint\":\n \"Select a region containing a table on the page. The current selection is not a table paragraph.\",\n \"table.tableLabel\": (p: { index: number }): string => `Table #${p.index}`,\n \"table.cellLabel\": (p: { row: number; col: number }): string =>\n `Cell (${p.row}, ${p.col})`,\n \"table.setCell\": \"Set cell\",\n \"table.mergeAnchor\": \"Set merge anchor\",\n \"table.mergeWithAnchor\": \"Merge with anchor\",\n \"table.splitCell\": \"Split cell\",\n \"table.rowsCols\": \"Rows / columns\",\n \"table.addRow\": \"Add row\",\n \"table.addCol\": \"Add column\",\n \"table.deleteRow\": \"Delete row\",\n \"table.deleteCol\": \"Delete column\",\n \"table.deleteTable\": \"Delete table\",\n\n // FieldsPanel\n \"fields.panelAria\": \"Fields\",\n \"fields.hint\": \"No {{name}} field placeholders were found in the document.\",\n \"fields.valuePlaceholder\": \"New value\",\n \"fields.fieldValueAria\": (p: { name: string }): string =>\n `Value for field ${p.name}`,\n \"fields.setValue\": \"Set value\",\n};\n\n/** The shape both locale tables must satisfy, derived from canonical `en`. */\nexport type MessageTable = typeof en;\n/** Every valid `t()` key. */\nexport type MessageKey = keyof MessageTable;\n/** Host-supplied per-key overrides; unknown keys are a `tsc` error. */\nexport type HwpEditorMessages = Partial<MessageTable>;\n/** Supported UI locales. Mount-time only — runtime switching is not supported. */\nexport type Locale = \"en\" | \"ko\";\n\n/**\n * Korean chrome. These are the literals that already shipped, carried over\n * VERBATIM (including the `...` in-progress convention, where English uses\n * a single `…`) — they are correct and the existing suite pins them.\n */\nexport const ko: MessageTable = {\n \"toolbar.toolsAria\": \"편집 도구\",\n \"toolbar.readOnly\": \"읽기 전용\",\n \"toolbar.pendingEdits\": (p) => `대기 편집 ${p.count}`,\n \"toolbar.revert\": \"되돌리기\",\n \"toolbar.apply\": \"적용\",\n \"toolbar.applyWithCount\": (p) => `적용 (${p.count})`,\n \"toolbar.applying\": \"적용 중...\",\n \"toolbar.newDocument\": \"새 문서\",\n\n \"validation.aria\": \"검증 결과\",\n \"validation.valid\": \"유효\",\n \"validation.errors\": (p) => `오류 ${p.count}건`,\n\n \"canvas.aria\": \"문서 페이지\",\n \"canvas.empty\": \"열린 문서가 없습니다.\",\n \"canvas.createCta\": \"새 문서 만들기\",\n \"canvas.emptyPages\": \"렌더링된 페이지가 없습니다.\",\n \"page.label\": (p) => `페이지 ${p.page}`,\n\n \"side.panelAria\": \"편집 패널\",\n \"tabs.para\": \"문단\",\n \"tabs.table\": \"표\",\n \"tabs.fields\": \"필드\",\n\n \"error.prefix.load\": \"문서 열기 실패\",\n \"error.prefix.apply\": \"편집 적용 실패\",\n \"error.prefix.compose\": \"문서 생성 실패\",\n \"error.kind.timeout\": \"엔진 시간 초과\",\n \"error.kind.unavailable\": \"hwp 실행 파일 없음\",\n \"error.kind.protected\": \"보호/배포 문서\",\n \"error.kind.generic\": \"\",\n\n \"compose.title\": \"새 문서 만들기\",\n \"compose.docType\": \"문서 유형\",\n \"compose.docTypeAria\": \"문서 유형\",\n \"compose.titleLabel\": \"제목\",\n \"compose.titlePlaceholder\": \"문서 제목\",\n \"compose.authorLabel\": \"작성자\",\n \"compose.authorPlaceholder\": \"작성자 (선택)\",\n \"compose.bodyLabel\": \"본문\",\n \"compose.bodyPlaceholder\":\n \"빈 줄로 문단을 구분합니다. '# '로 시작하는 줄은 소제목이 됩니다.\\n\\n예)\\n# 1. 개요\\n본문 내용...\",\n \"compose.cancel\": \"취소\",\n \"compose.submit\": \"문서 생성\",\n \"compose.submitting\": \"생성 중...\",\n \"compose.defaultFileStem\": \"새 문서\",\n\n \"presets.official\": \"공문\",\n \"presets.report\": \"보고서\",\n \"presets.plan\": \"계획서\",\n \"presets.notice\": \"안내문\",\n \"presets.minutes\": \"회의록\",\n \"presets.gaejosik\": \"개조식 문서\",\n \"presets.press\": \"보도자료\",\n\n \"segment.panelAria\": \"문단 편집\",\n \"segment.hint\": \"페이지를 클릭해 편집할 문단을 선택하세요.\",\n \"segment.selectedPara\": (p) => `선택 문단 (구역 ${p.section}, 문단 ${p.para})`,\n \"segment.emptyPara\": \"(빈 문단)\",\n \"segment.replaceLabel\": \"텍스트 교체\",\n \"segment.replacePlaceholder\": \"새 텍스트\",\n \"segment.replaceSubmit\": \"교체\",\n \"segment.insertLabel\": \"문단 삽입\",\n \"segment.insertPlaceholder\": \"삽입할 문단 텍스트\",\n \"segment.insertBefore\": \"앞에 삽입\",\n \"segment.insertAfter\": \"뒤에 삽입\",\n \"segment.deletePara\": \"문단 삭제\",\n \"segment.alignLabel\": \"정렬\",\n \"segment.alignGroupAria\": \"문단 정렬\",\n \"segment.alignLeft\": \"왼쪽\",\n \"segment.alignCenter\": \"가운데\",\n \"segment.alignRight\": \"오른쪽\",\n \"segment.alignJustify\": \"양쪽\",\n \"segment.formatLabel\": \"글자 서식\",\n \"segment.bold\": \"굵게\",\n \"segment.sizePlaceholder\": \"크기(pt)\",\n \"segment.sizeAria\": \"글자 크기(pt)\",\n \"segment.colorAria\": \"글자 색상\",\n \"segment.formatSubmit\": \"서식 적용\",\n\n \"table.panelAria\": \"표 편집\",\n \"table.hint\":\n \"표가 포함된 영역을 페이지에서 선택하세요. 표가 아닌 문단이 선택되어 있습니다.\",\n \"table.tableLabel\": (p) => `표 #${p.index}`,\n \"table.cellLabel\": (p) => `셀 (${p.row}, ${p.col})`,\n \"table.setCell\": \"셀 설정\",\n \"table.mergeAnchor\": \"병합 기준 지정\",\n \"table.mergeWithAnchor\": \"기준 셀과 병합\",\n \"table.splitCell\": \"셀 분할\",\n \"table.rowsCols\": \"행/열\",\n \"table.addRow\": \"행 추가\",\n \"table.addCol\": \"열 추가\",\n \"table.deleteRow\": \"행 삭제\",\n \"table.deleteCol\": \"열 삭제\",\n \"table.deleteTable\": \"표 삭제\",\n\n \"fields.panelAria\": \"필드\",\n \"fields.hint\": \"문서에서 {{이름}} 형태의 필드 자리표시자를 찾지 못했습니다.\",\n \"fields.valuePlaceholder\": \"새 값\",\n \"fields.fieldValueAria\": (p) => `필드 ${p.name} 값`,\n \"fields.setValue\": \"설정\",\n};\n\n/**\n * Lookup function. Keys with a function value REQUIRE their params object;\n * plain-string keys accept no second argument — both enforced per key by\n * the conditional variadic below, so a missing or wrong params object is a\n * compile error at the call site.\n */\nexport type TFunction = <K extends MessageKey>(\n key: K,\n ...args: MessageTable[K] extends (p: infer P) => string ? [params: P] : []\n) => string;\n\n/**\n * Build a `t()` bound to one locale and one set of host overrides.\n * Merge order: `en` -> locale table -> `messages` (last wins, per key).\n */\nexport function createT(\n locale: Locale,\n messages?: HwpEditorMessages,\n): TFunction {\n const table: MessageTable = {\n ...en,\n ...(locale === \"ko\" ? ko : {}),\n ...messages,\n };\n // The cast is contained here: the public TFunction signature still gives\n // call sites full per-key parameter checking.\n return ((key: MessageKey, params?: unknown): string => {\n const value = table[key];\n return typeof value === \"function\"\n ? (value as (p: unknown) => string)(params)\n : value;\n }) as TFunction;\n}\n"],"mappings":"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","names":["import_react","import_core","import_react","import_core","import_react","import_core","import_jsx_runtime","import_react","import_core","import_jsx_runtime","import_react","import_core","import_core","import_jsx_runtime","import_react","import_core","import_jsx_runtime","import_jsx_runtime","import_core","import_jsx_runtime","HwpEditor","document","dirty"]}