@hwp-editor/react 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.css CHANGED
@@ -417,17 +417,11 @@
417
417
  outline: 2px solid var(--hwped-accent);
418
418
  outline-offset: 3px;
419
419
  }
420
- .hwped-page-svg,
421
420
  .hwped-page-img {
422
421
  display: block;
423
422
  width: 100%;
424
423
  height: 100%;
425
424
  }
426
- .hwped-page-svg > svg {
427
- display: block;
428
- width: 100%;
429
- height: auto;
430
- }
431
425
  .hwped-band {
432
426
  position: absolute;
433
427
  left: 0;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/theme.css","../src/editor.css"],"sourcesContent":["/**\n * Theme contract for @hwp-editor/react. Hosts theme the editor ONLY by\n * overriding these variables on the editor root or any ancestor:\n *\n * --hwped-bg surface background\n * --hwped-fg primary text\n * --hwped-muted secondary text / disabled\n * --hwped-accent primary actions, selection\n * --hwped-border hairline borders\n * --hwped-error destructive / error text and badges\n * --hwped-warning transient warning (timeout badge only)\n * --hwped-success success badge\n * --hwped-radius corner radius\n * --hwped-font font stack (default: Pretendard -> system)\n *\n * Defaults below include a prefers-color-scheme dark fallback.\n */\n\n.hwped {\n --hwped-bg: #ffffff;\n --hwped-fg: #1a1d21;\n --hwped-muted: #6b7280;\n --hwped-accent: #1f5fbf;\n --hwped-border: #d7dbe0;\n --hwped-error: #b91c1c;\n --hwped-warning: #a16207;\n --hwped-success: #15803d;\n --hwped-radius: 6px;\n --hwped-font:\n \"Pretendard\", \"Pretendard Variable\", \"Malgun Gothic\", \"맑은 고딕\",\n -apple-system, \"Segoe UI\", Roboto, \"Noto Sans KR\", sans-serif;\n}\n\n@media (prefers-color-scheme: dark) {\n .hwped {\n --hwped-bg: #17191d;\n --hwped-fg: #e5e7eb;\n --hwped-muted: #9ca3af;\n --hwped-accent: #5b8def;\n --hwped-border: #33373f;\n /* Lifted for >= 4.5:1 against --hwped-bg at 11-13px. */\n --hwped-error: #f87171;\n --hwped-warning: #fbbf24;\n --hwped-success: #4ade80;\n }\n}\n","/**\n * Scoped stylesheet for @hwp-editor/react. Every class carries the `hwped`\n * prefix; the root element gets `.hwped.hwped-root`. No global selectors,\n * no component-kit assumptions.\n *\n * Design notes (HIG-derived, #34): depth comes from tone and shadow rather\n * than extra lines; every control answers on press, not on release; status\n * is tinted by kind; motion is short, and dropped under reduced motion.\n *\n * Every tone below is DERIVED from the public --hwped-* tokens with\n * color-mix, so a host that maps those tokens (light or dark) gets the whole\n * palette. The --_hwped-* names are private and not part of the contract.\n */\n\n.hwped {\n --_hwped-desk: color-mix(in srgb, var(--hwped-fg) 5%, var(--hwped-bg));\n --_hwped-fill: color-mix(in srgb, var(--hwped-fg) 7%, var(--hwped-bg));\n --_hwped-hover: color-mix(in srgb, var(--hwped-accent) 9%, var(--hwped-bg));\n --_hwped-press: color-mix(in srgb, var(--hwped-accent) 16%, var(--hwped-bg));\n --_hwped-hairline: color-mix(in srgb, var(--hwped-border) 75%, transparent);\n --_hwped-ring: 0 0 0 3px color-mix(in srgb, var(--hwped-accent) 35%, transparent);\n --_hwped-quick: 100ms ease-out;\n\n background: var(--hwped-bg);\n color: var(--hwped-fg);\n font-family: var(--hwped-font);\n font-size: 13px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n}\n\n.hwped *,\n.hwped *::before,\n.hwped *::after {\n box-sizing: border-box;\n}\n\n.hwped-root {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 320px;\n border: 1px solid var(--hwped-border);\n border-radius: var(--hwped-radius);\n overflow: hidden;\n}\n\n/* ---- toolbar ---- */\n\n.hwped-toolbar {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 44px;\n padding: 6px 12px;\n border-bottom: 1px solid var(--_hwped-hairline);\n background: var(--hwped-bg);\n flex: 0 0 auto;\n position: relative;\n z-index: 1;\n}\n\n.hwped-title {\n font-weight: 600;\n letter-spacing: -0.01em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 40%;\n}\n\n.hwped-spacer {\n flex: 1 1 auto;\n}\n\n/* The title and this notice are the only toolbar items that may shrink: a\n long engine reason truncates here (the full text stays reachable via the\n element's title attribute) instead of being distributed across the badge,\n count and buttons, which would collapse them to min-content and stack the\n row. That is why every sibling below carries `flex: 0 0 auto` (G-03-1). */\n.hwped-notice {\n color: var(--hwped-muted);\n background: var(--_hwped-fill);\n border-radius: 999px;\n padding: 2px 10px;\n font-size: 12px;\n letter-spacing: 0.01em;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 0 1 auto;\n}\n\n/* Status reads by kind, not by outline: a tinted pill in the kind's color. */\n.hwped-badge {\n border-radius: 999px;\n padding: 2px 10px;\n font-size: 12px;\n font-weight: 600;\n letter-spacing: 0.01em;\n border: 1px solid transparent;\n background: var(--_hwped-fill);\n flex: 0 0 auto;\n}\n\n.hwped-badge-ok {\n color: var(--hwped-success);\n background: color-mix(in srgb, var(--hwped-success) 14%, transparent);\n}\n\n.hwped-badge-err {\n color: var(--hwped-error);\n background: color-mix(in srgb, var(--hwped-error) 14%, transparent);\n}\n\n.hwped-count {\n color: var(--hwped-muted);\n font-size: 12px;\n letter-spacing: 0.01em;\n font-variant-numeric: tabular-nums;\n flex: 0 0 auto;\n}\n\n/* ---- buttons / inputs ---- */\n\n.hwped-btn {\n font: inherit;\n font-weight: 500;\n color: var(--hwped-fg);\n background: var(--hwped-bg);\n border: 1px solid var(--hwped-border);\n border-radius: var(--hwped-radius);\n min-height: 28px;\n padding: 3px 12px;\n cursor: pointer;\n transition:\n background-color var(--_hwped-quick),\n border-color var(--_hwped-quick),\n transform var(--_hwped-quick);\n}\n\n.hwped-btn:hover:not(:disabled) {\n background: var(--_hwped-hover);\n border-color: color-mix(in srgb, var(--hwped-accent) 55%, var(--hwped-border));\n}\n\n/* Feedback on press, instantly - never only on release. */\n.hwped-btn:active:not(:disabled) {\n background: var(--_hwped-press);\n transform: scale(0.97);\n}\n\n.hwped-btn:disabled {\n color: var(--hwped-muted);\n background: transparent;\n border-color: var(--_hwped-hairline);\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.hwped-btn-primary {\n background: var(--hwped-accent);\n border-color: var(--hwped-accent);\n color: #ffffff;\n font-weight: 600;\n}\n\n.hwped-btn-primary:hover:not(:disabled) {\n background: color-mix(in srgb, var(--hwped-accent) 88%, #000000);\n border-color: color-mix(in srgb, var(--hwped-accent) 88%, #000000);\n}\n\n.hwped-btn-primary:active:not(:disabled) {\n background: color-mix(in srgb, var(--hwped-accent) 78%, #000000);\n}\n\n/* A disabled primary keeps a trace of its accent, but must not read as live. */\n.hwped-btn-primary:disabled {\n color: var(--hwped-muted);\n background: color-mix(in srgb, var(--hwped-accent) 14%, var(--hwped-bg));\n border-color: transparent;\n opacity: 1;\n}\n\n/* Destructive reads as destructive at rest, not only on hover. */\n.hwped-btn-danger {\n color: var(--hwped-error);\n}\n\n.hwped-btn-danger:hover:not(:disabled) {\n border-color: var(--hwped-error);\n color: var(--hwped-error);\n background: color-mix(in srgb, var(--hwped-error) 9%, var(--hwped-bg));\n}\n\n.hwped-btn-link {\n border: none;\n background: none;\n min-height: 0;\n padding: 0;\n color: var(--hwped-accent);\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.hwped-btn-link:hover:not(:disabled) {\n background: none;\n}\n\n/* Scoped to direct toolbar children on purpose: `.hwped-btn` is reused by\n SegmentInspector, TableGrid, FieldsPanel, the compose dialog actions and\n the empty-state button, where non-shrinkable buttons would trade this bug\n for horizontal overflow in those narrow rows. */\n.hwped-toolbar > .hwped-btn {\n flex: 0 0 auto;\n}\n\n.hwped-input,\n.hwped-textarea {\n font: inherit;\n color: var(--hwped-fg);\n background: var(--hwped-bg);\n border: 1px solid var(--hwped-border);\n border-radius: var(--hwped-radius);\n min-height: 28px;\n padding: 4px 9px;\n width: 100%;\n transition:\n border-color var(--_hwped-quick),\n box-shadow var(--_hwped-quick);\n}\n\n.hwped-input::placeholder,\n.hwped-textarea::placeholder {\n color: var(--hwped-muted);\n opacity: 0.8;\n}\n\n.hwped-input:hover:not(:disabled),\n.hwped-textarea:hover:not(:disabled) {\n border-color: color-mix(in srgb, var(--hwped-fg) 30%, var(--hwped-border));\n}\n\n/* One focus treatment everywhere: accent edge plus a soft ring. */\n.hwped-input:focus,\n.hwped-textarea:focus {\n outline: none;\n border-color: var(--hwped-accent);\n box-shadow: var(--_hwped-ring);\n}\n\n.hwped-btn:focus-visible,\n.hwped-tab:focus-visible,\n.hwped-preset:focus-visible,\n.hwped-cell:focus-visible {\n outline: none;\n box-shadow: var(--_hwped-ring);\n}\n\n.hwped-input-narrow {\n width: 96px;\n flex: 0 0 auto;\n}\n\n.hwped-check {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n}\n\n.hwped-check input {\n accent-color: var(--hwped-accent);\n}\n\n/* ---- layout ---- */\n\n.hwped-pending-list {\n flex: 0 1 auto;\n min-height: 0;\n max-height: 120px;\n overflow: auto;\n overflow-wrap: anywhere;\n}\n\n.hwped-main {\n display: flex;\n flex: 1 1 auto;\n min-height: 0;\n}\n\n/* The desk: a tone below the chrome, so the page reads as a sheet on it. */\n.hwped-canvas {\n flex: 1 1 auto;\n overflow: auto;\n padding: 24px;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 24px;\n background: var(--_hwped-desk);\n}\n\n.hwped-side {\n flex: 0 0 300px;\n border-left: 1px solid var(--_hwped-hairline);\n background: var(--hwped-bg);\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n/* Tabs as a segmented control: a recessed track, the active segment raised. */\n.hwped-tabs {\n display: flex;\n flex-wrap: wrap;\n gap: 2px;\n margin: 10px 12px 2px;\n padding: 3px;\n background: var(--_hwped-fill);\n border-radius: calc(var(--hwped-radius) + 2px);\n flex: 0 0 auto;\n}\n\n.hwped-tab {\n font: inherit;\n font-weight: 500;\n flex: 1 1 78px;\n min-width: 0;\n min-height: 26px;\n padding: 3px 0;\n background: none;\n border: none;\n border-radius: var(--hwped-radius);\n color: var(--hwped-muted);\n cursor: pointer;\n transition:\n background-color var(--_hwped-quick),\n color var(--_hwped-quick),\n transform var(--_hwped-quick);\n}\n\n.hwped-tab:hover:not(.hwped-tab-active) {\n color: var(--hwped-fg);\n}\n\n.hwped-tab:active {\n transform: scale(0.97);\n}\n\n.hwped-tab-active {\n color: var(--hwped-fg);\n background: var(--hwped-bg);\n font-weight: 600;\n box-shadow:\n 0 1px 2px rgba(0, 0, 0, 0.12),\n 0 0 0 0.5px rgba(0, 0, 0, 0.06);\n}\n\n.hwped-panel {\n padding: 12px;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.hwped-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.hwped-label {\n font-size: 12px;\n font-weight: 600;\n letter-spacing: 0.01em;\n line-height: 1.35;\n color: color-mix(in srgb, var(--hwped-fg) 72%, var(--hwped-bg));\n}\n\n.hwped-row {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n/* A role=\"group\" row of peer actions (alignment) reads as one joined control. */\n.hwped-row[role=\"group\"] {\n gap: 0;\n flex-wrap: nowrap;\n}\n\n.hwped-row[role=\"group\"] > .hwped-btn {\n flex: 1 1 0;\n padding-inline: 6px;\n border-radius: 0;\n margin-left: -1px;\n}\n\n.hwped-row[role=\"group\"] > .hwped-btn:first-child {\n margin-left: 0;\n border-radius: var(--hwped-radius) 0 0 var(--hwped-radius);\n}\n\n.hwped-row[role=\"group\"] > .hwped-btn:last-child {\n border-radius: 0 var(--hwped-radius) var(--hwped-radius) 0;\n}\n\n.hwped-row[role=\"group\"] > .hwped-btn:hover:not(:disabled),\n.hwped-row[role=\"group\"] > .hwped-btn:focus-visible {\n position: relative;\n z-index: 1;\n}\n\n.hwped-quote {\n background: var(--_hwped-fill);\n border-radius: var(--hwped-radius);\n padding: 8px 10px;\n max-height: 120px;\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.hwped-hint,\n.hwped-empty {\n color: var(--hwped-muted);\n}\n\n.hwped-empty {\n margin: auto;\n text-align: center;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n}\n\n/* An error is a band in the kind's tint with a leading bar, not bare red text. */\n.hwped-error {\n color: var(--hwped-error);\n margin: 0;\n padding: 8px 12px;\n background: color-mix(in srgb, var(--hwped-error) 9%, var(--hwped-bg));\n border-bottom: 1px solid var(--_hwped-hairline);\n box-shadow: inset 3px 0 0 currentColor;\n}\n\n.hwped-error-kind {\n display: inline-block;\n margin-right: 8px;\n padding: 0 8px;\n border-radius: 999px;\n background: color-mix(in srgb, currentColor 14%, transparent);\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.02em;\n}\n\n/* timeout is transient (retry may succeed); unavailable/protected are not. */\n.hwped-error-timeout {\n color: var(--hwped-warning);\n background: color-mix(in srgb, var(--hwped-warning) 10%, var(--hwped-bg));\n}\n\n/* ---- page canvas ---- */\n\n/* Paper on the desk: layered shadow, the larger layer giving it thickness. */\n.hwped-page {\n position: relative;\n width: min(100%, 720px);\n border-radius: 3px;\n box-shadow:\n 0 0 0 1px color-mix(in srgb, var(--hwped-fg) 8%, transparent),\n 0 1px 2px rgba(0, 0, 0, 0.08),\n 0 8px 24px rgba(0, 0, 0, 0.12);\n background: #ffffff;\n cursor: text;\n}\n\n.hwped-page:focus-visible {\n outline: 2px solid var(--hwped-accent);\n outline-offset: 3px;\n}\n\n.hwped-page-svg,\n.hwped-page-img {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n.hwped-page-svg > svg {\n display: block;\n width: 100%;\n height: auto;\n}\n\n.hwped-band {\n position: absolute;\n left: 0;\n right: 0;\n pointer-events: none;\n transition: background-color var(--_hwped-quick);\n}\n\n/* Mark the selection without covering it: a light wash and an inset rule. */\n.hwped-band-selected {\n background: color-mix(in srgb, var(--hwped-accent) 9%, transparent);\n box-shadow:\n inset 3px 0 0 var(--hwped-accent),\n inset 0 0 0 1px color-mix(in srgb, var(--hwped-accent) 45%, transparent);\n}\n\n.hwped-band-pending {\n background: color-mix(in srgb, var(--hwped-accent) 6%, transparent);\n box-shadow: inset 3px 0 0 color-mix(in srgb, var(--hwped-accent) 45%, transparent);\n}\n\n/* ---- table grid ---- */\n\n.hwped-grid {\n border-collapse: collapse;\n width: 100%;\n}\n\n.hwped-grid td {\n border: 1px solid var(--hwped-border);\n padding: 0;\n}\n\n.hwped-cell {\n font: inherit;\n display: block;\n width: 100%;\n border: none;\n background: none;\n color: var(--hwped-fg);\n padding: 5px 8px;\n text-align: left;\n cursor: pointer;\n min-height: 28px;\n transition: background-color var(--_hwped-quick);\n}\n\n.hwped-cell:hover {\n background: var(--_hwped-hover);\n}\n\n.hwped-cell:active {\n background: var(--_hwped-press);\n}\n\n.hwped-cell-selected {\n outline: 2px solid var(--hwped-accent);\n outline-offset: -2px;\n}\n\n.hwped-cell-anchor {\n background: color-mix(in srgb, var(--hwped-accent) 14%, transparent);\n}\n\n/* ---- fields ---- */\n\n.hwped-fields {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.hwped-field-item {\n border-bottom: 1px solid var(--_hwped-hairline);\n padding-bottom: 10px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n/* ---- compose dialog ---- */\n\n/* Dim to focus: a modal task gets a scrim that pushes the editor back. */\n.hwped-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.32);\n backdrop-filter: blur(6px) saturate(120%);\n -webkit-backdrop-filter: blur(6px) saturate(120%);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: hwped-fade-in 160ms ease-out;\n}\n\n.hwped-dialog {\n background: var(--hwped-bg);\n color: var(--hwped-fg);\n border: 1px solid var(--_hwped-hairline);\n border-radius: calc(var(--hwped-radius) * 2);\n box-shadow:\n 0 2px 8px rgba(0, 0, 0, 0.12),\n 0 24px 64px rgba(0, 0, 0, 0.28);\n width: min(560px, calc(100vw - 32px));\n max-height: calc(100vh - 64px);\n overflow: auto;\n padding: 20px;\n display: flex;\n flex-direction: column;\n gap: 14px;\n animation: hwped-materialize 200ms cubic-bezier(0.2, 0.8, 0.2, 1);\n}\n\n.hwped-dialog-title {\n margin: 0;\n font-size: 17px;\n font-weight: 600;\n line-height: 1.3;\n letter-spacing: -0.015em;\n}\n\n.hwped-presets {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.hwped-preset {\n font: inherit;\n font-weight: 500;\n border: 1px solid var(--hwped-border);\n border-radius: 999px;\n background: var(--hwped-bg);\n color: var(--hwped-fg);\n min-height: 28px;\n padding: 3px 12px;\n cursor: pointer;\n transition:\n background-color var(--_hwped-quick),\n border-color var(--_hwped-quick),\n transform var(--_hwped-quick);\n}\n\n.hwped-preset:hover:not(.hwped-preset-active) {\n background: var(--_hwped-hover);\n}\n\n.hwped-preset:active {\n transform: scale(0.97);\n}\n\n.hwped-preset-active {\n border-color: var(--hwped-accent);\n background: color-mix(in srgb, var(--hwped-accent) 12%, var(--hwped-bg));\n color: var(--hwped-accent);\n font-weight: 600;\n}\n\n.hwped-dialog-actions {\n justify-content: flex-end;\n padding-top: 4px;\n}\n\n@keyframes hwped-fade-in {\n from {\n opacity: 0;\n }\n}\n\n/* Materialize, don't just fade: the surface arrives with a slight scale. */\n@keyframes hwped-materialize {\n from {\n opacity: 0;\n transform: scale(0.98);\n }\n}\n\n/* ---- accessibility preferences ---- */\n\n@media (prefers-reduced-motion: reduce) {\n .hwped *,\n .hwped *::before,\n .hwped *::after {\n transition-duration: 0ms !important;\n }\n\n .hwped-btn:active:not(:disabled),\n .hwped-tab:active,\n .hwped-preset:active {\n transform: none;\n }\n\n .hwped-overlay,\n .hwped-dialog {\n animation: none;\n }\n}\n\n@media (prefers-reduced-transparency: reduce) {\n .hwped-overlay {\n background: rgba(0, 0, 0, 0.55);\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n }\n}\n\n@media (prefers-contrast: more) {\n .hwped {\n --_hwped-hairline: var(--hwped-fg);\n }\n\n .hwped-btn,\n .hwped-input,\n .hwped-textarea,\n .hwped-preset,\n .hwped-grid td {\n border-color: var(--hwped-fg);\n }\n\n .hwped-tabs {\n box-shadow: inset 0 0 0 1px var(--hwped-fg);\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/theme.css","../src/editor.css"],"sourcesContent":["/**\n * Theme contract for @hwp-editor/react. Hosts theme the editor ONLY by\n * overriding these variables on the editor root or any ancestor:\n *\n * --hwped-bg surface background\n * --hwped-fg primary text\n * --hwped-muted secondary text / disabled\n * --hwped-accent primary actions, selection\n * --hwped-border hairline borders\n * --hwped-error destructive / error text and badges\n * --hwped-warning transient warning (timeout badge only)\n * --hwped-success success badge\n * --hwped-radius corner radius\n * --hwped-font font stack (default: Pretendard -> system)\n *\n * Defaults below include a prefers-color-scheme dark fallback.\n */\n\n.hwped {\n --hwped-bg: #ffffff;\n --hwped-fg: #1a1d21;\n --hwped-muted: #6b7280;\n --hwped-accent: #1f5fbf;\n --hwped-border: #d7dbe0;\n --hwped-error: #b91c1c;\n --hwped-warning: #a16207;\n --hwped-success: #15803d;\n --hwped-radius: 6px;\n --hwped-font:\n \"Pretendard\", \"Pretendard Variable\", \"Malgun Gothic\", \"맑은 고딕\",\n -apple-system, \"Segoe UI\", Roboto, \"Noto Sans KR\", sans-serif;\n}\n\n@media (prefers-color-scheme: dark) {\n .hwped {\n --hwped-bg: #17191d;\n --hwped-fg: #e5e7eb;\n --hwped-muted: #9ca3af;\n --hwped-accent: #5b8def;\n --hwped-border: #33373f;\n /* Lifted for >= 4.5:1 against --hwped-bg at 11-13px. */\n --hwped-error: #f87171;\n --hwped-warning: #fbbf24;\n --hwped-success: #4ade80;\n }\n}\n","/**\n * Scoped stylesheet for @hwp-editor/react. Every class carries the `hwped`\n * prefix; the root element gets `.hwped.hwped-root`. No global selectors,\n * no component-kit assumptions.\n *\n * Design notes (HIG-derived, #34): depth comes from tone and shadow rather\n * than extra lines; every control answers on press, not on release; status\n * is tinted by kind; motion is short, and dropped under reduced motion.\n *\n * Every tone below is DERIVED from the public --hwped-* tokens with\n * color-mix, so a host that maps those tokens (light or dark) gets the whole\n * palette. The --_hwped-* names are private and not part of the contract.\n */\n\n.hwped {\n --_hwped-desk: color-mix(in srgb, var(--hwped-fg) 5%, var(--hwped-bg));\n --_hwped-fill: color-mix(in srgb, var(--hwped-fg) 7%, var(--hwped-bg));\n --_hwped-hover: color-mix(in srgb, var(--hwped-accent) 9%, var(--hwped-bg));\n --_hwped-press: color-mix(in srgb, var(--hwped-accent) 16%, var(--hwped-bg));\n --_hwped-hairline: color-mix(in srgb, var(--hwped-border) 75%, transparent);\n --_hwped-ring: 0 0 0 3px color-mix(in srgb, var(--hwped-accent) 35%, transparent);\n --_hwped-quick: 100ms ease-out;\n\n background: var(--hwped-bg);\n color: var(--hwped-fg);\n font-family: var(--hwped-font);\n font-size: 13px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n}\n\n.hwped *,\n.hwped *::before,\n.hwped *::after {\n box-sizing: border-box;\n}\n\n.hwped-root {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 320px;\n border: 1px solid var(--hwped-border);\n border-radius: var(--hwped-radius);\n overflow: hidden;\n}\n\n/* ---- toolbar ---- */\n\n.hwped-toolbar {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 44px;\n padding: 6px 12px;\n border-bottom: 1px solid var(--_hwped-hairline);\n background: var(--hwped-bg);\n flex: 0 0 auto;\n position: relative;\n z-index: 1;\n}\n\n.hwped-title {\n font-weight: 600;\n letter-spacing: -0.01em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 40%;\n}\n\n.hwped-spacer {\n flex: 1 1 auto;\n}\n\n/* The title and this notice are the only toolbar items that may shrink: a\n long engine reason truncates here (the full text stays reachable via the\n element's title attribute) instead of being distributed across the badge,\n count and buttons, which would collapse them to min-content and stack the\n row. That is why every sibling below carries `flex: 0 0 auto` (G-03-1). */\n.hwped-notice {\n color: var(--hwped-muted);\n background: var(--_hwped-fill);\n border-radius: 999px;\n padding: 2px 10px;\n font-size: 12px;\n letter-spacing: 0.01em;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 0 1 auto;\n}\n\n/* Status reads by kind, not by outline: a tinted pill in the kind's color. */\n.hwped-badge {\n border-radius: 999px;\n padding: 2px 10px;\n font-size: 12px;\n font-weight: 600;\n letter-spacing: 0.01em;\n border: 1px solid transparent;\n background: var(--_hwped-fill);\n flex: 0 0 auto;\n}\n\n.hwped-badge-ok {\n color: var(--hwped-success);\n background: color-mix(in srgb, var(--hwped-success) 14%, transparent);\n}\n\n.hwped-badge-err {\n color: var(--hwped-error);\n background: color-mix(in srgb, var(--hwped-error) 14%, transparent);\n}\n\n.hwped-count {\n color: var(--hwped-muted);\n font-size: 12px;\n letter-spacing: 0.01em;\n font-variant-numeric: tabular-nums;\n flex: 0 0 auto;\n}\n\n/* ---- buttons / inputs ---- */\n\n.hwped-btn {\n font: inherit;\n font-weight: 500;\n color: var(--hwped-fg);\n background: var(--hwped-bg);\n border: 1px solid var(--hwped-border);\n border-radius: var(--hwped-radius);\n min-height: 28px;\n padding: 3px 12px;\n cursor: pointer;\n transition:\n background-color var(--_hwped-quick),\n border-color var(--_hwped-quick),\n transform var(--_hwped-quick);\n}\n\n.hwped-btn:hover:not(:disabled) {\n background: var(--_hwped-hover);\n border-color: color-mix(in srgb, var(--hwped-accent) 55%, var(--hwped-border));\n}\n\n/* Feedback on press, instantly - never only on release. */\n.hwped-btn:active:not(:disabled) {\n background: var(--_hwped-press);\n transform: scale(0.97);\n}\n\n.hwped-btn:disabled {\n color: var(--hwped-muted);\n background: transparent;\n border-color: var(--_hwped-hairline);\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.hwped-btn-primary {\n background: var(--hwped-accent);\n border-color: var(--hwped-accent);\n color: #ffffff;\n font-weight: 600;\n}\n\n.hwped-btn-primary:hover:not(:disabled) {\n background: color-mix(in srgb, var(--hwped-accent) 88%, #000000);\n border-color: color-mix(in srgb, var(--hwped-accent) 88%, #000000);\n}\n\n.hwped-btn-primary:active:not(:disabled) {\n background: color-mix(in srgb, var(--hwped-accent) 78%, #000000);\n}\n\n/* A disabled primary keeps a trace of its accent, but must not read as live. */\n.hwped-btn-primary:disabled {\n color: var(--hwped-muted);\n background: color-mix(in srgb, var(--hwped-accent) 14%, var(--hwped-bg));\n border-color: transparent;\n opacity: 1;\n}\n\n/* Destructive reads as destructive at rest, not only on hover. */\n.hwped-btn-danger {\n color: var(--hwped-error);\n}\n\n.hwped-btn-danger:hover:not(:disabled) {\n border-color: var(--hwped-error);\n color: var(--hwped-error);\n background: color-mix(in srgb, var(--hwped-error) 9%, var(--hwped-bg));\n}\n\n.hwped-btn-link {\n border: none;\n background: none;\n min-height: 0;\n padding: 0;\n color: var(--hwped-accent);\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n\n.hwped-btn-link:hover:not(:disabled) {\n background: none;\n}\n\n/* Scoped to direct toolbar children on purpose: `.hwped-btn` is reused by\n SegmentInspector, TableGrid, FieldsPanel, the compose dialog actions and\n the empty-state button, where non-shrinkable buttons would trade this bug\n for horizontal overflow in those narrow rows. */\n.hwped-toolbar > .hwped-btn {\n flex: 0 0 auto;\n}\n\n.hwped-input,\n.hwped-textarea {\n font: inherit;\n color: var(--hwped-fg);\n background: var(--hwped-bg);\n border: 1px solid var(--hwped-border);\n border-radius: var(--hwped-radius);\n min-height: 28px;\n padding: 4px 9px;\n width: 100%;\n transition:\n border-color var(--_hwped-quick),\n box-shadow var(--_hwped-quick);\n}\n\n.hwped-input::placeholder,\n.hwped-textarea::placeholder {\n color: var(--hwped-muted);\n opacity: 0.8;\n}\n\n.hwped-input:hover:not(:disabled),\n.hwped-textarea:hover:not(:disabled) {\n border-color: color-mix(in srgb, var(--hwped-fg) 30%, var(--hwped-border));\n}\n\n/* One focus treatment everywhere: accent edge plus a soft ring. */\n.hwped-input:focus,\n.hwped-textarea:focus {\n outline: none;\n border-color: var(--hwped-accent);\n box-shadow: var(--_hwped-ring);\n}\n\n.hwped-btn:focus-visible,\n.hwped-tab:focus-visible,\n.hwped-preset:focus-visible,\n.hwped-cell:focus-visible {\n outline: none;\n box-shadow: var(--_hwped-ring);\n}\n\n.hwped-input-narrow {\n width: 96px;\n flex: 0 0 auto;\n}\n\n.hwped-check {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n}\n\n.hwped-check input {\n accent-color: var(--hwped-accent);\n}\n\n/* ---- layout ---- */\n\n.hwped-pending-list {\n flex: 0 1 auto;\n min-height: 0;\n max-height: 120px;\n overflow: auto;\n overflow-wrap: anywhere;\n}\n\n.hwped-main {\n display: flex;\n flex: 1 1 auto;\n min-height: 0;\n}\n\n/* The desk: a tone below the chrome, so the page reads as a sheet on it. */\n.hwped-canvas {\n flex: 1 1 auto;\n overflow: auto;\n padding: 24px;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 24px;\n background: var(--_hwped-desk);\n}\n\n.hwped-side {\n flex: 0 0 300px;\n border-left: 1px solid var(--_hwped-hairline);\n background: var(--hwped-bg);\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n/* Tabs as a segmented control: a recessed track, the active segment raised. */\n.hwped-tabs {\n display: flex;\n flex-wrap: wrap;\n gap: 2px;\n margin: 10px 12px 2px;\n padding: 3px;\n background: var(--_hwped-fill);\n border-radius: calc(var(--hwped-radius) + 2px);\n flex: 0 0 auto;\n}\n\n.hwped-tab {\n font: inherit;\n font-weight: 500;\n flex: 1 1 78px;\n min-width: 0;\n min-height: 26px;\n padding: 3px 0;\n background: none;\n border: none;\n border-radius: var(--hwped-radius);\n color: var(--hwped-muted);\n cursor: pointer;\n transition:\n background-color var(--_hwped-quick),\n color var(--_hwped-quick),\n transform var(--_hwped-quick);\n}\n\n.hwped-tab:hover:not(.hwped-tab-active) {\n color: var(--hwped-fg);\n}\n\n.hwped-tab:active {\n transform: scale(0.97);\n}\n\n.hwped-tab-active {\n color: var(--hwped-fg);\n background: var(--hwped-bg);\n font-weight: 600;\n box-shadow:\n 0 1px 2px rgba(0, 0, 0, 0.12),\n 0 0 0 0.5px rgba(0, 0, 0, 0.06);\n}\n\n.hwped-panel {\n padding: 12px;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.hwped-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.hwped-label {\n font-size: 12px;\n font-weight: 600;\n letter-spacing: 0.01em;\n line-height: 1.35;\n color: color-mix(in srgb, var(--hwped-fg) 72%, var(--hwped-bg));\n}\n\n.hwped-row {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n/* A role=\"group\" row of peer actions (alignment) reads as one joined control. */\n.hwped-row[role=\"group\"] {\n gap: 0;\n flex-wrap: nowrap;\n}\n\n.hwped-row[role=\"group\"] > .hwped-btn {\n flex: 1 1 0;\n padding-inline: 6px;\n border-radius: 0;\n margin-left: -1px;\n}\n\n.hwped-row[role=\"group\"] > .hwped-btn:first-child {\n margin-left: 0;\n border-radius: var(--hwped-radius) 0 0 var(--hwped-radius);\n}\n\n.hwped-row[role=\"group\"] > .hwped-btn:last-child {\n border-radius: 0 var(--hwped-radius) var(--hwped-radius) 0;\n}\n\n.hwped-row[role=\"group\"] > .hwped-btn:hover:not(:disabled),\n.hwped-row[role=\"group\"] > .hwped-btn:focus-visible {\n position: relative;\n z-index: 1;\n}\n\n.hwped-quote {\n background: var(--_hwped-fill);\n border-radius: var(--hwped-radius);\n padding: 8px 10px;\n max-height: 120px;\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.hwped-hint,\n.hwped-empty {\n color: var(--hwped-muted);\n}\n\n.hwped-empty {\n margin: auto;\n text-align: center;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n}\n\n/* An error is a band in the kind's tint with a leading bar, not bare red text. */\n.hwped-error {\n color: var(--hwped-error);\n margin: 0;\n padding: 8px 12px;\n background: color-mix(in srgb, var(--hwped-error) 9%, var(--hwped-bg));\n border-bottom: 1px solid var(--_hwped-hairline);\n box-shadow: inset 3px 0 0 currentColor;\n}\n\n.hwped-error-kind {\n display: inline-block;\n margin-right: 8px;\n padding: 0 8px;\n border-radius: 999px;\n background: color-mix(in srgb, currentColor 14%, transparent);\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.02em;\n}\n\n/* timeout is transient (retry may succeed); unavailable/protected are not. */\n.hwped-error-timeout {\n color: var(--hwped-warning);\n background: color-mix(in srgb, var(--hwped-warning) 10%, var(--hwped-bg));\n}\n\n/* ---- page canvas ---- */\n\n/* Paper on the desk: layered shadow, the larger layer giving it thickness. */\n.hwped-page {\n position: relative;\n width: min(100%, 720px);\n border-radius: 3px;\n box-shadow:\n 0 0 0 1px color-mix(in srgb, var(--hwped-fg) 8%, transparent),\n 0 1px 2px rgba(0, 0, 0, 0.08),\n 0 8px 24px rgba(0, 0, 0, 0.12);\n background: #ffffff;\n cursor: text;\n}\n\n.hwped-page:focus-visible {\n outline: 2px solid var(--hwped-accent);\n outline-offset: 3px;\n}\n\n.hwped-page-img {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n.hwped-band {\n position: absolute;\n left: 0;\n right: 0;\n pointer-events: none;\n transition: background-color var(--_hwped-quick);\n}\n\n/* Mark the selection without covering it: a light wash and an inset rule. */\n.hwped-band-selected {\n background: color-mix(in srgb, var(--hwped-accent) 9%, transparent);\n box-shadow:\n inset 3px 0 0 var(--hwped-accent),\n inset 0 0 0 1px color-mix(in srgb, var(--hwped-accent) 45%, transparent);\n}\n\n.hwped-band-pending {\n background: color-mix(in srgb, var(--hwped-accent) 6%, transparent);\n box-shadow: inset 3px 0 0 color-mix(in srgb, var(--hwped-accent) 45%, transparent);\n}\n\n/* ---- table grid ---- */\n\n.hwped-grid {\n border-collapse: collapse;\n width: 100%;\n}\n\n.hwped-grid td {\n border: 1px solid var(--hwped-border);\n padding: 0;\n}\n\n.hwped-cell {\n font: inherit;\n display: block;\n width: 100%;\n border: none;\n background: none;\n color: var(--hwped-fg);\n padding: 5px 8px;\n text-align: left;\n cursor: pointer;\n min-height: 28px;\n transition: background-color var(--_hwped-quick);\n}\n\n.hwped-cell:hover {\n background: var(--_hwped-hover);\n}\n\n.hwped-cell:active {\n background: var(--_hwped-press);\n}\n\n.hwped-cell-selected {\n outline: 2px solid var(--hwped-accent);\n outline-offset: -2px;\n}\n\n.hwped-cell-anchor {\n background: color-mix(in srgb, var(--hwped-accent) 14%, transparent);\n}\n\n/* ---- fields ---- */\n\n.hwped-fields {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.hwped-field-item {\n border-bottom: 1px solid var(--_hwped-hairline);\n padding-bottom: 10px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n/* ---- compose dialog ---- */\n\n/* Dim to focus: a modal task gets a scrim that pushes the editor back. */\n.hwped-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.32);\n backdrop-filter: blur(6px) saturate(120%);\n -webkit-backdrop-filter: blur(6px) saturate(120%);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: hwped-fade-in 160ms ease-out;\n}\n\n.hwped-dialog {\n background: var(--hwped-bg);\n color: var(--hwped-fg);\n border: 1px solid var(--_hwped-hairline);\n border-radius: calc(var(--hwped-radius) * 2);\n box-shadow:\n 0 2px 8px rgba(0, 0, 0, 0.12),\n 0 24px 64px rgba(0, 0, 0, 0.28);\n width: min(560px, calc(100vw - 32px));\n max-height: calc(100vh - 64px);\n overflow: auto;\n padding: 20px;\n display: flex;\n flex-direction: column;\n gap: 14px;\n animation: hwped-materialize 200ms cubic-bezier(0.2, 0.8, 0.2, 1);\n}\n\n.hwped-dialog-title {\n margin: 0;\n font-size: 17px;\n font-weight: 600;\n line-height: 1.3;\n letter-spacing: -0.015em;\n}\n\n.hwped-presets {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.hwped-preset {\n font: inherit;\n font-weight: 500;\n border: 1px solid var(--hwped-border);\n border-radius: 999px;\n background: var(--hwped-bg);\n color: var(--hwped-fg);\n min-height: 28px;\n padding: 3px 12px;\n cursor: pointer;\n transition:\n background-color var(--_hwped-quick),\n border-color var(--_hwped-quick),\n transform var(--_hwped-quick);\n}\n\n.hwped-preset:hover:not(.hwped-preset-active) {\n background: var(--_hwped-hover);\n}\n\n.hwped-preset:active {\n transform: scale(0.97);\n}\n\n.hwped-preset-active {\n border-color: var(--hwped-accent);\n background: color-mix(in srgb, var(--hwped-accent) 12%, var(--hwped-bg));\n color: var(--hwped-accent);\n font-weight: 600;\n}\n\n.hwped-dialog-actions {\n justify-content: flex-end;\n padding-top: 4px;\n}\n\n@keyframes hwped-fade-in {\n from {\n opacity: 0;\n }\n}\n\n/* Materialize, don't just fade: the surface arrives with a slight scale. */\n@keyframes hwped-materialize {\n from {\n opacity: 0;\n transform: scale(0.98);\n }\n}\n\n/* ---- accessibility preferences ---- */\n\n@media (prefers-reduced-motion: reduce) {\n .hwped *,\n .hwped *::before,\n .hwped *::after {\n transition-duration: 0ms !important;\n }\n\n .hwped-btn:active:not(:disabled),\n .hwped-tab:active,\n .hwped-preset:active {\n transform: none;\n }\n\n .hwped-overlay,\n .hwped-dialog {\n animation: none;\n }\n}\n\n@media (prefers-reduced-transparency: reduce) {\n .hwped-overlay {\n background: rgba(0, 0, 0, 0.55);\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n }\n}\n\n@media (prefers-contrast: more) {\n .hwped {\n --_hwped-hairline: var(--hwped-fg);\n }\n\n .hwped-btn,\n .hwped-input,\n .hwped-textarea,\n .hwped-preset,\n .hwped-grid td {\n border-color: var(--hwped-fg);\n }\n\n .hwped-tabs {\n box-shadow: inset 0 0 0 1px var(--hwped-fg);\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -327,7 +327,7 @@ declare const en: {
327
327
  "segment.runSelectionParagraphs": (p: {
328
328
  count: number;
329
329
  }) => string;
330
- "segment.runSelectionTerminal": string;
330
+ "segment.runSelectionGestures": string;
331
331
  "segment.noParagraphSelection": string;
332
332
  "segment.cellSelectionRefused": string;
333
333
  "segment.tableSelectionRefused": string;
@@ -336,6 +336,8 @@ declare const en: {
336
336
  "segment.clickRefusedTable": string;
337
337
  "segment.clickRefusedContainer": string;
338
338
  "segment.clickRefusedUnaddressable": string;
339
+ "segment.clickRefusedUnaddressableRuns": string;
340
+ "segment.clickRefusedNoRuns": string;
339
341
  "segment.selectSimilar": string;
340
342
  "segment.similarChar": string;
341
343
  "segment.similarPara": string;
@@ -508,6 +510,7 @@ declare const en: {
508
510
  "error.staleCompose": string;
509
511
  "error.stalePreview": string;
510
512
  "error.unmatchedReplace": string;
513
+ "error.unresolvableAddress": string;
511
514
  "error.runRangeConflict": string;
512
515
  "error.rangeTagRefused": string;
513
516
  "error.stoppedWithoutDiagnostic": string;
@@ -1071,11 +1074,15 @@ declare function componentRefusalText(error: unknown, t: TFunction): string | nu
1071
1074
  declare function componentFailure(error: unknown, t: TFunction): unknown;
1072
1075
 
1073
1076
  /**
1074
- * Minimal SVG sanitizer for inline rendering of `hwp render --format svg`
1075
- * output. The CLI output is trusted, but hosts embedding arbitrary documents
1076
- * get script/foreignObject/event-handler removal for free.
1077
+ * Minimal SVG cleanup that removes script, foreignObject and event-handler
1078
+ * attributes. Returns "" when the payload does not parse as XML.
1077
1079
  *
1078
- * Returns "" when the payload does not parse as XML.
1080
+ * @deprecated Not a security boundary: a blocklist cannot make SVG safe to
1081
+ * insert into HTML, and its output must not be inserted into the DOM as
1082
+ * markup (innerHTML, dangerouslySetInnerHTML). Render an SVG page as an image
1083
+ * instead, e.g. `<img src="data:image/svg+xml;base64,...">`, which is what the
1084
+ * editor's page view does. Kept exported for API compatibility only; it is
1085
+ * unused by this package and will be removed in 2.0.
1079
1086
  */
1080
1087
  declare function sanitizeSvg(svgText: string): string;
1081
1088
 
package/dist/index.d.ts CHANGED
@@ -327,7 +327,7 @@ declare const en: {
327
327
  "segment.runSelectionParagraphs": (p: {
328
328
  count: number;
329
329
  }) => string;
330
- "segment.runSelectionTerminal": string;
330
+ "segment.runSelectionGestures": string;
331
331
  "segment.noParagraphSelection": string;
332
332
  "segment.cellSelectionRefused": string;
333
333
  "segment.tableSelectionRefused": string;
@@ -336,6 +336,8 @@ declare const en: {
336
336
  "segment.clickRefusedTable": string;
337
337
  "segment.clickRefusedContainer": string;
338
338
  "segment.clickRefusedUnaddressable": string;
339
+ "segment.clickRefusedUnaddressableRuns": string;
340
+ "segment.clickRefusedNoRuns": string;
339
341
  "segment.selectSimilar": string;
340
342
  "segment.similarChar": string;
341
343
  "segment.similarPara": string;
@@ -508,6 +510,7 @@ declare const en: {
508
510
  "error.staleCompose": string;
509
511
  "error.stalePreview": string;
510
512
  "error.unmatchedReplace": string;
513
+ "error.unresolvableAddress": string;
511
514
  "error.runRangeConflict": string;
512
515
  "error.rangeTagRefused": string;
513
516
  "error.stoppedWithoutDiagnostic": string;
@@ -1071,11 +1074,15 @@ declare function componentRefusalText(error: unknown, t: TFunction): string | nu
1071
1074
  declare function componentFailure(error: unknown, t: TFunction): unknown;
1072
1075
 
1073
1076
  /**
1074
- * Minimal SVG sanitizer for inline rendering of `hwp render --format svg`
1075
- * output. The CLI output is trusted, but hosts embedding arbitrary documents
1076
- * get script/foreignObject/event-handler removal for free.
1077
+ * Minimal SVG cleanup that removes script, foreignObject and event-handler
1078
+ * attributes. Returns "" when the payload does not parse as XML.
1077
1079
  *
1078
- * Returns "" when the payload does not parse as XML.
1080
+ * @deprecated Not a security boundary: a blocklist cannot make SVG safe to
1081
+ * insert into HTML, and its output must not be inserted into the DOM as
1082
+ * markup (innerHTML, dangerouslySetInnerHTML). Render an SVG page as an image
1083
+ * instead, e.g. `<img src="data:image/svg+xml;base64,...">`, which is what the
1084
+ * editor's page view does. Kept exported for API compatibility only; it is
1085
+ * unused by this package and will be removed in 2.0.
1079
1086
  */
1080
1087
  declare function sanitizeSvg(svgText: string): string;
1081
1088
 
package/dist/index.js CHANGED
@@ -129,31 +129,6 @@ function bandsOnPage(envelope, segment, page, pageIndex, pageCount) {
129
129
  });
130
130
  }
131
131
 
132
- // src/sanitize.ts
133
- function sanitizeSvg(svgText) {
134
- const doc = new DOMParser().parseFromString(svgText, "image/svg+xml");
135
- const root = doc.documentElement;
136
- if (root === null || root.nodeName === "parsererror" || doc.getElementsByTagName("parsererror").length > 0) {
137
- return "";
138
- }
139
- const dangerous = root.querySelectorAll("script, foreignObject");
140
- for (const node of Array.from(dangerous)) node.remove();
141
- scrubElement(root);
142
- return root.outerHTML;
143
- }
144
- function scrubElement(el) {
145
- for (const attr of Array.from(el.attributes)) {
146
- const name = attr.name.toLowerCase();
147
- const value = attr.value.trim().toLowerCase();
148
- if (name.startsWith("on")) {
149
- el.removeAttribute(attr.name);
150
- } else if ((name === "href" || name === "xlink:href") && value.startsWith("javascript:")) {
151
- el.removeAttribute(attr.name);
152
- }
153
- }
154
- for (const child of Array.from(el.children)) scrubElement(child);
155
- }
156
-
157
132
  // src/text.ts
158
133
  function plainSegmentText(markdownSlice) {
159
134
  return markdownSlice.split("\n").map(stripLine).join("\n").trim();
@@ -250,13 +225,8 @@ function PageView(props) {
250
225
  const { page, onClick, onActivate, bands } = props;
251
226
  const { t } = useHwpEditorContext();
252
227
  const label = t("page.label", { page: page.page });
253
- const svgHtml = useMemo(
254
- () => page.format === "svg" ? sanitizeSvg(new TextDecoder().decode(page.data)) : null,
255
- [page]
256
- );
257
228
  const imgSrc = useMemo(() => {
258
- if (page.format === "svg") return null;
259
- const mime = page.format === "jpeg" ? "image/jpeg" : `image/${page.format}`;
229
+ const mime = page.format === "jpeg" ? "image/jpeg" : page.format === "svg" ? "image/svg+xml" : `image/${page.format}`;
260
230
  return `data:${mime};base64,${base64.encode(page.data)}`;
261
231
  }, [page]);
262
232
  return /* @__PURE__ */ jsxs(
@@ -275,17 +245,11 @@ function PageView(props) {
275
245
  }
276
246
  },
277
247
  children: [
278
- svgHtml !== null ? /* @__PURE__ */ jsx(
279
- "div",
280
- {
281
- className: "hwped-page-svg",
282
- dangerouslySetInnerHTML: { __html: svgHtml }
283
- }
284
- ) : /* @__PURE__ */ jsx(
248
+ /* @__PURE__ */ jsx(
285
249
  "img",
286
250
  {
287
251
  className: "hwped-page-img",
288
- src: imgSrc ?? "",
252
+ src: imgSrc,
289
253
  alt: label,
290
254
  width: page.width,
291
255
  height: page.height
@@ -354,6 +318,14 @@ var SHAPE_KEYS = [
354
318
  { value: "top", key: "segment.shape.top" },
355
319
  { value: "bottom", key: "segment.shape.bottom" }
356
320
  ];
321
+ var CLICK_REFUSAL_MESSAGE = {
322
+ cell: "segment.clickRefusedCell",
323
+ table: "segment.clickRefusedTable",
324
+ container: "segment.clickRefusedContainer",
325
+ unaddressable: "segment.clickRefusedUnaddressable",
326
+ unaddressableRuns: "segment.clickRefusedUnaddressableRuns",
327
+ noRuns: "segment.clickRefusedNoRuns"
328
+ };
357
329
  function SegmentInspector() {
358
330
  const { state, store, envelope, editable, capabilities, styles, stylesStatus, t, insertedHidden } = useHwpEditorContext();
359
331
  const { selection } = state;
@@ -378,7 +350,7 @@ function SegmentInspector() {
378
350
  })();
379
351
  const directStyleWhy = directStyleRow !== void 0 ? null : stylesStatus === "loading" ? "segment.directStyleLoading" : stylesStatus === "failed" ? "segment.directStyleFailed" : stylesStatus === "unsupported" ? "styles.unavailableHost" : capabilities === null ? "styles.checkingHost" : capabilities.styles !== "v1" ? stylesVersionSupported(capabilities.version) ? "styles.unavailableHost" : "segment.directStyleUnavailable" : "segment.directStyleUnknown";
380
352
  const refusalText = (reason) => reason === null || reason === void 0 ? null : reason === "cell" ? t("segment.cellSelectionRefused") : reason === "table" ? t("segment.tableSelectionRefused") : reason === "container" ? t("segment.containerSelectionRefused") : t("segment.noParagraphSelection");
381
- const clickRefusedText = (reason) => reason === null || reason === void 0 ? null : reason === "cell" ? t("segment.clickRefusedCell") : reason === "table" ? t("segment.clickRefusedTable") : reason === "container" ? t("segment.clickRefusedContainer") : t("segment.clickRefusedUnaddressable");
353
+ const clickRefusedText = (reason) => reason === null || reason === void 0 ? null : t(CLICK_REFUSAL_MESSAGE[reason]);
382
354
  const refusalReason2 = refusalText(targets?.refusal);
383
355
  const targetLabel = segment === void 0 ? "" : segment.kind === "cell" ? t("segment.selectedCell", { path: segmentPath(segment), count: paragraphTargets.length }) : singleParagraph === void 0 ? "" : t("segment.selectedPara", { path: segmentPath(singleParagraph) });
384
356
  const currentText = envelope !== null && paragraphTargets.length > 0 ? plainSegmentText(paragraphTargets.map((candidate) => segmentText2(envelope, candidate)).join("\n")) : "";
@@ -557,7 +529,10 @@ function SegmentInspector() {
557
529
  type: "selectMany",
558
530
  selections: refs,
559
531
  primary,
560
- ...state.selectionAnchor === null || state.selectionAnchor === void 0 ? { anchor: primary } : { anchor: state.selectionAnchor }
532
+ // A matching-character-format selection is a new run selection, so its
533
+ // anchor is its own primary (#71 rule 7), never a run left over from an
534
+ // earlier one. The paragraph level keeps an existing anchor as before.
535
+ ...level === "char" || state.selectionAnchor === null || state.selectionAnchor === void 0 ? { anchor: primary } : { anchor: state.selectionAnchor }
561
536
  });
562
537
  };
563
538
  const moveParagraph = (direction) => {
@@ -671,9 +646,9 @@ function SegmentInspector() {
671
646
  // state holds and the targets the format op will address.
672
647
  children: hasRunSelection ? t("segment.selectedRunCount", { count: explicitSegments.length }) : t("segment.selectedCount", { count: selected.length })
673
648
  }),
674
- // A run-level selection formats runs, and a modifier click from it
675
- // starts a paragraph selection over instead of joining the runs.
676
- hasRunSelection && /* @__PURE__ */ jsx2("p", { className: "hwped-hint", role: "status", children: t("segment.runSelectionTerminal") }),
649
+ // A run-level selection formats runs, and a modifier click keeps it at
650
+ // run level: Ctrl toggles a unit's runs, Shift extends by run (#71).
651
+ hasRunSelection && /* @__PURE__ */ jsx2("p", { className: "hwped-hint", role: "status", children: t("segment.runSelectionGestures") }),
677
652
  // A modifier click that had no paragraph to add left the selection
678
653
  // alone, and reports the click here whatever the selection's own
679
654
  // reason is: the reader's action is what was refused, and a click
@@ -3834,7 +3809,7 @@ var en = {
3834
3809
  "segment.rangeTextEditHint": "A character range formats text but cannot rewrite it. Use whole paragraph to edit its text.",
3835
3810
  "segment.runTextEditHint": "A run selection formats runs only, so the text controls are off. Select a paragraph to edit its text.",
3836
3811
  "segment.runSelectionParagraphs": (p) => p.count === 1 ? "Alignment and spacing apply to the 1 paragraph containing a selected run." : `Alignment and spacing apply to all ${p.count} paragraphs containing a selected run.`,
3837
- "segment.runSelectionTerminal": "Starts a new paragraph selection",
3812
+ "segment.runSelectionGestures": "Ctrl adds or removes a paragraph's runs; Shift extends by run.",
3838
3813
  "segment.noParagraphSelection": "This selection carries no paragraph the engine can address, so paragraph edits are off. Pick a paragraph from the list above.",
3839
3814
  "segment.cellSelectionRefused": "This selection is a table cell. Alignment and spacing apply to every paragraph in the cell, but replace, insert and delete address exactly one paragraph, and the engine refuses to delete a cell's last one. Pick a paragraph from the list above.",
3840
3815
  "segment.tableSelectionRefused": "This selection is a table, not a paragraph. The paragraph that holds the table also holds its own text, so editing or deleting it would take the table with it. Pick a paragraph from the list above.",
@@ -3850,6 +3825,8 @@ var en = {
3850
3825
  "segment.clickRefusedTable": "The click added nothing: a table has no paragraph of its own, so there is none to add. Click a paragraph or a cell.",
3851
3826
  "segment.clickRefusedContainer": "The click added nothing: an image, a field or a bookmark has no text of its own, so there is no paragraph to add. Click a paragraph or a cell.",
3852
3827
  "segment.clickRefusedUnaddressable": "That unit does not name a paragraph the engine can address, so the click selected nothing. Click a paragraph or a cell.",
3828
+ "segment.clickRefusedUnaddressableRuns": "The clicked paragraph or cell has runs, but the engine published no address for them, so the click selected nothing. Click without Ctrl or Shift to select the whole paragraph, or click a paragraph or cell whose runs have addresses.",
3829
+ "segment.clickRefusedNoRuns": "The clicked paragraph or cell has no runs to add. Click a paragraph or cell that has text.",
3853
3830
  "segment.selectSimilar": "Select content with matching direct formatting",
3854
3831
  "segment.similarChar": "Matching character format",
3855
3832
  "segment.similarPara": "Matching paragraph format",
@@ -3976,6 +3953,7 @@ var en = {
3976
3953
  "error.staleCompose": "The open document changed while the new document was being composed; compose again.",
3977
3954
  "error.stalePreview": "The document changed while this preview was being made; preview again on the open document.",
3978
3955
  "error.unmatchedReplace": "The engine found no text to replace in that paragraph, so nothing was applied. Select the text again and retry.",
3956
+ "error.unresolvableAddress": "The engine could not address the edit's paragraph or run. Runs inside some nested paragraphs cannot be addressed. Format text in a top-level paragraph or a table cell, or edit this target in a word processor.",
3979
3957
  "error.runRangeConflict": "A run format change was refused because an earlier pending change in that paragraph (text, a link, a field, a bookmark, an image or a cell) may change its text, so the run might no longer name the same characters. Nothing was applied. Remove the format change from the pending list, apply the rest, then format the run again; or queue the format change before the others.",
3980
3958
  "error.rangeTagRefused": "This HWP document holds a range mark the engine cannot move, so a pending edit was refused and nothing was applied. Edits that move text around the mark are refused: changing a paragraph's text length, changing a field's value to one of a different length, inserting or deleting a link, field, bookmark or image, or deleting a table. A table cell that holds a mark refuses any change to its content. The engine does not say which edit. Remove those pending edits from the pending list (a same-length text replacement in a paragraph, or a same-length field value, is accepted) and apply the rest. To make those edits, convert the document to HWPX, which drops the range marks, or remove the mark in Hangul, then reopen it; reopening drops the pending list.",
3981
3959
  "error.stoppedWithoutDiagnostic": STOPPED_WITHOUT_DIAGNOSTIC,
@@ -4305,7 +4283,7 @@ var ko = {
4305
4283
  "segment.rangeTextEditHint": "\uAE00\uC790 \uBC94\uC704 \uC120\uD0DD\uC740 \uC11C\uC2DD\uB9CC \uBC14\uAFC0 \uC218 \uC788\uACE0 \uD14D\uC2A4\uD2B8\uB294 \uBC14\uAFC0 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uD14D\uC2A4\uD2B8\uB97C \uD3B8\uC9D1\uD558\uB824\uBA74 \uBB38\uB2E8 \uC804\uCCB4\uB97C \uC0AC\uC6A9\uD558\uC138\uC694.",
4306
4284
  "segment.runTextEditHint": "run \uC120\uD0DD\uC740 \uC11C\uC2DD\uB9CC \uBC14\uAFC0 \uC218 \uC788\uC5B4 \uD14D\uC2A4\uD2B8 \uC785\uB825\uB780\uC744 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uD14D\uC2A4\uD2B8\uB97C \uD3B8\uC9D1\uD558\uB824\uBA74 \uBB38\uB2E8\uC744 \uC120\uD0DD\uD558\uC138\uC694.",
4307
4285
  "segment.runSelectionParagraphs": (p) => `\uBB38\uB2E8 \uC815\uB82C\uACFC \uAC04\uACA9\uC740 \uC120\uD0DD\uD55C run\uC774 \uC788\uB294 \uBB38\uB2E8 ${p.count}\uAC1C \uC804\uCCB4\uC5D0 \uC801\uC6A9\uB429\uB2C8\uB2E4.`,
4308
- "segment.runSelectionTerminal": "\uC0C8 \uBB38\uB2E8 \uC120\uD0DD\uC774 \uC2DC\uC791\uB429\uB2C8\uB2E4",
4286
+ "segment.runSelectionGestures": "Ctrl\uB85C \uBB38\uB2E8\uC758 run\uC744 \uB354\uD558\uAC70\uB098 \uBE7C\uACE0, Shift\uB85C run \uB2E8\uC704\uB85C \uB113\uD799\uB2C8\uB2E4.",
4309
4287
  "segment.noParagraphSelection": "\uC774 \uC120\uD0DD\uC5D0\uB294 \uC5D4\uC9C4\uC774 \uC8FC\uC18C\uB85C \uC9C0\uC815\uD560 \uC218 \uC788\uB294 \uBB38\uB2E8\uC774 \uC5C6\uC5B4 \uBB38\uB2E8 \uD3B8\uC9D1\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC704 \uBAA9\uB85D\uC5D0\uC11C \uBB38\uB2E8\uC744 \uC120\uD0DD\uD558\uC138\uC694.",
4310
4288
  "segment.cellSelectionRefused": "\uC774 \uC120\uD0DD\uC740 \uD45C\uC758 \uC140\uC785\uB2C8\uB2E4. \uC815\uB82C\uACFC \uBB38\uB2E8 \uBAA8\uC591\uC740 \uC140 \uC548\uC758 \uBAA8\uB4E0 \uBB38\uB2E8\uC5D0 \uC801\uC6A9\uB418\uC9C0\uB9CC, \uAD50\uCCB4, \uC0BD\uC785, \uC0AD\uC81C\uB294 \uBB38\uB2E8 \uD558\uB098\uB9CC \uB300\uC0C1\uC73C\uB85C \uD558\uBA70, \uC5D4\uC9C4\uC740 \uC140\uC758 \uB9C8\uC9C0\uB9C9 \uBB38\uB2E8 \uC0AD\uC81C\uB3C4 \uAC70\uBD80\uD569\uB2C8\uB2E4. \uC704 \uBAA9\uB85D\uC5D0\uC11C \uBB38\uB2E8\uC744 \uC120\uD0DD\uD558\uC138\uC694.",
4311
4289
  "segment.tableSelectionRefused": "\uC774 \uC120\uD0DD\uC740 \uBB38\uB2E8\uC774 \uC544\uB2C8\uB77C \uD45C\uC785\uB2C8\uB2E4. \uD45C\uB97C \uB2F4\uACE0 \uC788\uB294 \uBB38\uB2E8\uC740 \uC790\uAE30 \uD14D\uC2A4\uD2B8\uB3C4 \uD568\uAED8 \uB2F4\uACE0 \uC788\uC5B4, \uADF8 \uBB38\uB2E8\uC744 \uD3B8\uC9D1\uD558\uAC70\uB098 \uC0AD\uC81C\uD558\uBA74 \uD45C\uAC00 \uC0AC\uB77C\uC9D1\uB2C8\uB2E4. \uC704 \uBAA9\uB85D\uC5D0\uC11C \uBB38\uB2E8\uC744 \uC120\uD0DD\uD558\uC138\uC694.",
@@ -4314,6 +4292,8 @@ var ko = {
4314
4292
  "segment.clickRefusedTable": "\uD074\uB9AD\uC73C\uB85C \uCD94\uAC00\uB41C \uBB38\uB2E8\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uD45C\uB294 \uC790\uCCB4 \uBB38\uB2E8\uC774 \uC5C6\uC5B4 \uCD94\uAC00\uD560 \uB300\uC0C1\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uBB38\uB2E8\uC774\uB098 \uC140\uC744 \uD074\uB9AD\uD558\uC138\uC694.",
4315
4293
  "segment.clickRefusedContainer": "\uD074\uB9AD\uC73C\uB85C \uCD94\uAC00\uB41C \uBB38\uB2E8\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uADF8\uB9BC, \uD544\uB4DC \uB610\uB294 \uCC45\uAC08\uD53C\uB294 \uC790\uCCB4 \uD14D\uC2A4\uD2B8\uAC00 \uC5C6\uC5B4 \uCD94\uAC00\uD560 \uBB38\uB2E8\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uBB38\uB2E8\uC774\uB098 \uC140\uC744 \uD074\uB9AD\uD558\uC138\uC694.",
4316
4294
  "segment.clickRefusedUnaddressable": "\uADF8 \uC694\uC18C\uB294 \uC5D4\uC9C4\uC774 \uC8FC\uC18C\uB85C \uC9C0\uC815\uD560 \uC218 \uC788\uB294 \uBB38\uB2E8\uC744 \uAC00\uB9AC\uD0A4\uC9C0 \uC54A\uC73C\uBBC0\uB85C \uD074\uB9AD\uC73C\uB85C \uC120\uD0DD\uB41C \uAC83\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uBB38\uB2E8\uC774\uB098 \uC140\uC744 \uD074\uB9AD\uD558\uC138\uC694.",
4295
+ "segment.clickRefusedUnaddressableRuns": "\uD074\uB9AD\uD55C \uBB38\uB2E8\uC774\uB098 \uC140\uC5D0 run\uC740 \uC788\uC9C0\uB9CC \uC5D4\uC9C4\uC774 \uADF8 run\uC758 \uC8FC\uC18C\uB97C \uC81C\uACF5\uD558\uC9C0 \uC54A\uC544 \uC120\uD0DD\uB41C \uAC83\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. Ctrl\uC774\uB098 Shift \uC5C6\uC774 \uD074\uB9AD\uD574 \uBB38\uB2E8 \uC804\uCCB4\uB97C \uC120\uD0DD\uD558\uAC70\uB098, \uC8FC\uC18C\uAC00 \uC788\uB294 run\uC744 \uAC00\uC9C4 \uBB38\uB2E8\uC774\uB098 \uC140\uC744 \uD074\uB9AD\uD558\uC138\uC694.",
4296
+ "segment.clickRefusedNoRuns": "\uD074\uB9AD\uD55C \uBB38\uB2E8\uC774\uB098 \uC140\uC5D0 \uCD94\uAC00\uD560 run\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uD14D\uC2A4\uD2B8\uAC00 \uC788\uB294 \uBB38\uB2E8\uC774\uB098 \uC140\uC744 \uD074\uB9AD\uD558\uC138\uC694.",
4317
4297
  "segment.selectSimilar": "\uC9C1\uC811 \uC11C\uC2DD\uC774 \uAC19\uC740 \uB0B4\uC6A9 \uC120\uD0DD",
4318
4298
  "segment.similarChar": "\uAC19\uC740 \uAE00\uC790 \uC11C\uC2DD",
4319
4299
  "segment.similarPara": "\uAC19\uC740 \uBB38\uB2E8 \uC11C\uC2DD",
@@ -4431,6 +4411,7 @@ var ko = {
4431
4411
  "error.staleCompose": "\uC0C8 \uBB38\uC11C\uB97C \uC791\uC131\uD558\uB294 \uB3D9\uC548 \uC5F4\uB9B0 \uBB38\uC11C\uAC00 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC791\uC131\uD558\uC138\uC694.",
4432
4412
  "error.stalePreview": "\uBBF8\uB9AC\uBCF4\uAE30\uB97C \uB9CC\uB4DC\uB294 \uB3D9\uC548 \uBB38\uC11C\uAC00 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uC5F4\uB9B0 \uBB38\uC11C\uC5D0\uC11C \uB2E4\uC2DC \uBBF8\uB9AC\uBCF4\uAE30\uD558\uC138\uC694.",
4433
4413
  "error.unmatchedReplace": "\uD574\uB2F9 \uBB38\uB2E8\uC5D0\uC11C \uBC14\uAFC0 \uD14D\uC2A4\uD2B8\uB97C \uC5D4\uC9C4\uC774 \uCC3E\uC9C0 \uBABB\uD574 \uC544\uBB34\uAC83\uB3C4 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uD14D\uC2A4\uD2B8\uB97C \uB2E4\uC2DC \uC120\uD0DD\uD55C \uB4A4 \uC7AC\uC2DC\uB3C4\uD558\uC138\uC694.",
4414
+ "error.unresolvableAddress": "\uC5D4\uC9C4\uC774 \uD3B8\uC9D1 \uB300\uC0C1 \uBB38\uB2E8\uC774\uB098 run\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC77C\uBD80 \uC911\uCCA9 \uBB38\uB2E8 \uC548\uC758 run\uC740 \uC5D4\uC9C4\uC774 \uC8FC\uC18C\uB85C \uC9C0\uC815\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uCD5C\uC0C1\uC704 \uBB38\uB2E8\uC774\uB098 \uD45C \uC140\uC758 \uD14D\uC2A4\uD2B8\uC5D0 \uC11C\uC2DD\uC744 \uC9C0\uC815\uD558\uAC70\uB098, \uC774 \uB300\uC0C1\uC740 \uC6CC\uB4DC\uD504\uB85C\uC138\uC11C\uC5D0\uC11C \uD3B8\uC9D1\uD558\uC138\uC694.",
4434
4415
  "error.runRangeConflict": "\uAC19\uC740 \uBB38\uB2E8\uC5D0 \uB300\uAE30 \uC911\uC778 \uC55E\uC120 \uBCC0\uACBD(\uD14D\uC2A4\uD2B8, \uB9C1\uD06C, \uD544\uB4DC, \uCC45\uAC08\uD53C, \uC774\uBBF8\uC9C0, \uC140)\uC774 \uBB38\uB2E8 \uD14D\uC2A4\uD2B8\uB97C \uBC14\uAFC0 \uC218 \uC788\uC5B4 run\uC774 \uB354 \uC774\uC0C1 \uAC19\uC740 \uAE00\uC790\uB97C \uAC00\uB9AC\uD0A4\uC9C0 \uC54A\uC744 \uC218 \uC788\uC73C\uBBC0\uB85C run \uC11C\uC2DD \uBCC0\uACBD\uC774 \uAC70\uBD80\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC544\uBB34\uAC83\uB3C4 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uB300\uAE30 \uBAA9\uB85D\uC5D0\uC11C \uC11C\uC2DD \uBCC0\uACBD\uC744 \uC81C\uAC70\uD558\uACE0 \uB098\uBA38\uC9C0\uB97C \uC801\uC6A9\uD55C \uB4A4 run \uC11C\uC2DD\uC744 \uB2E4\uC2DC \uC9C0\uC815\uD558\uAC70\uB098, \uC11C\uC2DD \uBCC0\uACBD\uC744 \uB2E4\uB978 \uBCC0\uACBD\uBCF4\uB2E4 \uBA3C\uC800 \uB300\uAE30\uC5F4\uC5D0 \uB123\uC73C\uC138\uC694.",
4435
4416
  "error.rangeTagRefused": "\uC774 HWP \uBB38\uC11C\uC5D0\uB294 \uC5D4\uC9C4\uC774 \uC62E\uAE38 \uC218 \uC5C6\uB294 \uAD6C\uAC04 \uD45C\uC2DC\uAC00 \uC788\uC5B4 \uB300\uAE30 \uC911\uC778 \uD3B8\uC9D1\uC774 \uAC70\uBD80\uB418\uC5C8\uACE0, \uC544\uBB34\uAC83\uB3C4 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uAD6C\uAC04 \uD45C\uC2DC \uC8FC\uBCC0\uC758 \uAE00\uC790\uB97C \uC6C0\uC9C1\uC774\uB294 \uD3B8\uC9D1\uC740 \uAC70\uBD80\uB429\uB2C8\uB2E4: \uBB38\uB2E8 \uD14D\uC2A4\uD2B8 \uAE38\uC774 \uBCC0\uACBD, \uAE38\uC774\uAC00 \uB2E4\uB978 \uD544\uB4DC \uAC12\uC73C\uB85C\uC758 \uBCC0\uACBD, \uB9C1\uD06C\xB7\uD544\uB4DC\xB7\uCC45\uAC08\uD53C\xB7\uC774\uBBF8\uC9C0\uC758 \uC0BD\uC785\uC774\uB098 \uC0AD\uC81C, \uD45C \uC0AD\uC81C. \uAD6C\uAC04 \uD45C\uC2DC\uAC00 \uC788\uB294 \uD45C \uC140\uC740 \uB0B4\uC6A9\uC744 \uC5B4\uB5BB\uAC8C \uBC14\uAFB8\uB4E0 \uAC70\uBD80\uD569\uB2C8\uB2E4. \uC5D4\uC9C4\uC740 \uC5B4\uB290 \uD3B8\uC9D1\uC778\uC9C0 \uC54C\uB824 \uC8FC\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uB300\uAE30 \uBAA9\uB85D\uC5D0\uC11C \uD574\uB2F9 \uD3B8\uC9D1\uC744 \uC81C\uAC70\uD558\uACE0(\uBB38\uB2E8 \uC548\uC758 \uAC19\uC740 \uAE38\uC774 \uD14D\uC2A4\uD2B8 \uCE58\uD658\uACFC \uAC19\uC740 \uAE38\uC774\uC758 \uD544\uB4DC \uAC12\uC740 \uD5C8\uC6A9\uB429\uB2C8\uB2E4) \uB098\uBA38\uC9C0\uB97C \uC801\uC6A9\uD558\uC138\uC694. \uADF8\uB7F0 \uD3B8\uC9D1\uC774 \uD544\uC694\uD558\uBA74 \uBB38\uC11C\uB97C HWPX\uB85C \uBCC0\uD658\uD558\uAC70\uB098(\uBCC0\uD658\uD558\uBA74 \uAD6C\uAC04 \uD45C\uC2DC\uAC00 \uC0AC\uB77C\uC9D1\uB2C8\uB2E4) \uD55C\uAE00\uC5D0\uC11C \uAD6C\uAC04 \uD45C\uC2DC\uB97C \uC81C\uAC70\uD55C \uB4A4 \uB2E4\uC2DC \uC5EC\uC138\uC694. \uB2E4\uC2DC \uC5F4\uBA74 \uB300\uAE30 \uBAA9\uB85D\uC740 \uC0AC\uB77C\uC9D1\uB2C8\uB2E4.",
4436
4417
  "error.noEngineCause": "\uC5D4\uC9C4\uC774 \uC6D0\uC778\uC744 \uBC1D\uD788\uC9C0 \uC54A\uACE0 \uC2E4\uD328\uD588\uC73C\uBBC0\uB85C(\uB300\uAC1C \uBE44\uC815\uC0C1 \uC885\uB8CC\uB41C \uACBD\uC6B0\uC785\uB2C8\uB2E4) \uC544\uBB34\uAC83\uB3C4 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC801\uC6A9\uD558\uACE0, \uAC19\uC740 \uBC29\uC2DD\uC73C\uB85C \uC2E4\uD328\uD558\uBA74 \uD638\uC2A4\uD2B8 \uB85C\uADF8\uC640 \uD568\uAED8 \uC54C\uB824 \uC8FC\uC138\uC694.",
@@ -4608,7 +4589,8 @@ var RENDER_SVG = { format: "svg" };
4608
4589
  var REFUSAL_MESSAGE = {
4609
4590
  unmatched_replace: "error.unmatchedReplace",
4610
4591
  run_range_conflict: "error.runRangeConflict",
4611
- range_tag: "error.rangeTagRefused"
4592
+ range_tag: "error.rangeTagRefused",
4593
+ unresolvable_address: "error.unresolvableAddress"
4612
4594
  };
4613
4595
  var HwpEditor = forwardRef(
4614
4596
  function HwpEditor2(props, ref) {
@@ -5477,6 +5459,31 @@ var HwpEditor = forwardRef(
5477
5459
  ) });
5478
5460
  }
5479
5461
  );
5462
+
5463
+ // src/sanitize.ts
5464
+ function sanitizeSvg(svgText) {
5465
+ const doc = new DOMParser().parseFromString(svgText, "image/svg+xml");
5466
+ const root = doc.documentElement;
5467
+ if (root === null || root.nodeName === "parsererror" || doc.getElementsByTagName("parsererror").length > 0) {
5468
+ return "";
5469
+ }
5470
+ const dangerous = root.querySelectorAll("script, foreignObject");
5471
+ for (const node of Array.from(dangerous)) node.remove();
5472
+ scrubElement(root);
5473
+ return root.outerHTML;
5474
+ }
5475
+ function scrubElement(el) {
5476
+ for (const attr of Array.from(el.attributes)) {
5477
+ const name = attr.name.toLowerCase();
5478
+ const value = attr.value.trim().toLowerCase();
5479
+ if (name.startsWith("on")) {
5480
+ el.removeAttribute(attr.name);
5481
+ } else if ((name === "href" || name === "xlink:href") && value.startsWith("javascript:")) {
5482
+ el.removeAttribute(attr.name);
5483
+ }
5484
+ }
5485
+ for (const child of Array.from(el.children)) scrubElement(child);
5486
+ }
5480
5487
  export {
5481
5488
  COMPOSE_PRESETS,
5482
5489
  ComponentsPanel,