@notectl/core 2.2.2 → 2.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/README.md +12 -0
  2. package/dist/chunks/AlignmentPlugin-BCHxo16v.mjs +2 -0
  3. package/dist/chunks/AlignmentPlugin-BCHxo16v.mjs.map +1 -0
  4. package/dist/chunks/{BidiIsolationPlugin-Bm3h9J15.mjs → BidiIsolationPlugin-BddRbDCN.mjs} +2 -2
  5. package/dist/chunks/{BidiIsolationPlugin-Bm3h9J15.mjs.map → BidiIsolationPlugin-BddRbDCN.mjs.map} +1 -1
  6. package/dist/chunks/{BlockquotePlugin-CxrCA0vY.mjs → BlockquotePlugin-4V7KV_Sb.mjs} +2 -2
  7. package/dist/chunks/{BlockquotePlugin-CxrCA0vY.mjs.map → BlockquotePlugin-4V7KV_Sb.mjs.map} +1 -1
  8. package/dist/chunks/{CaretNavigationPlugin-Bb7W_FMg.mjs → CaretNavigationPlugin-C6XBwp0N.mjs} +2 -2
  9. package/dist/chunks/{CaretNavigationPlugin-Bb7W_FMg.mjs.map → CaretNavigationPlugin-C6XBwp0N.mjs.map} +1 -1
  10. package/dist/chunks/{CodeBlockPlugin-Uv6EXaH1.mjs → CodeBlockPlugin-DC0-BnNy.mjs} +2 -2
  11. package/dist/chunks/{CodeBlockPlugin-Uv6EXaH1.mjs.map → CodeBlockPlugin-DC0-BnNy.mjs.map} +1 -1
  12. package/dist/chunks/{Commands-CyT1Li7_.mjs → Commands-BIIpx_Zd.mjs} +2 -2
  13. package/dist/chunks/Commands-BIIpx_Zd.mjs.map +1 -0
  14. package/dist/chunks/FontPlugin-DB1_bgam.mjs +2 -0
  15. package/dist/chunks/{FontPlugin-1VYDwETg.mjs.map → FontPlugin-DB1_bgam.mjs.map} +1 -1
  16. package/dist/chunks/{FontSizePlugin-L1uDVsKY.mjs → FontSizePlugin-DFvp7Ki9.mjs} +2 -2
  17. package/dist/chunks/{FontSizePlugin-L1uDVsKY.mjs.map → FontSizePlugin-DFvp7Ki9.mjs.map} +1 -1
  18. package/dist/chunks/{FormulaPlugin-UA-9tRpY.mjs → FormulaPlugin-BLEcyazj.mjs} +2 -2
  19. package/dist/chunks/{FormulaPlugin-UA-9tRpY.mjs.map → FormulaPlugin-BLEcyazj.mjs.map} +1 -1
  20. package/dist/chunks/GapCursorPlugin-Zvxjnr82.mjs +2 -0
  21. package/dist/chunks/{GapCursorPlugin-B29ieXel.mjs.map → GapCursorPlugin-Zvxjnr82.mjs.map} +1 -1
  22. package/dist/chunks/{HardBreakPlugin-BkgoJkjC.mjs → HardBreakPlugin-9DOyCyyM.mjs} +2 -2
  23. package/dist/chunks/{HardBreakPlugin-BkgoJkjC.mjs.map → HardBreakPlugin-9DOyCyyM.mjs.map} +1 -1
  24. package/dist/chunks/{HeadingPlugin-SICF6Tm0.mjs → HeadingPlugin-D9yvG2Aw.mjs} +2 -2
  25. package/dist/chunks/{HeadingPlugin-SICF6Tm0.mjs.map → HeadingPlugin-D9yvG2Aw.mjs.map} +1 -1
  26. package/dist/chunks/{HighlightPlugin-B3b_qe68.mjs → HighlightPlugin-D4gh4RP7.mjs} +2 -2
  27. package/dist/chunks/{HighlightPlugin-B3b_qe68.mjs.map → HighlightPlugin-D4gh4RP7.mjs.map} +1 -1
  28. package/dist/chunks/HorizontalRulePlugin-0FjHPZuA.mjs +2 -0
  29. package/dist/chunks/{HorizontalRulePlugin-BrFlrpmb.mjs.map → HorizontalRulePlugin-0FjHPZuA.mjs.map} +1 -1
  30. package/dist/chunks/{ImagePlugin-eRVtFFou.mjs → ImagePlugin-Cp_RINtc.mjs} +2 -2
  31. package/dist/chunks/{ImagePlugin-eRVtFFou.mjs.map → ImagePlugin-Cp_RINtc.mjs.map} +1 -1
  32. package/dist/chunks/{InlineCodePlugin-D3QulApr.mjs → InlineCodePlugin-DMr4O7c7.mjs} +2 -2
  33. package/dist/chunks/{InlineCodePlugin-D3QulApr.mjs.map → InlineCodePlugin-DMr4O7c7.mjs.map} +1 -1
  34. package/dist/chunks/LinkPlugin-DvZ3MPgL.mjs +2 -0
  35. package/dist/chunks/{LinkPlugin-B_ysjORS.mjs.map → LinkPlugin-DvZ3MPgL.mjs.map} +1 -1
  36. package/dist/chunks/{ListPlugin-C0BV8CnQ.mjs → ListPlugin-CVId2dE0.mjs} +2 -2
  37. package/dist/chunks/{ListPlugin-C0BV8CnQ.mjs.map → ListPlugin-CVId2dE0.mjs.map} +1 -1
  38. package/dist/chunks/PluginHelpers-KDuTlmXm.mjs +2 -0
  39. package/dist/chunks/{PluginHelpers-D4quRJ5a.mjs.map → PluginHelpers-KDuTlmXm.mjs.map} +1 -1
  40. package/dist/chunks/{PrintPlugin-CXDFFzWB.mjs → PrintPlugin-C6gOJT6d.mjs} +2 -2
  41. package/dist/chunks/{PrintPlugin-CXDFFzWB.mjs.map → PrintPlugin-C6gOJT6d.mjs.map} +1 -1
  42. package/dist/chunks/{SimpleMark-Db8ir_z2.mjs → SimpleMark-CaQtFAau.mjs} +2 -2
  43. package/dist/chunks/{SimpleMark-Db8ir_z2.mjs.map → SimpleMark-CaQtFAau.mjs.map} +1 -1
  44. package/dist/chunks/{SmartPastePlugin-Db1RcNJf.mjs → SmartPastePlugin-Bi_wpTCV.mjs} +2 -2
  45. package/dist/chunks/{SmartPastePlugin-Db1RcNJf.mjs.map → SmartPastePlugin-Bi_wpTCV.mjs.map} +1 -1
  46. package/dist/chunks/StrikethroughPlugin-BLKDRWtf.mjs +2 -0
  47. package/dist/chunks/{StrikethroughPlugin-Bsg7Ma4I.mjs.map → StrikethroughPlugin-BLKDRWtf.mjs.map} +1 -1
  48. package/dist/chunks/{SuperSubPlugin-ChEga-b_.mjs → SuperSubPlugin-DVP7VnIz.mjs} +2 -2
  49. package/dist/chunks/{SuperSubPlugin-ChEga-b_.mjs.map → SuperSubPlugin-DVP7VnIz.mjs.map} +1 -1
  50. package/dist/chunks/{TablePlugin-CRp4qSZE.mjs → TablePlugin-D93RR5xH.mjs} +2 -2
  51. package/dist/chunks/{TablePlugin-CRp4qSZE.mjs.map → TablePlugin-D93RR5xH.mjs.map} +1 -1
  52. package/dist/chunks/TextColorPlugin-C1qpzEOa.mjs +2 -0
  53. package/dist/chunks/{TextColorPlugin-CViEiYZk.mjs.map → TextColorPlugin-C1qpzEOa.mjs.map} +1 -1
  54. package/dist/chunks/TextDirectionPlugin-DHB88HKf.mjs +2 -0
  55. package/dist/chunks/TextDirectionPlugin-DHB88HKf.mjs.map +1 -0
  56. package/dist/chunks/{TextFormattingPlugin-Db5SCNOF.mjs → TextFormattingPlugin-Cubp3e7f.mjs} +2 -2
  57. package/dist/chunks/{TextFormattingPlugin-Db5SCNOF.mjs.map → TextFormattingPlugin-Cubp3e7f.mjs.map} +1 -1
  58. package/dist/chunks/{ToolbarPlugin-B5UUc6dY.mjs → ToolbarPlugin-CLz2wa2c.mjs} +2 -2
  59. package/dist/chunks/{ToolbarPlugin-B5UUc6dY.mjs.map → ToolbarPlugin-CLz2wa2c.mjs.map} +1 -1
  60. package/dist/chunks/{VideoPlugin-mXIDODzC.mjs → VideoPlugin-D9rQZol6.mjs} +2 -2
  61. package/dist/chunks/{VideoPlugin-mXIDODzC.mjs.map → VideoPlugin-D9rQZol6.mjs.map} +1 -1
  62. package/dist/chunks/full-Cah3qjCT.mjs +2 -0
  63. package/dist/chunks/{full--GEBZ2xU.mjs.map → full-Cah3qjCT.mjs.map} +1 -1
  64. package/dist/chunks/minimal-DqATlnAL.mjs +2 -0
  65. package/dist/chunks/{minimal-D5v-raei.mjs.map → minimal-DqATlnAL.mjs.map} +1 -1
  66. package/dist/chunks/{src-C5Lblp2i.mjs → src-YY6n2SmV.mjs} +2 -2
  67. package/dist/chunks/{src-C5Lblp2i.mjs.map → src-YY6n2SmV.mjs.map} +1 -1
  68. package/dist/commands/Commands.d.ts.map +1 -1
  69. package/dist/full.mjs +1 -1
  70. package/dist/notectl-core.mjs +1 -1
  71. package/dist/notectl-core.umd.js +1 -1
  72. package/dist/notectl-core.umd.js.map +1 -1
  73. package/dist/plugins/alignment/AlignmentPlugin.d.ts +5 -0
  74. package/dist/plugins/alignment/AlignmentPlugin.d.ts.map +1 -1
  75. package/dist/plugins/alignment.mjs +1 -1
  76. package/dist/plugins/bidi-isolation.mjs +1 -1
  77. package/dist/plugins/blockquote.mjs +1 -1
  78. package/dist/plugins/caret-navigation.mjs +1 -1
  79. package/dist/plugins/code-block.mjs +1 -1
  80. package/dist/plugins/font-size.mjs +1 -1
  81. package/dist/plugins/font.mjs +1 -1
  82. package/dist/plugins/formula.mjs +1 -1
  83. package/dist/plugins/gap-cursor.mjs +1 -1
  84. package/dist/plugins/hard-break.mjs +1 -1
  85. package/dist/plugins/heading.mjs +1 -1
  86. package/dist/plugins/highlight.mjs +1 -1
  87. package/dist/plugins/horizontal-rule.mjs +1 -1
  88. package/dist/plugins/image.mjs +1 -1
  89. package/dist/plugins/inline-code.mjs +1 -1
  90. package/dist/plugins/link.mjs +1 -1
  91. package/dist/plugins/list.mjs +1 -1
  92. package/dist/plugins/print.mjs +1 -1
  93. package/dist/plugins/shared/PluginHelpers.d.ts +8 -0
  94. package/dist/plugins/shared/PluginHelpers.d.ts.map +1 -1
  95. package/dist/plugins/shared.mjs +1 -1
  96. package/dist/plugins/smart-paste.mjs +1 -1
  97. package/dist/plugins/strikethrough.mjs +1 -1
  98. package/dist/plugins/super-sub.mjs +1 -1
  99. package/dist/plugins/table/TableNodeViews.d.ts.map +1 -1
  100. package/dist/plugins/table.mjs +1 -1
  101. package/dist/plugins/text-color.mjs +1 -1
  102. package/dist/plugins/text-direction/TextDirectionPlugin.d.ts +0 -1
  103. package/dist/plugins/text-direction/TextDirectionPlugin.d.ts.map +1 -1
  104. package/dist/plugins/text-direction.mjs +1 -1
  105. package/dist/plugins/text-formatting.mjs +1 -1
  106. package/dist/plugins/toolbar.mjs +1 -1
  107. package/dist/plugins/video.mjs +1 -1
  108. package/dist/presets/full.mjs +1 -1
  109. package/dist/presets/minimal.mjs +1 -1
  110. package/dist/presets.mjs +1 -1
  111. package/package.json +415 -423
  112. package/dist/chunks/AlignmentPlugin-h6sx-yIf.mjs +0 -2
  113. package/dist/chunks/AlignmentPlugin-h6sx-yIf.mjs.map +0 -1
  114. package/dist/chunks/Commands-CyT1Li7_.mjs.map +0 -1
  115. package/dist/chunks/FontPlugin-1VYDwETg.mjs +0 -2
  116. package/dist/chunks/GapCursorPlugin-B29ieXel.mjs +0 -2
  117. package/dist/chunks/HorizontalRulePlugin-BrFlrpmb.mjs +0 -2
  118. package/dist/chunks/LinkPlugin-B_ysjORS.mjs +0 -2
  119. package/dist/chunks/PluginHelpers-D4quRJ5a.mjs +0 -2
  120. package/dist/chunks/StrikethroughPlugin-Bsg7Ma4I.mjs +0 -2
  121. package/dist/chunks/TextColorPlugin-CViEiYZk.mjs +0 -2
  122. package/dist/chunks/TextDirectionPlugin-CQGkaS2s.mjs +0 -2
  123. package/dist/chunks/TextDirectionPlugin-CQGkaS2s.mjs.map +0 -1
  124. package/dist/chunks/full--GEBZ2xU.mjs +0 -2
  125. package/dist/chunks/minimal-D5v-raei.mjs +0 -2
package/README.md CHANGED
@@ -35,6 +35,18 @@ Build a real editor in plain HTML, React, Vue, Svelte, or Angular without lockin
35
35
  - CSP-safe styling with `adoptedStyleSheets`
36
36
  - A fast path for "just give me a full editor" and a granular path for "I only want these plugins"
37
37
 
38
+ ## In a team collaboration app
39
+
40
+ notectl is built to live inside real products. Here it powers the card description editor in a Trello-style board, sitting naturally next to checklists, due dates, labels, and assignees:
41
+
42
+ <div align="center">
43
+
44
+ <img src="media/notectl-team-collab-card.png" alt="notectl as the description editor inside a Trello-style team collaboration card" width="720" />
45
+
46
+ </div>
47
+
48
+ Because the editor is a Web Component, dropping it into an existing card, ticket, or comment surface is just mounting one custom element. You get a full rich-text toolbar, keyboard shortcuts, and accessible markup without pulling a framework-specific editor runtime into your app.
49
+
38
50
  ## Install
39
51
 
40
52
  ```bash
@@ -0,0 +1,2 @@
1
+ import{s as t}from"./StyleRuntime-BAutwDZT.mjs";import{a as e,c as s,n as i,o as n,r as a,t as l}from"./PluginHelpers-KDuTlmXm.mjs";import{t as o}from"./NodeSpecPatching-B_yLknTl.mjs";var r={alignStart:"Align Start",alignCenter:"Align Center",alignEnd:"Align End",justify:"Justify",toolbarLabel:"Alignment",toolbarTooltip:"Alignment"},g=/* #__PURE__ */Object.assign({"./locales/ar.ts":()=>import("./ar-Bdmunk5h.mjs"),"./locales/de.ts":()=>import("./de-B8-w9gPi.mjs"),"./locales/es.ts":()=>import("./es-B8K3Yvf3.mjs"),"./locales/fr.ts":()=>import("./fr-BeRlON1t.mjs"),"./locales/hi.ts":()=>import("./hi-Bl-yeeOI.mjs"),"./locales/pt.ts":()=>import("./pt-5VeuNDd2.mjs"),"./locales/ru.ts":()=>import("./ru-Yngw7nFP.mjs"),"./locales/zh.ts":()=>import("./zh-BvuAbM2S.mjs")});async function m(t){return s(g,t,r)}var c={alignments:["start","center","end","justify"],alignableTypes:["paragraph","heading","title","subtitle","table_cell","image"],defaults:{image:"center"}},h={start:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z"/></svg>',center:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z"/></svg>',end:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z"/></svg>',justify:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 21h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18V7H3v2zM3 3v2h18V3H3z"/></svg>'},p=class{id="alignment";name="Alignment";priority=90;config;locale;alignableTypes;constructor(t){this.config={...c,...t,defaults:{...c.defaults,...t?.defaults}}}async init(t){this.locale=await n(t,this.config.locale,r,m),this.alignableTypes=new Set(this.config.alignableTypes),this.patchNodeSpecs(t),this.registerCommands(t),this.registerKeymaps(t),this.registerToolbarItem(t),this.registerMiddleware(t)}patchNodeSpecs(t){o(t.getSchemaRegistry(),this.config.alignableTypes,{attrName:"align",getDefault:t=>this.config.defaults[t]??"start",applyToDOM:d})}registerCommands(t){for(const e of this.config.alignments)t.registerCommand(`align${l(e)}`,()=>this.setAlignment(t,e))}registerKeymaps(t){const e={};this.config.alignments.includes("start")&&(e["Mod-Shift-L"]=()=>t.executeCommand("alignStart")),this.config.alignments.includes("center")&&(e["Mod-Shift-E"]=()=>t.executeCommand("alignCenter")),this.config.alignments.includes("end")&&(e["Mod-Shift-R"]=()=>t.executeCommand("alignEnd")),this.config.alignments.includes("justify")&&(e["Mod-Shift-J"]=()=>t.executeCommand("alignJustify")),Object.keys(e).length>0&&t.registerKeymap(e)}registerToolbarItem(t){const e=this.config.alignments.map(t=>({label:this.getAlignmentLabel(t),command:`align${l(t)}`,icon:h[t]}));t.registerToolbarItem({id:"alignment",group:"block",icon:h.start,label:this.locale.toolbarLabel,tooltip:this.locale.toolbarTooltip,command:"alignStart",popupType:"dropdown",popupConfig:{items:e},isActive:t=>this.isNonDefaultAlignment(t),isEnabled:t=>this.isAlignable(t)})}getAlignmentLabel(t){return{start:this.locale.alignStart,center:this.locale.alignCenter,end:this.locale.alignEnd,justify:this.locale.justify}[t]}registerMiddleware(t){t.registerMiddleware((t,e,s)=>{let i=!1;const n=t.steps.map(t=>{if("setBlockType"!==t.type)return t;if(!this.alignableTypes.has(t.nodeType))return t;const e=t.previousAttrs?.align;return e&&"start"!==e?(i=!0,{...t,attrs:{...t.attrs,align:e}}):t});s(i?{...t,steps:n}:t)},{name:"alignment:preserve-align"})}setAlignment(t,s){const n=t.getState(),a=e(n);if(0===a.length)return!1;const l=n.transaction("command");let o=!1;for(const e of a){const t=n.getBlock(e);if(!t||!this.alignableTypes.has(t.type))continue;const i=n.getNodePath(e);i&&(l.setNodeAttr(i,{...t.attrs,align:s}),o=!0)}return!!o&&i(t,l.setSelection(n.selection).build())}isNonDefaultAlignment(t){const e=a(t);if(!e||!this.alignableTypes.has(e.type))return!1;const s=e.attrs?.align,i=this.config.defaults[e.type]??"start";return null!=s&&s!==i}isAlignable(t){const e=a(t);return null!=e&&this.alignableTypes.has(e.type)}};function d(e,s){const i=s.attrs?.align;"string"==typeof i&&"start"!==i&&t(e,"textAlign",i)}export{m as i,p as n,r,h as t};
2
+ //# sourceMappingURL=AlignmentPlugin-BCHxo16v.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AlignmentPlugin-BCHxo16v.mjs","names":[],"sources":["../../src/plugins/alignment/AlignmentLocale.ts","../../src/plugins/alignment/AlignmentPlugin.ts"],"sourcesContent":["/** Locale interface and default English locale for the AlignmentPlugin. */\n\nimport { type LocaleModuleMap, loadLocaleModule } from '../shared/LocaleLoader.js';\n\nexport interface AlignmentLocale {\n\treadonly alignStart: string;\n\treadonly alignCenter: string;\n\treadonly alignEnd: string;\n\treadonly justify: string;\n\treadonly toolbarLabel: string;\n\treadonly toolbarTooltip: string;\n}\n\n// --- Default English Locale ---\n\nexport const ALIGNMENT_LOCALE_EN: AlignmentLocale = {\n\talignStart: 'Align Start',\n\talignCenter: 'Align Center',\n\talignEnd: 'Align End',\n\tjustify: 'Justify',\n\ttoolbarLabel: 'Alignment',\n\ttoolbarTooltip: 'Alignment',\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: LocaleModuleMap<AlignmentLocale> = import.meta.glob<{\n\tdefault: AlignmentLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadAlignmentLocale(lang: string): Promise<AlignmentLocale> {\n\treturn loadLocaleModule(localeModules, lang, ALIGNMENT_LOCALE_EN);\n}\n","/**\n * AlignmentPlugin: adds start/center/end/justify alignment as a block\n * attribute on paragraphs, headings, images, and other alignable types.\n * Uses logical values (`start`/`end`) instead of physical (`left`/`right`)\n * for correct behavior with RTL text direction. Patches NodeSpecs to render\n * the `align` attribute via inline `text-align` style and provides toggle\n * commands, keyboard shortcuts, and a toolbar dropdown.\n */\n\nimport type { BlockAlignment } from '../../model/BlockAlignment.js';\nimport type { BlockNode } from '../../model/Document.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport { setStyleProperty } from '../../style/StyleRuntime.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { patchNodeSpecAttr } from '../shared/NodeSpecPatching.js';\nimport {\n\tcapitalize,\n\tdispatchIfPresent,\n\tgetSelectedBlock,\n\tgetSelectedBlockIds,\n\tresolveLocale,\n} from '../shared/PluginHelpers.js';\nimport {\n\tALIGNMENT_LOCALE_EN,\n\ttype AlignmentLocale,\n\tloadAlignmentLocale,\n} from './AlignmentLocale.js';\n\n// --- Public Types ---\n\nexport interface AlignmentConfig {\n\t/** Which alignments to expose. Defaults to all four. */\n\treadonly alignments: readonly BlockAlignment[];\n\t/** Block types that support alignment. Defaults to paragraph + heading + title + subtitle + table_cell + image. */\n\treadonly alignableTypes: readonly string[];\n\t/** Per-type default alignment (e.g. `{ image: 'center' }`). Falls back to `'start'`. */\n\treadonly defaults: Readonly<Record<string, BlockAlignment>>;\n\treadonly locale?: AlignmentLocale;\n}\n\n// --- Constants ---\n\nconst DEFAULT_CONFIG: AlignmentConfig = {\n\talignments: ['start', 'center', 'end', 'justify'],\n\talignableTypes: ['paragraph', 'heading', 'title', 'subtitle', 'table_cell', 'image'],\n\tdefaults: { image: 'center' },\n};\n\nexport const ALIGNMENT_ICONS: Readonly<Record<BlockAlignment, string>> = {\n\tstart:\n\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z\"/></svg>',\n\tcenter:\n\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z\"/></svg>',\n\tend: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z\"/></svg>',\n\tjustify:\n\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M3 21h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18V7H3v2zM3 3v2h18V3H3z\"/></svg>',\n};\n\n// --- Plugin ---\n\nexport class AlignmentPlugin implements Plugin {\n\treadonly id = 'alignment';\n\treadonly name = 'Alignment';\n\treadonly priority = 90;\n\n\tprivate readonly config: AlignmentConfig;\n\tprivate locale!: AlignmentLocale;\n\tprivate alignableTypes!: ReadonlySet<string>;\n\n\tconstructor(config?: Partial<AlignmentConfig>) {\n\t\tthis.config = {\n\t\t\t...DEFAULT_CONFIG,\n\t\t\t...config,\n\t\t\tdefaults: { ...DEFAULT_CONFIG.defaults, ...config?.defaults },\n\t\t};\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tALIGNMENT_LOCALE_EN,\n\t\t\tloadAlignmentLocale,\n\t\t);\n\n\t\tthis.alignableTypes = new Set(this.config.alignableTypes);\n\t\tthis.patchNodeSpecs(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymaps(context);\n\t\tthis.registerToolbarItem(context);\n\t\tthis.registerMiddleware(context);\n\t}\n\n\t// --- NodeSpec Patching ---\n\n\t/**\n\t * Patches existing NodeSpecs for alignable block types to support the\n\t * `align` attribute and render it as an inline style. Skips types\n\t * that already define an `align` attribute in their spec.\n\t */\n\tprivate patchNodeSpecs(context: PluginContext): void {\n\t\tpatchNodeSpecAttr(context.getSchemaRegistry(), this.config.alignableTypes, {\n\t\t\tattrName: 'align',\n\t\t\tgetDefault: (type) => this.config.defaults[type] ?? 'start',\n\t\t\tapplyToDOM: applyAlignment,\n\t\t});\n\t}\n\n\t// --- Commands ---\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tfor (const alignment of this.config.alignments) {\n\t\t\tcontext.registerCommand(`align${capitalize(alignment)}`, () => {\n\t\t\t\treturn this.setAlignment(context, alignment);\n\t\t\t});\n\t\t}\n\t}\n\n\t// --- Keymaps ---\n\n\tprivate registerKeymaps(context: PluginContext): void {\n\t\tconst bindings: Record<string, () => boolean> = {};\n\n\t\tif (this.config.alignments.includes('start')) {\n\t\t\tbindings['Mod-Shift-L'] = () => context.executeCommand('alignStart');\n\t\t}\n\t\tif (this.config.alignments.includes('center')) {\n\t\t\tbindings['Mod-Shift-E'] = () => context.executeCommand('alignCenter');\n\t\t}\n\t\tif (this.config.alignments.includes('end')) {\n\t\t\tbindings['Mod-Shift-R'] = () => context.executeCommand('alignEnd');\n\t\t}\n\t\tif (this.config.alignments.includes('justify')) {\n\t\t\tbindings['Mod-Shift-J'] = () => context.executeCommand('alignJustify');\n\t\t}\n\n\t\tif (Object.keys(bindings).length > 0) {\n\t\t\tcontext.registerKeymap(bindings);\n\t\t}\n\t}\n\n\t// --- Toolbar ---\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst dropdownItems = this.config.alignments.map((alignment) => ({\n\t\t\tlabel: this.getAlignmentLabel(alignment),\n\t\t\tcommand: `align${capitalize(alignment)}`,\n\t\t\ticon: ALIGNMENT_ICONS[alignment],\n\t\t}));\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'alignment',\n\t\t\tgroup: 'block',\n\t\t\ticon: ALIGNMENT_ICONS.start,\n\t\t\tlabel: this.locale.toolbarLabel,\n\t\t\ttooltip: this.locale.toolbarTooltip,\n\t\t\tcommand: 'alignStart',\n\t\t\tpopupType: 'dropdown',\n\t\t\tpopupConfig: { items: dropdownItems },\n\t\t\tisActive: (state) => this.isNonDefaultAlignment(state),\n\t\t\tisEnabled: (state) => this.isAlignable(state),\n\t\t});\n\t}\n\n\tprivate getAlignmentLabel(alignment: BlockAlignment): string {\n\t\tconst labels: Record<BlockAlignment, string> = {\n\t\t\tstart: this.locale.alignStart,\n\t\t\tcenter: this.locale.alignCenter,\n\t\t\tend: this.locale.alignEnd,\n\t\t\tjustify: this.locale.justify,\n\t\t};\n\t\treturn labels[alignment];\n\t}\n\n\t// --- Middleware ---\n\n\t/**\n\t * Preserves the `align` attribute when other plugins change the block\n\t * type (e.g. paragraph → heading) via `setBlockType`, which replaces attrs.\n\t */\n\tprivate registerMiddleware(context: PluginContext): void {\n\t\tcontext.registerMiddleware(\n\t\t\t(tr, _state, next) => {\n\t\t\t\tlet patched = false;\n\n\t\t\t\tconst patchedSteps = tr.steps.map((step) => {\n\t\t\t\t\tif (step.type !== 'setBlockType') return step;\n\t\t\t\t\tif (!this.alignableTypes.has(step.nodeType)) return step;\n\n\t\t\t\t\tconst prevAlign = step.previousAttrs?.align;\n\t\t\t\t\tif (!prevAlign || prevAlign === 'start') return step;\n\n\t\t\t\t\t// Carry forward align into new attrs\n\t\t\t\t\tpatched = true;\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...step,\n\t\t\t\t\t\tattrs: { ...step.attrs, align: prevAlign },\n\t\t\t\t\t};\n\t\t\t\t});\n\n\t\t\t\tnext(patched ? { ...tr, steps: patchedSteps } : tr);\n\t\t\t},\n\t\t\t{ name: 'alignment:preserve-align' },\n\t\t);\n\t}\n\n\t// --- Alignment Logic ---\n\n\t/**\n\t * Applies `alignment` to every alignable block in the current selection in\n\t * a single transaction. A multi-block selection aligns all of its blocks,\n\t * not just the anchor; non-alignable blocks in the range are left untouched.\n\t */\n\tprivate setAlignment(context: PluginContext, alignment: BlockAlignment): boolean {\n\t\tconst state = context.getState();\n\t\tconst blockIds: BlockId[] = getSelectedBlockIds(state);\n\t\tif (blockIds.length === 0) return false;\n\n\t\tconst tb = state.transaction('command');\n\t\tlet changed = false;\n\n\t\tfor (const id of blockIds) {\n\t\t\tconst block = state.getBlock(id);\n\t\t\tif (!block || !this.alignableTypes.has(block.type)) continue;\n\n\t\t\tconst path = state.getNodePath(id);\n\t\t\tif (!path) continue;\n\n\t\t\ttb.setNodeAttr(path, { ...block.attrs, align: alignment });\n\t\t\tchanged = true;\n\t\t}\n\n\t\tif (!changed) return false;\n\n\t\treturn dispatchIfPresent(context, tb.setSelection(state.selection).build());\n\t}\n\n\tprivate isNonDefaultAlignment(state: EditorState): boolean {\n\t\tconst block = getSelectedBlock(state);\n\t\tif (!block || !this.alignableTypes.has(block.type)) return false;\n\t\tconst align = block.attrs?.align;\n\t\tconst defaultAlign: BlockAlignment = this.config.defaults[block.type] ?? 'start';\n\t\treturn align != null && align !== defaultAlign;\n\t}\n\n\tprivate isAlignable(state: EditorState): boolean {\n\t\tconst block = getSelectedBlock(state);\n\t\treturn block != null && this.alignableTypes.has(block.type);\n\t}\n}\n\n// --- Helpers ---\n\nfunction applyAlignment(el: HTMLElement, node: BlockNode): void {\n\tconst align = node.attrs?.align;\n\tif (typeof align === 'string' && align !== 'start') {\n\t\tsetStyleProperty(el, 'textAlign', align);\n\t}\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{o as i,u as t}from"./Selection-HYoVFpAx.mjs";import{i as e}from"./TypeBrands-Ch9856Gb.mjs";import{r as o}from"./HTMLUtils-C6B4UT00.mjs";import{i as n,r,t as s}from"./AttributedMarkCommands-D4W2Jgpj.mjs";import{a as l,n as a,r as m,s as c}from"./PluginHelpers-D4quRJ5a.mjs";import{t as d}from"./ShortcutFormatting-TwiufqeV.mjs";import{t as g}from"./DirectionIcons-Bbawl9ei.mjs";import{t as p}from"./TextDirectionService-OFOU6r_s.mjs";var u={inlineLTR:"Inline LTR",inlineRTL:"Inline RTL",inlineAuto:"Inline Auto",inlineLabel:"Inline Direction",inlineTooltip:"Inline Direction",announceRemoveBidi:"Inline direction isolation removed"},h=/* #__PURE__ */Object.assign({"./locales/ar.ts":()=>import("./ar-B03uY4xr.mjs"),"./locales/de.ts":()=>import("./de-XCCpWyg0.mjs"),"./locales/es.ts":()=>import("./es-B0Za939C.mjs"),"./locales/fr.ts":()=>import("./fr-DciSEykY.mjs"),"./locales/hi.ts":()=>import("./hi-j3TDLMYd.mjs"),"./locales/pt.ts":()=>import("./pt-CEUgbrii.mjs"),"./locales/ru.ts":()=>import("./ru-BNPUT-3S.mjs"),"./locales/zh.ts":()=>import("./zh-Oj-qSUEp.mjs")});async function B(i){return c(h,i,u)}var v=class{id="bidi-isolation";name="Bidi Isolation";priority=92;config;locale;constructor(i){this.config={...i}}async init(i){this.locale=await l(i,this.config.locale,u,B),this.registerBdiMark(i),this.registerCommands(i),this.registerKeymaps(i),this.registerInlineToolbarItem(i)}registerBdiMark(i){i.registerMarkSpec({type:"bdi",rank:10,attrs:{dir:{default:"auto"}},toDOM(i){const t=document.createElement("bdi"),e=String(i.attrs?.dir??"auto");return t.setAttribute("dir",e),t},toHTMLString:(i,t)=>`<bdi dir="${o(String(i.attrs?.dir??"auto"))}">${t}</bdi>`,parseHTML:[{tag:"bdi",getAttrs:i=>{const t=i.getAttribute("dir");return"ltr"===t||"rtl"===t?{dir:t}:{dir:"auto"}}}],sanitize:{tags:["bdi"],attrs:["dir"]}})}registerCommands(i){i.registerCommand("toggleBidiLTR",()=>{const t=this.applyBdi(i,"ltr");return t&&i.announce(this.locale.inlineLTR),t}),i.registerCommand("toggleBidiRTL",()=>{const t=this.applyBdi(i,"rtl");return t&&i.announce(this.locale.inlineRTL),t}),i.registerCommand("toggleBidiAuto",()=>{const t=this.applyBdi(i,"auto");return t&&i.announce(this.locale.inlineAuto),t}),i.registerCommand("removeBidi",()=>{const t=this.removeBdi(i);return t&&i.announce(this.locale.announceRemoveBidi),t}),i.registerCommand("toggleBidiIsolation",()=>this.toggleBidiIsolation(i))}registerKeymaps(i){i.registerKeymap({"Mod-Shift-B":()=>i.executeCommand("toggleBidiIsolation")})}registerInlineToolbarItem(e){const o=[{label:this.locale.inlineLTR,command:"toggleBidiLTR",icon:g.ltr},{label:this.locale.inlineRTL,command:"toggleBidiRTL",icon:g.rtl},{label:this.locale.inlineAuto,command:"toggleBidiAuto",icon:g.auto},{label:this.locale.announceRemoveBidi,command:"removeBidi"}];e.registerToolbarItem({id:"inline-direction",group:"format",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4v7h2V4h2v7h2V4h1V2H10a3 3 0 1 0 0 6zm-3.5 9.5L3 17l3.5 3.5V18h3v-2h-3v-2.5zm14 0L17 17l3.5 3.5V18h-3v-2h3v-2.5zM11 16h2v6h-2z"/></svg>',label:this.locale.inlineLabel,tooltip:`${this.locale.inlineTooltip} (${d("Mod-Shift-B")})`,command:"toggleBidiIsolation",popupType:"dropdown",popupConfig:{items:o},isActive:i=>r(i,"bdi"),isEnabled:e=>{const o=e.selection;return t(o)&&!i(o)}})}toggleBidiIsolation(i){const t=i.getState();if(r(t,"bdi")){const t=this.removeBdi(i);return t&&i.announce(this.locale.announceRemoveBidi),t}const e=m(t),o=i.getService(p),n="rtl"===(e&&o?o.getBlockDir(e):"auto")?"ltr":"rtl",s=this.applyBdi(i,n);if(s){const t="ltr"===n?this.locale.inlineLTR:this.locale.inlineRTL;i.announce(t)}return s}applyBdi(i,t){return a(i,s(i.getState(),{type:e("bdi"),attrs:{dir:t}}))}removeBdi(i){return a(i,n(i.getState(),e("bdi")))}};export{u as n,B as r,v as t};
2
- //# sourceMappingURL=BidiIsolationPlugin-Bm3h9J15.mjs.map
1
+ import{o as i,u as t}from"./Selection-HYoVFpAx.mjs";import{i as e}from"./TypeBrands-Ch9856Gb.mjs";import{r as o}from"./HTMLUtils-C6B4UT00.mjs";import{i as n,r,t as s}from"./AttributedMarkCommands-D4W2Jgpj.mjs";import{c as l,n as a,o as m,r as c}from"./PluginHelpers-KDuTlmXm.mjs";import{t as d}from"./ShortcutFormatting-TwiufqeV.mjs";import{t as g}from"./DirectionIcons-Bbawl9ei.mjs";import{t as p}from"./TextDirectionService-OFOU6r_s.mjs";var u={inlineLTR:"Inline LTR",inlineRTL:"Inline RTL",inlineAuto:"Inline Auto",inlineLabel:"Inline Direction",inlineTooltip:"Inline Direction",announceRemoveBidi:"Inline direction isolation removed"},h=/* #__PURE__ */Object.assign({"./locales/ar.ts":()=>import("./ar-B03uY4xr.mjs"),"./locales/de.ts":()=>import("./de-XCCpWyg0.mjs"),"./locales/es.ts":()=>import("./es-B0Za939C.mjs"),"./locales/fr.ts":()=>import("./fr-DciSEykY.mjs"),"./locales/hi.ts":()=>import("./hi-j3TDLMYd.mjs"),"./locales/pt.ts":()=>import("./pt-CEUgbrii.mjs"),"./locales/ru.ts":()=>import("./ru-BNPUT-3S.mjs"),"./locales/zh.ts":()=>import("./zh-Oj-qSUEp.mjs")});async function B(i){return l(h,i,u)}var v=class{id="bidi-isolation";name="Bidi Isolation";priority=92;config;locale;constructor(i){this.config={...i}}async init(i){this.locale=await m(i,this.config.locale,u,B),this.registerBdiMark(i),this.registerCommands(i),this.registerKeymaps(i),this.registerInlineToolbarItem(i)}registerBdiMark(i){i.registerMarkSpec({type:"bdi",rank:10,attrs:{dir:{default:"auto"}},toDOM(i){const t=document.createElement("bdi"),e=String(i.attrs?.dir??"auto");return t.setAttribute("dir",e),t},toHTMLString:(i,t)=>`<bdi dir="${o(String(i.attrs?.dir??"auto"))}">${t}</bdi>`,parseHTML:[{tag:"bdi",getAttrs:i=>{const t=i.getAttribute("dir");return"ltr"===t||"rtl"===t?{dir:t}:{dir:"auto"}}}],sanitize:{tags:["bdi"],attrs:["dir"]}})}registerCommands(i){i.registerCommand("toggleBidiLTR",()=>{const t=this.applyBdi(i,"ltr");return t&&i.announce(this.locale.inlineLTR),t}),i.registerCommand("toggleBidiRTL",()=>{const t=this.applyBdi(i,"rtl");return t&&i.announce(this.locale.inlineRTL),t}),i.registerCommand("toggleBidiAuto",()=>{const t=this.applyBdi(i,"auto");return t&&i.announce(this.locale.inlineAuto),t}),i.registerCommand("removeBidi",()=>{const t=this.removeBdi(i);return t&&i.announce(this.locale.announceRemoveBidi),t}),i.registerCommand("toggleBidiIsolation",()=>this.toggleBidiIsolation(i))}registerKeymaps(i){i.registerKeymap({"Mod-Shift-B":()=>i.executeCommand("toggleBidiIsolation")})}registerInlineToolbarItem(e){const o=[{label:this.locale.inlineLTR,command:"toggleBidiLTR",icon:g.ltr},{label:this.locale.inlineRTL,command:"toggleBidiRTL",icon:g.rtl},{label:this.locale.inlineAuto,command:"toggleBidiAuto",icon:g.auto},{label:this.locale.announceRemoveBidi,command:"removeBidi"}];e.registerToolbarItem({id:"inline-direction",group:"format",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4v7h2V4h2v7h2V4h1V2H10a3 3 0 1 0 0 6zm-3.5 9.5L3 17l3.5 3.5V18h3v-2h-3v-2.5zm14 0L17 17l3.5 3.5V18h-3v-2h3v-2.5zM11 16h2v6h-2z"/></svg>',label:this.locale.inlineLabel,tooltip:`${this.locale.inlineTooltip} (${d("Mod-Shift-B")})`,command:"toggleBidiIsolation",popupType:"dropdown",popupConfig:{items:o},isActive:i=>r(i,"bdi"),isEnabled:e=>{const o=e.selection;return t(o)&&!i(o)}})}toggleBidiIsolation(i){const t=i.getState();if(r(t,"bdi")){const t=this.removeBdi(i);return t&&i.announce(this.locale.announceRemoveBidi),t}const e=c(t),o=i.getService(p),n="rtl"===(e&&o?o.getBlockDir(e):"auto")?"ltr":"rtl",s=this.applyBdi(i,n);if(s){const t="ltr"===n?this.locale.inlineLTR:this.locale.inlineRTL;i.announce(t)}return s}applyBdi(i,t){return a(i,s(i.getState(),{type:e("bdi"),attrs:{dir:t}}))}removeBdi(i){return a(i,n(i.getState(),e("bdi")))}};export{u as n,B as r,v as t};
2
+ //# sourceMappingURL=BidiIsolationPlugin-BddRbDCN.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"BidiIsolationPlugin-Bm3h9J15.mjs","names":[],"sources":["../../src/plugins/bidi-isolation/BidiIsolationLocale.ts","../../src/plugins/bidi-isolation/BidiIsolationPlugin.ts"],"sourcesContent":["/** Locale interface and default English locale for the BidiIsolationPlugin. */\n\nimport { type LocaleModuleMap, loadLocaleModule } from '../shared/LocaleLoader.js';\n\nexport interface BidiIsolationLocale {\n\treadonly inlineLTR: string;\n\treadonly inlineRTL: string;\n\treadonly inlineAuto: string;\n\treadonly inlineLabel: string;\n\treadonly inlineTooltip: string;\n\treadonly announceRemoveBidi: string;\n}\n\nexport const BIDI_ISOLATION_LOCALE_EN: BidiIsolationLocale = {\n\tinlineLTR: 'Inline LTR',\n\tinlineRTL: 'Inline RTL',\n\tinlineAuto: 'Inline Auto',\n\tinlineLabel: 'Inline Direction',\n\tinlineTooltip: 'Inline Direction',\n\tannounceRemoveBidi: 'Inline direction isolation removed',\n};\n\nconst localeModules: LocaleModuleMap<BidiIsolationLocale> = import.meta.glob<{\n\tdefault: BidiIsolationLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadBidiIsolationLocale(lang: string): Promise<BidiIsolationLocale> {\n\treturn loadLocaleModule(localeModules, lang, BIDI_ISOLATION_LOCALE_EN);\n}\n","/**\n * Inline bidi isolation plugin: registers a `<bdi>` mark and the inline\n * commands / toolbar / keymap that wrap selected text in a `<bdi>` element\n * with an explicit `dir` attribute.\n *\n * Use alongside {@link TextDirectionPlugin} for the full RTL story:\n * block-level direction lives there, the optional `TextDirectionService`\n * lets this plugin pick the inline direction opposite to the block direction\n * in `toggleBidiIsolation`. Without `TextDirectionPlugin`, this plugin\n * still works — `toggleBidiIsolation` falls back to applying `'rtl'`.\n */\n\nimport {\n\tapplyAttributedMark,\n\tisAttributedMarkActive,\n\tremoveAttributedMark,\n} from '../../commands/AttributedMarkCommands.js';\nimport { escapeHTML } from '../../model/HTMLUtils.js';\nimport { isCollapsed, isTextSelection } from '../../model/Selection.js';\nimport { markType } from '../../model/TypeBrands.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { dispatchIfPresent, getSelectedBlock, resolveLocale } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { DIRECTION_ICONS } from '../text-direction/DirectionIcons.js';\nimport {\n\tTEXT_DIRECTION_SERVICE_KEY,\n\ttype TextDirection,\n\ttype TextDirectionService,\n} from '../text-direction/TextDirectionService.js';\nimport {\n\tBIDI_ISOLATION_LOCALE_EN,\n\ttype BidiIsolationLocale,\n\tloadBidiIsolationLocale,\n} from './BidiIsolationLocale.js';\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\tbdi: { dir: 'ltr' | 'rtl' | 'auto' };\n\t}\n}\n\nexport interface BidiIsolationConfig {\n\treadonly locale?: BidiIsolationLocale;\n}\n\nconst INLINE_BDI_ICON: string =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M10 4v7h2V4h2v7h2V4h1V2H10a3 3 0 1 0 0 6zm-3.5 9.5L3 17l3.5 3.5V18h3v-2h-3v-2.5zm14 0L17 17l3.5 3.5V18h-3v-2h3v-2.5zM11 16h2v6h-2z\"/></svg>';\n\nexport class BidiIsolationPlugin implements Plugin {\n\treadonly id = 'bidi-isolation';\n\treadonly name = 'Bidi Isolation';\n\treadonly priority = 92;\n\n\tprivate readonly config: BidiIsolationConfig;\n\tprivate locale!: BidiIsolationLocale;\n\n\tconstructor(config?: Partial<BidiIsolationConfig>) {\n\t\tthis.config = { ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tBIDI_ISOLATION_LOCALE_EN,\n\t\t\tloadBidiIsolationLocale,\n\t\t);\n\n\t\tthis.registerBdiMark(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymaps(context);\n\t\tthis.registerInlineToolbarItem(context);\n\t}\n\n\tprivate registerBdiMark(context: PluginContext): void {\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: 'bdi',\n\t\t\trank: 10,\n\t\t\tattrs: {\n\t\t\t\tdir: { default: 'auto' },\n\t\t\t},\n\t\t\ttoDOM(mark) {\n\t\t\t\tconst el: HTMLElement = document.createElement('bdi');\n\t\t\t\tconst dir: string = String(mark.attrs?.dir ?? 'auto');\n\t\t\t\tel.setAttribute('dir', dir);\n\t\t\t\treturn el;\n\t\t\t},\n\t\t\ttoHTMLString: (mark, content) => {\n\t\t\t\tconst dir: string = escapeHTML(String(mark.attrs?.dir ?? 'auto'));\n\t\t\t\treturn `<bdi dir=\"${dir}\">${content}</bdi>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'bdi',\n\t\t\t\t\tgetAttrs: (el) => {\n\t\t\t\t\t\tconst dir: string | null = el.getAttribute('dir');\n\t\t\t\t\t\tif (dir === 'ltr' || dir === 'rtl') return { dir };\n\t\t\t\t\t\treturn { dir: 'auto' };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: { tags: ['bdi'], attrs: ['dir'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('toggleBidiLTR', () => {\n\t\t\tconst result: boolean = this.applyBdi(context, 'ltr');\n\t\t\tif (result) context.announce(this.locale.inlineLTR);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('toggleBidiRTL', () => {\n\t\t\tconst result: boolean = this.applyBdi(context, 'rtl');\n\t\t\tif (result) context.announce(this.locale.inlineRTL);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('toggleBidiAuto', () => {\n\t\t\tconst result: boolean = this.applyBdi(context, 'auto');\n\t\t\tif (result) context.announce(this.locale.inlineAuto);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('removeBidi', () => {\n\t\t\tconst result: boolean = this.removeBdi(context);\n\t\t\tif (result) context.announce(this.locale.announceRemoveBidi);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('toggleBidiIsolation', () => {\n\t\t\treturn this.toggleBidiIsolation(context);\n\t\t});\n\t}\n\n\tprivate registerKeymaps(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-Shift-B': () => context.executeCommand('toggleBidiIsolation'),\n\t\t});\n\t}\n\n\tprivate registerInlineToolbarItem(context: PluginContext): void {\n\t\tconst inlineItems = [\n\t\t\t{ label: this.locale.inlineLTR, command: 'toggleBidiLTR', icon: DIRECTION_ICONS.ltr },\n\t\t\t{ label: this.locale.inlineRTL, command: 'toggleBidiRTL', icon: DIRECTION_ICONS.rtl },\n\t\t\t{ label: this.locale.inlineAuto, command: 'toggleBidiAuto', icon: DIRECTION_ICONS.auto },\n\t\t\t{ label: this.locale.announceRemoveBidi, command: 'removeBidi' },\n\t\t];\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'inline-direction',\n\t\t\tgroup: 'format',\n\t\t\ticon: INLINE_BDI_ICON,\n\t\t\tlabel: this.locale.inlineLabel,\n\t\t\ttooltip: `${this.locale.inlineTooltip} (${formatShortcut('Mod-Shift-B')})`,\n\t\t\tcommand: 'toggleBidiIsolation',\n\t\t\tpopupType: 'dropdown',\n\t\t\tpopupConfig: { items: inlineItems },\n\t\t\tisActive: (state) => isAttributedMarkActive(state, 'bdi'),\n\t\t\tisEnabled: (state) => {\n\t\t\t\tconst sel = state.selection;\n\t\t\t\treturn isTextSelection(sel) && !isCollapsed(sel);\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Cycles inline bidi isolation: no-bdi → bdi (opposite of block dir) →\n\t * remove. When the {@link TextDirectionService} is registered, picks the\n\t * direction opposite to the current block; otherwise defaults to `'rtl'`.\n\t */\n\tprivate toggleBidiIsolation(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tif (isAttributedMarkActive(state, 'bdi')) {\n\t\t\tconst result: boolean = this.removeBdi(context);\n\t\t\tif (result) context.announce(this.locale.announceRemoveBidi);\n\t\t\treturn result;\n\t\t}\n\n\t\tconst block = getSelectedBlock(state);\n\t\tconst directionService: TextDirectionService | undefined = context.getService(\n\t\t\tTEXT_DIRECTION_SERVICE_KEY,\n\t\t);\n\t\tconst blockDir: TextDirection =\n\t\t\tblock && directionService ? directionService.getBlockDir(block) : 'auto';\n\t\tconst bdiDir: TextDirection = blockDir === 'rtl' ? 'ltr' : 'rtl';\n\n\t\tconst result: boolean = this.applyBdi(context, bdiDir);\n\t\tif (result) {\n\t\t\tconst announcement: string = bdiDir === 'ltr' ? this.locale.inlineLTR : this.locale.inlineRTL;\n\t\t\tcontext.announce(announcement);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate applyBdi(context: PluginContext, dir: TextDirection): boolean {\n\t\tconst state = context.getState();\n\t\tconst mark = { type: markType('bdi'), attrs: { dir } };\n\t\treturn dispatchIfPresent(context, applyAttributedMark(state, mark));\n\t}\n\n\tprivate removeBdi(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\treturn dispatchIfPresent(context, removeAttributedMark(state, markType('bdi')));\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"BidiIsolationPlugin-BddRbDCN.mjs","names":[],"sources":["../../src/plugins/bidi-isolation/BidiIsolationLocale.ts","../../src/plugins/bidi-isolation/BidiIsolationPlugin.ts"],"sourcesContent":["/** Locale interface and default English locale for the BidiIsolationPlugin. */\n\nimport { type LocaleModuleMap, loadLocaleModule } from '../shared/LocaleLoader.js';\n\nexport interface BidiIsolationLocale {\n\treadonly inlineLTR: string;\n\treadonly inlineRTL: string;\n\treadonly inlineAuto: string;\n\treadonly inlineLabel: string;\n\treadonly inlineTooltip: string;\n\treadonly announceRemoveBidi: string;\n}\n\nexport const BIDI_ISOLATION_LOCALE_EN: BidiIsolationLocale = {\n\tinlineLTR: 'Inline LTR',\n\tinlineRTL: 'Inline RTL',\n\tinlineAuto: 'Inline Auto',\n\tinlineLabel: 'Inline Direction',\n\tinlineTooltip: 'Inline Direction',\n\tannounceRemoveBidi: 'Inline direction isolation removed',\n};\n\nconst localeModules: LocaleModuleMap<BidiIsolationLocale> = import.meta.glob<{\n\tdefault: BidiIsolationLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadBidiIsolationLocale(lang: string): Promise<BidiIsolationLocale> {\n\treturn loadLocaleModule(localeModules, lang, BIDI_ISOLATION_LOCALE_EN);\n}\n","/**\n * Inline bidi isolation plugin: registers a `<bdi>` mark and the inline\n * commands / toolbar / keymap that wrap selected text in a `<bdi>` element\n * with an explicit `dir` attribute.\n *\n * Use alongside {@link TextDirectionPlugin} for the full RTL story:\n * block-level direction lives there, the optional `TextDirectionService`\n * lets this plugin pick the inline direction opposite to the block direction\n * in `toggleBidiIsolation`. Without `TextDirectionPlugin`, this plugin\n * still works — `toggleBidiIsolation` falls back to applying `'rtl'`.\n */\n\nimport {\n\tapplyAttributedMark,\n\tisAttributedMarkActive,\n\tremoveAttributedMark,\n} from '../../commands/AttributedMarkCommands.js';\nimport { escapeHTML } from '../../model/HTMLUtils.js';\nimport { isCollapsed, isTextSelection } from '../../model/Selection.js';\nimport { markType } from '../../model/TypeBrands.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { dispatchIfPresent, getSelectedBlock, resolveLocale } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { DIRECTION_ICONS } from '../text-direction/DirectionIcons.js';\nimport {\n\tTEXT_DIRECTION_SERVICE_KEY,\n\ttype TextDirection,\n\ttype TextDirectionService,\n} from '../text-direction/TextDirectionService.js';\nimport {\n\tBIDI_ISOLATION_LOCALE_EN,\n\ttype BidiIsolationLocale,\n\tloadBidiIsolationLocale,\n} from './BidiIsolationLocale.js';\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface MarkAttrRegistry {\n\t\tbdi: { dir: 'ltr' | 'rtl' | 'auto' };\n\t}\n}\n\nexport interface BidiIsolationConfig {\n\treadonly locale?: BidiIsolationLocale;\n}\n\nconst INLINE_BDI_ICON: string =\n\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M10 4v7h2V4h2v7h2V4h1V2H10a3 3 0 1 0 0 6zm-3.5 9.5L3 17l3.5 3.5V18h3v-2h-3v-2.5zm14 0L17 17l3.5 3.5V18h-3v-2h3v-2.5zM11 16h2v6h-2z\"/></svg>';\n\nexport class BidiIsolationPlugin implements Plugin {\n\treadonly id = 'bidi-isolation';\n\treadonly name = 'Bidi Isolation';\n\treadonly priority = 92;\n\n\tprivate readonly config: BidiIsolationConfig;\n\tprivate locale!: BidiIsolationLocale;\n\n\tconstructor(config?: Partial<BidiIsolationConfig>) {\n\t\tthis.config = { ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tBIDI_ISOLATION_LOCALE_EN,\n\t\t\tloadBidiIsolationLocale,\n\t\t);\n\n\t\tthis.registerBdiMark(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymaps(context);\n\t\tthis.registerInlineToolbarItem(context);\n\t}\n\n\tprivate registerBdiMark(context: PluginContext): void {\n\t\tcontext.registerMarkSpec({\n\t\t\ttype: 'bdi',\n\t\t\trank: 10,\n\t\t\tattrs: {\n\t\t\t\tdir: { default: 'auto' },\n\t\t\t},\n\t\t\ttoDOM(mark) {\n\t\t\t\tconst el: HTMLElement = document.createElement('bdi');\n\t\t\t\tconst dir: string = String(mark.attrs?.dir ?? 'auto');\n\t\t\t\tel.setAttribute('dir', dir);\n\t\t\t\treturn el;\n\t\t\t},\n\t\t\ttoHTMLString: (mark, content) => {\n\t\t\t\tconst dir: string = escapeHTML(String(mark.attrs?.dir ?? 'auto'));\n\t\t\t\treturn `<bdi dir=\"${dir}\">${content}</bdi>`;\n\t\t\t},\n\t\t\tparseHTML: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'bdi',\n\t\t\t\t\tgetAttrs: (el) => {\n\t\t\t\t\t\tconst dir: string | null = el.getAttribute('dir');\n\t\t\t\t\t\tif (dir === 'ltr' || dir === 'rtl') return { dir };\n\t\t\t\t\t\treturn { dir: 'auto' };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsanitize: { tags: ['bdi'], attrs: ['dir'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('toggleBidiLTR', () => {\n\t\t\tconst result: boolean = this.applyBdi(context, 'ltr');\n\t\t\tif (result) context.announce(this.locale.inlineLTR);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('toggleBidiRTL', () => {\n\t\t\tconst result: boolean = this.applyBdi(context, 'rtl');\n\t\t\tif (result) context.announce(this.locale.inlineRTL);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('toggleBidiAuto', () => {\n\t\t\tconst result: boolean = this.applyBdi(context, 'auto');\n\t\t\tif (result) context.announce(this.locale.inlineAuto);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('removeBidi', () => {\n\t\t\tconst result: boolean = this.removeBdi(context);\n\t\t\tif (result) context.announce(this.locale.announceRemoveBidi);\n\t\t\treturn result;\n\t\t});\n\n\t\tcontext.registerCommand('toggleBidiIsolation', () => {\n\t\t\treturn this.toggleBidiIsolation(context);\n\t\t});\n\t}\n\n\tprivate registerKeymaps(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-Shift-B': () => context.executeCommand('toggleBidiIsolation'),\n\t\t});\n\t}\n\n\tprivate registerInlineToolbarItem(context: PluginContext): void {\n\t\tconst inlineItems = [\n\t\t\t{ label: this.locale.inlineLTR, command: 'toggleBidiLTR', icon: DIRECTION_ICONS.ltr },\n\t\t\t{ label: this.locale.inlineRTL, command: 'toggleBidiRTL', icon: DIRECTION_ICONS.rtl },\n\t\t\t{ label: this.locale.inlineAuto, command: 'toggleBidiAuto', icon: DIRECTION_ICONS.auto },\n\t\t\t{ label: this.locale.announceRemoveBidi, command: 'removeBidi' },\n\t\t];\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'inline-direction',\n\t\t\tgroup: 'format',\n\t\t\ticon: INLINE_BDI_ICON,\n\t\t\tlabel: this.locale.inlineLabel,\n\t\t\ttooltip: `${this.locale.inlineTooltip} (${formatShortcut('Mod-Shift-B')})`,\n\t\t\tcommand: 'toggleBidiIsolation',\n\t\t\tpopupType: 'dropdown',\n\t\t\tpopupConfig: { items: inlineItems },\n\t\t\tisActive: (state) => isAttributedMarkActive(state, 'bdi'),\n\t\t\tisEnabled: (state) => {\n\t\t\t\tconst sel = state.selection;\n\t\t\t\treturn isTextSelection(sel) && !isCollapsed(sel);\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Cycles inline bidi isolation: no-bdi → bdi (opposite of block dir) →\n\t * remove. When the {@link TextDirectionService} is registered, picks the\n\t * direction opposite to the current block; otherwise defaults to `'rtl'`.\n\t */\n\tprivate toggleBidiIsolation(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tif (isAttributedMarkActive(state, 'bdi')) {\n\t\t\tconst result: boolean = this.removeBdi(context);\n\t\t\tif (result) context.announce(this.locale.announceRemoveBidi);\n\t\t\treturn result;\n\t\t}\n\n\t\tconst block = getSelectedBlock(state);\n\t\tconst directionService: TextDirectionService | undefined = context.getService(\n\t\t\tTEXT_DIRECTION_SERVICE_KEY,\n\t\t);\n\t\tconst blockDir: TextDirection =\n\t\t\tblock && directionService ? directionService.getBlockDir(block) : 'auto';\n\t\tconst bdiDir: TextDirection = blockDir === 'rtl' ? 'ltr' : 'rtl';\n\n\t\tconst result: boolean = this.applyBdi(context, bdiDir);\n\t\tif (result) {\n\t\t\tconst announcement: string = bdiDir === 'ltr' ? this.locale.inlineLTR : this.locale.inlineRTL;\n\t\t\tcontext.announce(announcement);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate applyBdi(context: PluginContext, dir: TextDirection): boolean {\n\t\tconst state = context.getState();\n\t\tconst mark = { type: markType('bdi'), attrs: { dir } };\n\t\treturn dispatchIfPresent(context, applyAttributedMark(state, mark));\n\t}\n\n\tprivate removeBdi(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\treturn dispatchIfPresent(context, removeAttributedMark(state, markType('bdi')));\n\t}\n}\n"],"mappings":"wbAaA,IAAa,EAAgD,CAC5D,UAAW,aACX,UAAW,aACX,WAAY,cACZ,YAAa,mBACb,cAAe,mBACf,mBAAoB,sCAGf,iBAAsD,OAAA,OAAA,CAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,qBAAA,kBAAA,IAAA,OAAA,uBAI5D,eAAsB,EAAwB,GAC7C,OAAO,EAAiB,EAAe,EAAM,EAC9C,CCiBA,IAGa,EAAb,MACC,GAAc,iBACd,KAAgB,iBAChB,SAAoB,GAEpB,OACA,OAEA,WAAA,CAAY,GACX,KAAK,OAAS,IAAK,EACpB,CAEA,UAAM,CAAK,GACV,KAAK,aAAe,EACnB,EACA,KAAK,OAAO,OACZ,EACA,GAGD,KAAK,gBAAgB,GACrB,KAAK,iBAAiB,GACtB,KAAK,gBAAgB,GACrB,KAAK,0BAA0B,EAChC,CAEA,eAAA,CAAwB,GACvB,EAAQ,iBAAiB,CACxB,KAAM,MACN,KAAM,GACN,MAAO,CACN,IAAK,CAAE,QAAS,SAEjB,KAAA,CAAM,GACL,MAAM,EAAkB,SAAS,cAAc,OACzC,EAAc,OAAO,EAAK,OAAO,KAAO,QAE9C,OADA,EAAG,aAAa,MAAO,GAChB,CACR,EACA,aAAA,CAAe,EAAM,IAEb,aADa,EAAW,OAAO,EAAK,OAAO,KAAO,aAC7B,UAE7B,UAAW,CACV,CACC,IAAK,MACL,SAAW,IACV,MAAM,EAAqB,EAAG,aAAa,OAC3C,MAAY,QAAR,GAAyB,QAAR,EAAsB,CAAE,OACtC,CAAE,IAAK,WAIjB,SAAU,CAAE,KAAM,CAAC,OAAQ,MAAO,CAAC,SAErC,CAEA,gBAAA,CAAyB,GACxB,EAAQ,gBAAgB,gBAAA,KACvB,MAAM,EAAkB,KAAK,SAAS,EAAS,OAE/C,OADI,GAAQ,EAAQ,SAAS,KAAK,OAAO,WAClC,IAGR,EAAQ,gBAAgB,gBAAA,KACvB,MAAM,EAAkB,KAAK,SAAS,EAAS,OAE/C,OADI,GAAQ,EAAQ,SAAS,KAAK,OAAO,WAClC,IAGR,EAAQ,gBAAgB,iBAAA,KACvB,MAAM,EAAkB,KAAK,SAAS,EAAS,QAE/C,OADI,GAAQ,EAAQ,SAAS,KAAK,OAAO,YAClC,IAGR,EAAQ,gBAAgB,aAAA,KACvB,MAAM,EAAkB,KAAK,UAAU,GAEvC,OADI,GAAQ,EAAQ,SAAS,KAAK,OAAO,oBAClC,IAGR,EAAQ,gBAAgB,sBAAA,IAChB,KAAK,oBAAoB,GAElC,CAEA,eAAA,CAAwB,GACvB,EAAQ,eAAe,CACtB,cAAA,IAAqB,EAAQ,eAAe,wBAE9C,CAEA,yBAAA,CAAkC,GACjC,MAAM,EAAc,CACnB,CAAE,MAAO,KAAK,OAAO,UAAW,QAAS,gBAAiB,KAAM,EAAgB,KAChF,CAAE,MAAO,KAAK,OAAO,UAAW,QAAS,gBAAiB,KAAM,EAAgB,KAChF,CAAE,MAAO,KAAK,OAAO,WAAY,QAAS,iBAAkB,KAAM,EAAgB,MAClF,CAAE,MAAO,KAAK,OAAO,mBAAoB,QAAS,eAGnD,EAAQ,oBAAoB,CAC3B,GAAI,mBACJ,MAAO,SACP,KA1GF,mNA2GE,MAAO,KAAK,OAAO,YACnB,QAAS,GAAG,KAAK,OAAO,kBAAkB,EAAe,kBACzD,QAAS,sBACT,UAAW,WACX,YAAa,CAAE,MAAO,GACtB,SAAW,GAAU,EAAuB,EAAO,OACnD,UAAY,IACX,MAAM,EAAM,EAAM,UAClB,OAAO,EAAgB,KAAS,EAAY,KAG/C,CAOA,mBAAA,CAA4B,GAC3B,MAAM,EAAQ,EAAQ,WACtB,GAAI,EAAuB,EAAO,OAAQ,CACzC,MAAM,EAAkB,KAAK,UAAU,GAEvC,OADI,GAAQ,EAAQ,SAAS,KAAK,OAAO,oBAClC,CACR,CAEA,MAAM,EAAQ,EAAiB,GACzB,EAAqD,EAAQ,WAClE,GAIK,EAAqC,SAD1C,GAAS,EAAmB,EAAiB,YAAY,GAAS,QAChB,MAAQ,MAErD,EAAkB,KAAK,SAAS,EAAS,GAC/C,GAAI,EAAQ,CACX,MAAM,EAAkC,QAAX,EAAmB,KAAK,OAAO,UAAY,KAAK,OAAO,UACpF,EAAQ,SAAS,EAClB,CACA,OAAO,CACR,CAEA,QAAA,CAAiB,EAAwB,GAGxC,OAAO,EAAkB,EAAS,EAFpB,EAAQ,WAEuC,CAD9C,KAAM,EAAS,OAAQ,MAAO,CAAE,SAEhD,CAEA,SAAA,CAAkB,GAEjB,OAAO,EAAkB,EAAS,EADpB,EAAQ,WACwC,EAAS,QACxE"}
@@ -1,2 +1,2 @@
1
- import{d as t,i as e,o,p as n,u as r}from"./Document-r7vLOAGA.mjs";import{d as i,o as c,t as s,u as l}from"./Selection-HYoVFpAx.mjs";import{a}from"./TypeBrands-Ch9856Gb.mjs";import{n as u}from"./DomUtils-Bf7JLFlx.mjs";import{a as d,c as h,t as m}from"./NodeResolver-ChgLF_IP.mjs";import{a as p,s as g}from"./PluginHelpers-D4quRJ5a.mjs";import{t as f}from"./ShortcutFormatting-TwiufqeV.mjs";function b(t,e){const o=t.getNodePath(e)?.[0];return o?t.doc.children.findIndex(t=>t.id===o):-1}function q(t,o,n,c){const s=i(n,t.getBlockOrder()),l=b(t,s.from.blockId),a=b(t,s.to.blockId);if(l<0||a<0)return null;const u=Math.min(l,a),d=Math.max(l,a),h=t.doc.children.slice(u,d+1),m=c??(()=>!0),p=[];let g=[],f=!1;const q=()=>{0!==g.length&&(p.push(e(o,g,r())),f=!0,g=[])};for(const e of h)m(e)?g.push(e):(q(),p.push(e));if(q(),!f)return null;const k=t.transaction("command");for(let e=d;e>=u;e--)k.removeNode([],e);return p.forEach((t,e)=>{k.insertNode([],u+e,t)}),k.setSelection(n),k.build()}function k(e,o){const n=e.getState();if(!l(n.selection))return!1;const r=n.selection;if(!c(r))return!1;const i=r.anchor.blockId,s=n.getParent(i);if(!s||"blockquote"!==s.type)return!1;const a=n.getBlock(i);if(!a)return!1;const u=n.getNodePath(s.id);if(!u)return!1;const d=h(n.doc,u);if(!d)return!1;const m=t(s),p=m.findIndex(t=>t.id===i);return!(p<0)&&o({state:n,quotePath:u,quoteParentPath:u.slice(0,-1),quoteIndex:d.index,child:a,childIndex:p,childCount:m.length,offset:r.anchor.offset})}var I={label:"Blockquote",tooltip:t=>`Blockquote (${t})`},x=/* #__PURE__ */Object.assign({"./locales/ar.ts":()=>import("./ar-sGZ-oZqB.mjs"),"./locales/de.ts":()=>import("./de-uKR7koQe.mjs"),"./locales/es.ts":()=>import("./es-DrJyl38L.mjs"),"./locales/fr.ts":()=>import("./fr-BRXUnq3R.mjs"),"./locales/hi.ts":()=>import("./hi-SECtQQzq.mjs"),"./locales/pt.ts":()=>import("./pt-Cv6q7x5x.mjs"),"./locales/ru.ts":()=>import("./ru-DSRv3_Rg.mjs"),"./locales/zh.ts":()=>import("./zh-DYD476c5.mjs")});async function v(t){return g(x,t,I)}var N={},P=class{id="blockquote";name="Blockquote";priority=35;config;locale;constructor(t){this.config={...N,...t}}async init(t){this.locale=await p(t,this.config.locale,I,v),t.registerStyleSheet("\n.notectl-content blockquote {\n\tmargin: 0;\n\tpadding: 2px 0;\n\tpadding-inline-start: 16px;\n\tborder-inline-start: 3px solid var(--notectl-blockquote-border, var(--notectl-border));\n\tbackground: var(--notectl-blockquote-bg, transparent);\n\tcolor: var(--notectl-blockquote-fg, inherit);\n\tmin-height: 1.6em;\n}\n"),this.registerNodeSpec(t),this.registerCommands(t),this.registerKeymap(t),this.registerInputRule(t),this.registerToolbarItem(t)}registerNodeSpec(t){t.registerNodeSpec({type:"blockquote",group:"block",content:{allow:["paragraph","heading","list_item","blockquote","horizontal_rule","code_block"],min:1},toDOM(t){const e=u("blockquote",t.id);return e.setAttribute("part","blockquote"),e},toHTML:(t,e)=>`<blockquote>${e||"<br>"}</blockquote>`,parseHTML:[{tag:"blockquote"}],sanitize:{tags:["blockquote"]}})}registerCommands(t){t.registerCommand("toggleBlockquote",()=>this.toggleBlockquote(t)),t.registerCommand("setBlockquote",()=>this.wrapInBlockquote(t))}registerKeymap(t){t.registerKeymap({"Mod-Shift->":()=>t.executeCommand("toggleBlockquote")}),function(t){t.registerKeymap({Enter:()=>function(t){return k(t,e=>{if("list_item"===e.child.type)return!1;if(e.childIndex!==e.childCount-1||n(e.child)>0)return!1;const r=o(),i=e.state.transaction("input");return 1===e.childCount?(i.removeNode(e.quoteParentPath,e.quoteIndex),i.insertNode(e.quoteParentPath,e.quoteIndex,r)):(i.removeNode(e.quotePath,e.childIndex),i.insertNode(e.quoteParentPath,e.quoteIndex+1,r)),i.setSelection(s(r.id,0)),t.dispatch(i.build()),!0})}(t),Backspace:()=>function(t){return k(t,e=>{if(0!==e.offset||0!==e.childIndex)return!1;if("list_item"===e.child.type)return!1;const o=e.state.transaction("input");return 1===e.childCount?(o.removeNode(e.quoteParentPath,e.quoteIndex),o.insertNode(e.quoteParentPath,e.quoteIndex,e.child)):(o.removeNode(e.quotePath,0),o.insertNode(e.quoteParentPath,e.quoteIndex,e.child)),o.setSelection(s(e.child.id,0)),t.dispatch(o.build()),!0})}(t)},{priority:"context"})}(t)}registerInputRule(t){t.registerInputRule({pattern:/^> $/,handler(t,o,n,i){const s=t.selection;if(!l(s))return null;if(!c(s))return null;const u=t.getBlock(s.anchor.blockId);if(!u||"paragraph"!==u.type)return null;const d=t.doc.children.findIndex(t=>t.id===u.id);if(d<0)return null;const h=e(a("blockquote"),[u],r());return t.transaction("input").removeNode([],d).insertNode([],d,h).deleteTextAt(s.anchor.blockId,n,n+2).setSelection(s).build()}})}registerToolbarItem(t){t.registerToolbarItem({id:"blockquote",group:"block",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z"/></svg>',label:this.locale.label,tooltip:this.locale.tooltip(f("Mod-Shift->")),command:"toggleBlockquote",isActive:t=>!!l(t.selection)&&d(t.doc,t.selection.anchor.blockId,"blockquote")})}toggleBlockquote(e){const o=e.getState(),n=o.selection;if(!l(n))return!1;const r=d(o.doc,n.anchor.blockId,"blockquote")?function(e,o,n){const r=m(e.doc,n.anchor.blockId,o);if(!r||1!==r.path.length)return null;const i=e.doc.children.findIndex(t=>t.id===r.node.id);if(i<0)return null;const c=t(r.node),s=e.transaction("command");return s.removeNode([],i),c.forEach((t,e)=>{s.insertNode([],i+e,t)}),s.setSelection(n),s.build()}(o,a("blockquote"),n):q(o,a("blockquote"),n,this.isQuoteChild(e));return!!r&&(e.dispatch(r),!0)}wrapInBlockquote(t){const e=t.getState(),o=e.selection;if(!l(o))return!1;const n=q(e,a("blockquote"),o,this.isQuoteChild(t));return!!n&&(t.dispatch(n),!0)}isQuoteChild(t){const e=t.getSchemaRegistry(),o=new Set(e.getNodeSpec(a("blockquote"))?.content?.allow??[]);return t=>{if(o.has(t.type))return!0;const n=e.getNodeSpec(t.type)?.group;return void 0!==n&&o.has(n)}}};export{I as n,v as r,P as t};
2
- //# sourceMappingURL=BlockquotePlugin-CxrCA0vY.mjs.map
1
+ import{d as t,i as e,o,p as n,u as r}from"./Document-r7vLOAGA.mjs";import{d as i,o as c,t as s,u as l}from"./Selection-HYoVFpAx.mjs";import{a}from"./TypeBrands-Ch9856Gb.mjs";import{n as u}from"./DomUtils-Bf7JLFlx.mjs";import{a as d,c as h,t as m}from"./NodeResolver-ChgLF_IP.mjs";import{c as p,o as g}from"./PluginHelpers-KDuTlmXm.mjs";import{t as f}from"./ShortcutFormatting-TwiufqeV.mjs";function b(t,e){const o=t.getNodePath(e)?.[0];return o?t.doc.children.findIndex(t=>t.id===o):-1}function q(t,o,n,c){const s=i(n,t.getBlockOrder()),l=b(t,s.from.blockId),a=b(t,s.to.blockId);if(l<0||a<0)return null;const u=Math.min(l,a),d=Math.max(l,a),h=t.doc.children.slice(u,d+1),m=c??(()=>!0),p=[];let g=[],f=!1;const q=()=>{0!==g.length&&(p.push(e(o,g,r())),f=!0,g=[])};for(const e of h)m(e)?g.push(e):(q(),p.push(e));if(q(),!f)return null;const k=t.transaction("command");for(let e=d;e>=u;e--)k.removeNode([],e);return p.forEach((t,e)=>{k.insertNode([],u+e,t)}),k.setSelection(n),k.build()}function k(e,o){const n=e.getState();if(!l(n.selection))return!1;const r=n.selection;if(!c(r))return!1;const i=r.anchor.blockId,s=n.getParent(i);if(!s||"blockquote"!==s.type)return!1;const a=n.getBlock(i);if(!a)return!1;const u=n.getNodePath(s.id);if(!u)return!1;const d=h(n.doc,u);if(!d)return!1;const m=t(s),p=m.findIndex(t=>t.id===i);return!(p<0)&&o({state:n,quotePath:u,quoteParentPath:u.slice(0,-1),quoteIndex:d.index,child:a,childIndex:p,childCount:m.length,offset:r.anchor.offset})}var I={label:"Blockquote",tooltip:t=>`Blockquote (${t})`},x=/* #__PURE__ */Object.assign({"./locales/ar.ts":()=>import("./ar-sGZ-oZqB.mjs"),"./locales/de.ts":()=>import("./de-uKR7koQe.mjs"),"./locales/es.ts":()=>import("./es-DrJyl38L.mjs"),"./locales/fr.ts":()=>import("./fr-BRXUnq3R.mjs"),"./locales/hi.ts":()=>import("./hi-SECtQQzq.mjs"),"./locales/pt.ts":()=>import("./pt-Cv6q7x5x.mjs"),"./locales/ru.ts":()=>import("./ru-DSRv3_Rg.mjs"),"./locales/zh.ts":()=>import("./zh-DYD476c5.mjs")});async function v(t){return p(x,t,I)}var N={},P=class{id="blockquote";name="Blockquote";priority=35;config;locale;constructor(t){this.config={...N,...t}}async init(t){this.locale=await g(t,this.config.locale,I,v),t.registerStyleSheet("\n.notectl-content blockquote {\n\tmargin: 0;\n\tpadding: 2px 0;\n\tpadding-inline-start: 16px;\n\tborder-inline-start: 3px solid var(--notectl-blockquote-border, var(--notectl-border));\n\tbackground: var(--notectl-blockquote-bg, transparent);\n\tcolor: var(--notectl-blockquote-fg, inherit);\n\tmin-height: 1.6em;\n}\n"),this.registerNodeSpec(t),this.registerCommands(t),this.registerKeymap(t),this.registerInputRule(t),this.registerToolbarItem(t)}registerNodeSpec(t){t.registerNodeSpec({type:"blockquote",group:"block",content:{allow:["paragraph","heading","list_item","blockquote","horizontal_rule","code_block"],min:1},toDOM(t){const e=u("blockquote",t.id);return e.setAttribute("part","blockquote"),e},toHTML:(t,e)=>`<blockquote>${e||"<br>"}</blockquote>`,parseHTML:[{tag:"blockquote"}],sanitize:{tags:["blockquote"]}})}registerCommands(t){t.registerCommand("toggleBlockquote",()=>this.toggleBlockquote(t)),t.registerCommand("setBlockquote",()=>this.wrapInBlockquote(t))}registerKeymap(t){t.registerKeymap({"Mod-Shift->":()=>t.executeCommand("toggleBlockquote")}),function(t){t.registerKeymap({Enter:()=>function(t){return k(t,e=>{if("list_item"===e.child.type)return!1;if(e.childIndex!==e.childCount-1||n(e.child)>0)return!1;const r=o(),i=e.state.transaction("input");return 1===e.childCount?(i.removeNode(e.quoteParentPath,e.quoteIndex),i.insertNode(e.quoteParentPath,e.quoteIndex,r)):(i.removeNode(e.quotePath,e.childIndex),i.insertNode(e.quoteParentPath,e.quoteIndex+1,r)),i.setSelection(s(r.id,0)),t.dispatch(i.build()),!0})}(t),Backspace:()=>function(t){return k(t,e=>{if(0!==e.offset||0!==e.childIndex)return!1;if("list_item"===e.child.type)return!1;const o=e.state.transaction("input");return 1===e.childCount?(o.removeNode(e.quoteParentPath,e.quoteIndex),o.insertNode(e.quoteParentPath,e.quoteIndex,e.child)):(o.removeNode(e.quotePath,0),o.insertNode(e.quoteParentPath,e.quoteIndex,e.child)),o.setSelection(s(e.child.id,0)),t.dispatch(o.build()),!0})}(t)},{priority:"context"})}(t)}registerInputRule(t){t.registerInputRule({pattern:/^> $/,handler(t,o,n,i){const s=t.selection;if(!l(s))return null;if(!c(s))return null;const u=t.getBlock(s.anchor.blockId);if(!u||"paragraph"!==u.type)return null;const d=t.doc.children.findIndex(t=>t.id===u.id);if(d<0)return null;const h=e(a("blockquote"),[u],r());return t.transaction("input").removeNode([],d).insertNode([],d,h).deleteTextAt(s.anchor.blockId,n,n+2).setSelection(s).build()}})}registerToolbarItem(t){t.registerToolbarItem({id:"blockquote",group:"block",icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z"/></svg>',label:this.locale.label,tooltip:this.locale.tooltip(f("Mod-Shift->")),command:"toggleBlockquote",isActive:t=>!!l(t.selection)&&d(t.doc,t.selection.anchor.blockId,"blockquote")})}toggleBlockquote(e){const o=e.getState(),n=o.selection;if(!l(n))return!1;const r=d(o.doc,n.anchor.blockId,"blockquote")?function(e,o,n){const r=m(e.doc,n.anchor.blockId,o);if(!r||1!==r.path.length)return null;const i=e.doc.children.findIndex(t=>t.id===r.node.id);if(i<0)return null;const c=t(r.node),s=e.transaction("command");return s.removeNode([],i),c.forEach((t,e)=>{s.insertNode([],i+e,t)}),s.setSelection(n),s.build()}(o,a("blockquote"),n):q(o,a("blockquote"),n,this.isQuoteChild(e));return!!r&&(e.dispatch(r),!0)}wrapInBlockquote(t){const e=t.getState(),o=e.selection;if(!l(o))return!1;const n=q(e,a("blockquote"),o,this.isQuoteChild(t));return!!n&&(t.dispatch(n),!0)}isQuoteChild(t){const e=t.getSchemaRegistry(),o=new Set(e.getNodeSpec(a("blockquote"))?.content?.allow??[]);return t=>{if(o.has(t.type))return!0;const n=e.getNodeSpec(t.type)?.group;return void 0!==n&&o.has(n)}}};export{I as n,v as r,P as t};
2
+ //# sourceMappingURL=BlockquotePlugin-4V7KV_Sb.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"BlockquotePlugin-CxrCA0vY.mjs","names":[],"sources":["../../src/commands/ContainerCommands.ts","../../src/plugins/blockquote/BlockquoteKeyboardHandlers.ts","../../src/plugins/blockquote/BlockquoteLocale.ts","../../src/plugins/blockquote/BlockquoteStyles.ts","../../src/plugins/blockquote/BlockquotePlugin.ts"],"sourcesContent":["/**\n * Generic wrap/lift commands for container blocks (issue #136).\n *\n * A container block (e.g. `blockquote`) holds other blocks as children, mirroring\n * HTML flow-content semantics. Wrapping moves the selected top-level blocks into a\n * new container; lifting dissolves a container and returns its children to the\n * parent. Block identity (IDs) is preserved across both operations so the active\n * selection survives the structural change.\n *\n * Scope: operations act on top-level containers. Nested containers (quote-in-quote,\n * quote-in-cell) are intentionally out of scope here and return `null`.\n */\n\nimport type { BlockNode } from '../model/Document.js';\nimport { createBlockNode, generateBlockId, getBlockChildren } from '../model/Document.js';\nimport { findAncestorOfType } from '../model/NodeResolver.js';\nimport type { Selection } from '../model/Selection.js';\nimport { selectionRange } from '../model/Selection.js';\nimport type { BlockId, NodeTypeName } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction } from '../state/Transaction.js';\n\n/** Returns the index in `doc.children` of the top-level ancestor of the given block. */\nfunction topLevelIndexOf(state: EditorState, blockId: BlockId): number {\n\tconst topId: BlockId | undefined = state.getNodePath(blockId)?.[0];\n\tif (!topId) return -1;\n\treturn state.doc.children.findIndex((b) => b.id === topId);\n}\n\n/**\n * Wraps the top-level blocks spanned by `selection` into new container blocks of\n * `containerType`. Returns `null` when the range cannot be resolved.\n *\n * `isAllowedChild` guards the container's schema (`content.allow`): blocks the\n * container cannot legally hold (e.g. a `table` inside a `blockquote`) are left at\n * the top level instead of being nested into an invalid document. Disallowed blocks\n * therefore split the range into separate contiguous runs, each wrapped in its own\n * container, mirroring `wrapIn`. Defaults to wrapping everything when omitted.\n * Returns `null` when no block in the range is wrappable.\n */\nexport function wrapSelectionInContainer(\n\tstate: EditorState,\n\tcontainerType: NodeTypeName,\n\tselection: Selection,\n\tisAllowedChild?: (block: BlockNode) => boolean,\n): Transaction | null {\n\tconst range = selectionRange(selection, state.getBlockOrder());\n\tconst fromIdx: number = topLevelIndexOf(state, range.from.blockId);\n\tconst toIdx: number = topLevelIndexOf(state, range.to.blockId);\n\tif (fromIdx < 0 || toIdx < 0) return null;\n\n\tconst lo: number = Math.min(fromIdx, toIdx);\n\tconst hi: number = Math.max(fromIdx, toIdx);\n\n\tconst blocks: readonly BlockNode[] = state.doc.children.slice(lo, hi + 1);\n\tconst allowed: (block: BlockNode) => boolean = isAllowedChild ?? (() => true);\n\n\t// Group the range into maximal runs of wrappable blocks; each run becomes one\n\t// container, disallowed blocks pass through unchanged and break the run.\n\tconst sequence: BlockNode[] = [];\n\tlet run: BlockNode[] = [];\n\tlet wrappedAny = false;\n\tconst flushRun = (): void => {\n\t\tif (run.length === 0) return;\n\t\tsequence.push(createBlockNode(containerType, run, generateBlockId()));\n\t\twrappedAny = true;\n\t\trun = [];\n\t};\n\tfor (const block of blocks) {\n\t\tif (allowed(block)) {\n\t\t\trun.push(block);\n\t\t} else {\n\t\t\tflushRun();\n\t\t\tsequence.push(block);\n\t\t}\n\t}\n\tflushRun();\n\n\tif (!wrappedAny) return null;\n\n\tconst builder = state.transaction('command');\n\tfor (let i: number = hi; i >= lo; i--) {\n\t\tbuilder.removeNode([], i);\n\t}\n\tsequence.forEach((node, i) => {\n\t\tbuilder.insertNode([], lo + i, node);\n\t});\n\tbuilder.setSelection(selection);\n\treturn builder.build();\n}\n\n/**\n * Lifts the children of the nearest top-level `containerType` ancestor of the\n * selection anchor back out to the top level, dissolving the container. Returns\n * `null` when no such top-level container surrounds the selection.\n */\nexport function liftSelectionFromContainer(\n\tstate: EditorState,\n\tcontainerType: NodeTypeName,\n\tselection: Selection,\n): Transaction | null {\n\tconst ancestor = findAncestorOfType(state.doc, selection.anchor.blockId, containerType);\n\t// Only top-level containers are dissolved (path === [containerId]).\n\tif (!ancestor || ancestor.path.length !== 1) return null;\n\n\tconst containerIdx: number = state.doc.children.findIndex((b) => b.id === ancestor.node.id);\n\tif (containerIdx < 0) return null;\n\n\tconst children: readonly BlockNode[] = getBlockChildren(ancestor.node);\n\n\tconst builder = state.transaction('command');\n\tbuilder.removeNode([], containerIdx);\n\tchildren.forEach((child, i) => {\n\t\tbuilder.insertNode([], containerIdx + i, child);\n\t});\n\tbuilder.setSelection(selection);\n\treturn builder.build();\n}\n","/**\n * Keyboard handlers for the blockquote container (issue #136, B2 model).\n *\n * Under the container model the caret lives in a child block of the blockquote,\n * not in the blockquote itself. These handlers manage the two container\n * boundaries; everything in between (splitting, merging, arrow navigation) is\n * left to the default commands, which already operate correctly on the nested\n * child blocks:\n *\n * - Enter in an empty last child → exit the blockquote (paragraph after it).\n * - Backspace at start of the first child → lift that child out of the quote.\n *\n * List items are deferred to the list plugin's own handlers.\n */\n\nimport type { BlockNode } from '../../model/Document.js';\nimport { createEmptyParagraph, getBlockChildren, getBlockLength } from '../../model/Document.js';\nimport { resolveParentByPath } from '../../model/NodeResolver.js';\nimport { createCollapsedSelection, isCollapsed, isTextSelection } from '../../model/Selection.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { PluginContext } from '../Plugin.js';\n\n// --- Context Guard ---\n\ninterface QuoteChildContext {\n\treadonly state: EditorState;\n\treadonly quotePath: readonly BlockId[];\n\treadonly quoteParentPath: readonly BlockId[];\n\treadonly quoteIndex: number;\n\treadonly child: BlockNode;\n\treadonly childIndex: number;\n\treadonly childCount: number;\n\treadonly offset: number;\n}\n\n/**\n * Resolves the caret context when the cursor sits in a direct child of a\n * blockquote. Returns false (not handled) otherwise, so the default keymap and\n * other plugins keep their behavior.\n */\nfunction withBlockquoteChildContext(\n\tcontext: PluginContext,\n\thandler: (ctx: QuoteChildContext) => boolean,\n): boolean {\n\tconst state: EditorState = context.getState();\n\tif (!isTextSelection(state.selection)) return false;\n\tconst sel = state.selection;\n\tif (!isCollapsed(sel)) return false;\n\n\tconst childId: BlockId = sel.anchor.blockId;\n\tconst quote: BlockNode | undefined = state.getParent(childId);\n\tif (!quote || quote.type !== 'blockquote') return false;\n\n\tconst child: BlockNode | undefined = state.getBlock(childId);\n\tif (!child) return false;\n\n\tconst quotePath: BlockId[] | undefined = state.getNodePath(quote.id);\n\tif (!quotePath) return false;\n\tconst parentRef = resolveParentByPath(state.doc, quotePath);\n\tif (!parentRef) return false;\n\n\tconst children: readonly BlockNode[] = getBlockChildren(quote);\n\tconst childIndex: number = children.findIndex((b) => b.id === childId);\n\tif (childIndex < 0) return false;\n\n\treturn handler({\n\t\tstate,\n\t\tquotePath,\n\t\tquoteParentPath: quotePath.slice(0, -1),\n\t\tquoteIndex: parentRef.index,\n\t\tchild,\n\t\tchildIndex,\n\t\tchildCount: children.length,\n\t\toffset: sel.anchor.offset,\n\t});\n}\n\n/** Registers the blockquote container keyboard handlers at context priority. */\nexport function registerBlockquoteKeymaps(context: PluginContext): void {\n\tcontext.registerKeymap(\n\t\t{\n\t\t\tEnter: () => handleEnterExit(context),\n\t\t\tBackspace: () => handleBackspaceLift(context),\n\t\t},\n\t\t{ priority: 'context' },\n\t);\n}\n\n// --- Handlers ---\n\n/**\n * Enter in an empty last child of the blockquote exits the container: a fresh\n * paragraph is created after the quote (or, when that child is the quote's only\n * child, the quote dissolves into that paragraph). Any other case returns false\n * so the default splitBlock creates a new line inside the quote.\n */\nfunction handleEnterExit(context: PluginContext): boolean {\n\treturn withBlockquoteChildContext(context, (ctx) => {\n\t\tif (ctx.child.type === 'list_item') return false;\n\t\tconst isLast: boolean = ctx.childIndex === ctx.childCount - 1;\n\t\tif (!isLast || getBlockLength(ctx.child) > 0) return false;\n\n\t\tconst paragraph: BlockNode = createEmptyParagraph();\n\t\tconst builder = ctx.state.transaction('input');\n\n\t\tif (ctx.childCount === 1) {\n\t\t\t// Sole child: dissolve the quote, replacing it with the paragraph.\n\t\t\tbuilder.removeNode(ctx.quoteParentPath, ctx.quoteIndex);\n\t\t\tbuilder.insertNode(ctx.quoteParentPath, ctx.quoteIndex, paragraph);\n\t\t} else {\n\t\t\t// Drop the empty trailing child and continue after the quote.\n\t\t\tbuilder.removeNode(ctx.quotePath, ctx.childIndex);\n\t\t\tbuilder.insertNode(ctx.quoteParentPath, ctx.quoteIndex + 1, paragraph);\n\t\t}\n\n\t\tbuilder.setSelection(createCollapsedSelection(paragraph.id, 0));\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t});\n}\n\n/**\n * Backspace at the start of the blockquote's first child lifts that child out of\n * the quote (placing it directly before the quote, or dissolving the quote when\n * it was the only child). Inner children at offset 0 fall through to the default\n * merge, which joins adjacent siblings within the quote.\n */\nfunction handleBackspaceLift(context: PluginContext): boolean {\n\treturn withBlockquoteChildContext(context, (ctx) => {\n\t\tif (ctx.offset !== 0 || ctx.childIndex !== 0) return false;\n\t\tif (ctx.child.type === 'list_item') return false;\n\n\t\tconst builder = ctx.state.transaction('input');\n\n\t\tif (ctx.childCount === 1) {\n\t\t\t// Sole child: dissolve the quote, the child takes its place.\n\t\t\tbuilder.removeNode(ctx.quoteParentPath, ctx.quoteIndex);\n\t\t\tbuilder.insertNode(ctx.quoteParentPath, ctx.quoteIndex, ctx.child);\n\t\t} else {\n\t\t\t// Lift the first child out, immediately before the quote.\n\t\t\tbuilder.removeNode(ctx.quotePath, 0);\n\t\t\tbuilder.insertNode(ctx.quoteParentPath, ctx.quoteIndex, ctx.child);\n\t\t}\n\n\t\tbuilder.setSelection(createCollapsedSelection(ctx.child.id, 0));\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t});\n}\n","/**\n * Locale interface and default English locale for the BlockquotePlugin.\n */\n\nimport { type LocaleModuleMap, loadLocaleModule } from '../shared/LocaleLoader.js';\n\n// --- Locale Interface ---\n\nexport interface BlockquoteLocale {\n\treadonly label: string;\n\treadonly tooltip: (shortcut: string) => string;\n}\n\n// --- Default English Locale ---\n\nexport const BLOCKQUOTE_LOCALE_EN: BlockquoteLocale = {\n\tlabel: 'Blockquote',\n\ttooltip: (shortcut: string) => `Blockquote (${shortcut})`,\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: LocaleModuleMap<BlockquoteLocale> = import.meta.glob<{\n\tdefault: BlockquoteLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadBlockquoteLocale(lang: string): Promise<BlockquoteLocale> {\n\treturn loadLocaleModule(localeModules, lang, BLOCKQUOTE_LOCALE_EN);\n}\n","/** Blockquote styles using CSS logical properties for RTL support. */\nexport const BLOCKQUOTE_CSS = `\n.notectl-content blockquote {\n\tmargin: 0;\n\tpadding: 2px 0;\n\tpadding-inline-start: 16px;\n\tborder-inline-start: 3px solid var(--notectl-blockquote-border, var(--notectl-border));\n\tbackground: var(--notectl-blockquote-bg, transparent);\n\tcolor: var(--notectl-blockquote-fg, inherit);\n\tmin-height: 1.6em;\n}\n`;\n","/**\n * BlockquotePlugin: registers a blockquote block type with NodeSpec,\n * toggle command, keyboard shortcut, input rule, and a toolbar button.\n */\n\nimport {\n\tliftSelectionFromContainer,\n\twrapSelectionInContainer,\n} from '../../commands/ContainerCommands.js';\nimport type { BlockNode } from '../../model/Document.js';\nimport { createBlockNode, generateBlockId } from '../../model/Document.js';\nimport { hasAncestorOfType } from '../../model/NodeResolver.js';\nimport { isCollapsed, isTextSelection } from '../../model/Selection.js';\nimport { nodeType } from '../../model/TypeBrands.js';\nimport { createBlockElement } from '../../view/DomUtils.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { registerBlockquoteKeymaps } from './BlockquoteKeyboardHandlers.js';\nimport {\n\tBLOCKQUOTE_LOCALE_EN,\n\ttype BlockquoteLocale,\n\tloadBlockquoteLocale,\n} from './BlockquoteLocale.js';\nimport { BLOCKQUOTE_CSS } from './BlockquoteStyles.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\tblockquote: Record<string, never>;\n\t}\n}\n\n// --- Configuration ---\n\nexport interface BlockquoteConfig {\n\treadonly locale?: BlockquoteLocale;\n}\n\nconst DEFAULT_CONFIG: BlockquoteConfig = {};\n\n// --- Plugin ---\n\nexport class BlockquotePlugin implements Plugin {\n\treadonly id = 'blockquote';\n\treadonly name = 'Blockquote';\n\treadonly priority = 35;\n\n\tprivate readonly config: BlockquoteConfig;\n\tprivate locale!: BlockquoteLocale;\n\n\tconstructor(config?: Partial<BlockquoteConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tBLOCKQUOTE_LOCALE_EN,\n\t\t\tloadBlockquoteLocale,\n\t\t);\n\t\tcontext.registerStyleSheet(BLOCKQUOTE_CSS);\n\t\tthis.registerNodeSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymap(context);\n\t\tthis.registerInputRule(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerNodeSpec(context: PluginContext): void {\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'blockquote',\n\t\t\tgroup: 'block',\n\t\t\t// Container block (issue #136): a blockquote wraps other blocks, mirroring\n\t\t\t// HTML flow-content semantics. `isolating` is intentionally NOT set so the\n\t\t\t// caret can flow across the container boundary (unlike table_cell).\n\t\t\tcontent: {\n\t\t\t\tallow: ['paragraph', 'heading', 'list_item', 'blockquote', 'horizontal_rule', 'code_block'],\n\t\t\t\tmin: 1,\n\t\t\t},\n\t\t\ttoDOM(node) {\n\t\t\t\tconst el = createBlockElement('blockquote', node.id);\n\t\t\t\tel.setAttribute('part', 'blockquote');\n\t\t\t\treturn el;\n\t\t\t},\n\t\t\ttoHTML(_node, content) {\n\t\t\t\treturn `<blockquote>${content || '<br>'}</blockquote>`;\n\t\t\t},\n\t\t\tparseHTML: [{ tag: 'blockquote' }],\n\t\t\tsanitize: { tags: ['blockquote'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('toggleBlockquote', () => {\n\t\t\treturn this.toggleBlockquote(context);\n\t\t});\n\n\t\tcontext.registerCommand('setBlockquote', () => {\n\t\t\treturn this.wrapInBlockquote(context);\n\t\t});\n\t}\n\n\tprivate registerKeymap(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-Shift->': () => context.executeCommand('toggleBlockquote'),\n\t\t});\n\t\tregisterBlockquoteKeymaps(context);\n\t}\n\n\tprivate registerInputRule(context: PluginContext): void {\n\t\tcontext.registerInputRule({\n\t\t\tpattern: /^> $/,\n\t\t\thandler(state, _match, start, _end) {\n\t\t\t\tconst sel = state.selection;\n\t\t\t\tif (!isTextSelection(sel)) return null;\n\t\t\t\tif (!isCollapsed(sel)) return null;\n\n\t\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\t\tif (!block || block.type !== 'paragraph') return null;\n\n\t\t\t\tconst index: number = state.doc.children.findIndex((b) => b.id === block.id);\n\t\t\t\tif (index < 0) return null;\n\n\t\t\t\t// B2: wrap the paragraph into a blockquote container, then strip the\n\t\t\t\t// \"> \" marker from the (now nested) paragraph in the same transaction.\n\t\t\t\tconst container = createBlockNode(nodeType('blockquote'), [block], generateBlockId());\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.removeNode([], index)\n\t\t\t\t\t.insertNode([], index, container)\n\t\t\t\t\t.deleteTextAt(sel.anchor.blockId, start, start + 2)\n\t\t\t\t\t.setSelection(sel)\n\t\t\t\t\t.build();\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon =\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z\"/></svg>';\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'blockquote',\n\t\t\tgroup: 'block',\n\t\t\ticon,\n\t\t\tlabel: this.locale.label,\n\t\t\ttooltip: this.locale.tooltip(formatShortcut('Mod-Shift->')),\n\t\t\tcommand: 'toggleBlockquote',\n\t\t\tisActive: (state) => {\n\t\t\t\tif (!isTextSelection(state.selection)) return false;\n\t\t\t\treturn hasAncestorOfType(state.doc, state.selection.anchor.blockId, 'blockquote');\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Toggles the blockquote container around the selection.\n\t * If the selection already lives inside a blockquote, its blocks are lifted\n\t * back out; otherwise the selected blocks are wrapped into one blockquote.\n\t */\n\tprivate toggleBlockquote(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\n\t\tconst tr = hasAncestorOfType(state.doc, sel.anchor.blockId, 'blockquote')\n\t\t\t? liftSelectionFromContainer(state, nodeType('blockquote'), sel)\n\t\t\t: wrapSelectionInContainer(state, nodeType('blockquote'), sel, this.isQuoteChild(context));\n\n\t\tif (!tr) return false;\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/** Wraps the selected blocks into a blockquote container (no toggle-off). */\n\tprivate wrapInBlockquote(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\n\t\tconst tr = wrapSelectionInContainer(\n\t\t\tstate,\n\t\t\tnodeType('blockquote'),\n\t\t\tsel,\n\t\t\tthis.isQuoteChild(context),\n\t\t);\n\t\tif (!tr) return false;\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Builds a predicate that reports whether a block may legally become a direct\n\t * child of the blockquote container, derived from the registered NodeSpec's\n\t * `content.allow` (single source of truth). Matches both concrete child types\n\t * and group names (e.g. `block`), so blocks the quote cannot hold (e.g. a\n\t * `table`) are excluded rather than nested into an invalid document.\n\t */\n\tprivate isQuoteChild(context: PluginContext): (block: BlockNode) => boolean {\n\t\tconst registry = context.getSchemaRegistry();\n\t\tconst allow: ReadonlySet<string> = new Set(\n\t\t\tregistry.getNodeSpec(nodeType('blockquote'))?.content?.allow ?? [],\n\t\t);\n\t\treturn (block: BlockNode): boolean => {\n\t\t\tif (allow.has(block.type)) return true;\n\t\t\tconst group: string | undefined = registry.getNodeSpec(block.type)?.group;\n\t\t\treturn group !== undefined && allow.has(group);\n\t\t};\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"BlockquotePlugin-4V7KV_Sb.mjs","names":[],"sources":["../../src/commands/ContainerCommands.ts","../../src/plugins/blockquote/BlockquoteKeyboardHandlers.ts","../../src/plugins/blockquote/BlockquoteLocale.ts","../../src/plugins/blockquote/BlockquoteStyles.ts","../../src/plugins/blockquote/BlockquotePlugin.ts"],"sourcesContent":["/**\n * Generic wrap/lift commands for container blocks (issue #136).\n *\n * A container block (e.g. `blockquote`) holds other blocks as children, mirroring\n * HTML flow-content semantics. Wrapping moves the selected top-level blocks into a\n * new container; lifting dissolves a container and returns its children to the\n * parent. Block identity (IDs) is preserved across both operations so the active\n * selection survives the structural change.\n *\n * Scope: operations act on top-level containers. Nested containers (quote-in-quote,\n * quote-in-cell) are intentionally out of scope here and return `null`.\n */\n\nimport type { BlockNode } from '../model/Document.js';\nimport { createBlockNode, generateBlockId, getBlockChildren } from '../model/Document.js';\nimport { findAncestorOfType } from '../model/NodeResolver.js';\nimport type { Selection } from '../model/Selection.js';\nimport { selectionRange } from '../model/Selection.js';\nimport type { BlockId, NodeTypeName } from '../model/TypeBrands.js';\nimport type { EditorState } from '../state/EditorState.js';\nimport type { Transaction } from '../state/Transaction.js';\n\n/** Returns the index in `doc.children` of the top-level ancestor of the given block. */\nfunction topLevelIndexOf(state: EditorState, blockId: BlockId): number {\n\tconst topId: BlockId | undefined = state.getNodePath(blockId)?.[0];\n\tif (!topId) return -1;\n\treturn state.doc.children.findIndex((b) => b.id === topId);\n}\n\n/**\n * Wraps the top-level blocks spanned by `selection` into new container blocks of\n * `containerType`. Returns `null` when the range cannot be resolved.\n *\n * `isAllowedChild` guards the container's schema (`content.allow`): blocks the\n * container cannot legally hold (e.g. a `table` inside a `blockquote`) are left at\n * the top level instead of being nested into an invalid document. Disallowed blocks\n * therefore split the range into separate contiguous runs, each wrapped in its own\n * container, mirroring `wrapIn`. Defaults to wrapping everything when omitted.\n * Returns `null` when no block in the range is wrappable.\n */\nexport function wrapSelectionInContainer(\n\tstate: EditorState,\n\tcontainerType: NodeTypeName,\n\tselection: Selection,\n\tisAllowedChild?: (block: BlockNode) => boolean,\n): Transaction | null {\n\tconst range = selectionRange(selection, state.getBlockOrder());\n\tconst fromIdx: number = topLevelIndexOf(state, range.from.blockId);\n\tconst toIdx: number = topLevelIndexOf(state, range.to.blockId);\n\tif (fromIdx < 0 || toIdx < 0) return null;\n\n\tconst lo: number = Math.min(fromIdx, toIdx);\n\tconst hi: number = Math.max(fromIdx, toIdx);\n\n\tconst blocks: readonly BlockNode[] = state.doc.children.slice(lo, hi + 1);\n\tconst allowed: (block: BlockNode) => boolean = isAllowedChild ?? (() => true);\n\n\t// Group the range into maximal runs of wrappable blocks; each run becomes one\n\t// container, disallowed blocks pass through unchanged and break the run.\n\tconst sequence: BlockNode[] = [];\n\tlet run: BlockNode[] = [];\n\tlet wrappedAny = false;\n\tconst flushRun = (): void => {\n\t\tif (run.length === 0) return;\n\t\tsequence.push(createBlockNode(containerType, run, generateBlockId()));\n\t\twrappedAny = true;\n\t\trun = [];\n\t};\n\tfor (const block of blocks) {\n\t\tif (allowed(block)) {\n\t\t\trun.push(block);\n\t\t} else {\n\t\t\tflushRun();\n\t\t\tsequence.push(block);\n\t\t}\n\t}\n\tflushRun();\n\n\tif (!wrappedAny) return null;\n\n\tconst builder = state.transaction('command');\n\tfor (let i: number = hi; i >= lo; i--) {\n\t\tbuilder.removeNode([], i);\n\t}\n\tsequence.forEach((node, i) => {\n\t\tbuilder.insertNode([], lo + i, node);\n\t});\n\tbuilder.setSelection(selection);\n\treturn builder.build();\n}\n\n/**\n * Lifts the children of the nearest top-level `containerType` ancestor of the\n * selection anchor back out to the top level, dissolving the container. Returns\n * `null` when no such top-level container surrounds the selection.\n */\nexport function liftSelectionFromContainer(\n\tstate: EditorState,\n\tcontainerType: NodeTypeName,\n\tselection: Selection,\n): Transaction | null {\n\tconst ancestor = findAncestorOfType(state.doc, selection.anchor.blockId, containerType);\n\t// Only top-level containers are dissolved (path === [containerId]).\n\tif (!ancestor || ancestor.path.length !== 1) return null;\n\n\tconst containerIdx: number = state.doc.children.findIndex((b) => b.id === ancestor.node.id);\n\tif (containerIdx < 0) return null;\n\n\tconst children: readonly BlockNode[] = getBlockChildren(ancestor.node);\n\n\tconst builder = state.transaction('command');\n\tbuilder.removeNode([], containerIdx);\n\tchildren.forEach((child, i) => {\n\t\tbuilder.insertNode([], containerIdx + i, child);\n\t});\n\tbuilder.setSelection(selection);\n\treturn builder.build();\n}\n","/**\n * Keyboard handlers for the blockquote container (issue #136, B2 model).\n *\n * Under the container model the caret lives in a child block of the blockquote,\n * not in the blockquote itself. These handlers manage the two container\n * boundaries; everything in between (splitting, merging, arrow navigation) is\n * left to the default commands, which already operate correctly on the nested\n * child blocks:\n *\n * - Enter in an empty last child → exit the blockquote (paragraph after it).\n * - Backspace at start of the first child → lift that child out of the quote.\n *\n * List items are deferred to the list plugin's own handlers.\n */\n\nimport type { BlockNode } from '../../model/Document.js';\nimport { createEmptyParagraph, getBlockChildren, getBlockLength } from '../../model/Document.js';\nimport { resolveParentByPath } from '../../model/NodeResolver.js';\nimport { createCollapsedSelection, isCollapsed, isTextSelection } from '../../model/Selection.js';\nimport type { BlockId } from '../../model/TypeBrands.js';\nimport type { EditorState } from '../../state/EditorState.js';\nimport type { PluginContext } from '../Plugin.js';\n\n// --- Context Guard ---\n\ninterface QuoteChildContext {\n\treadonly state: EditorState;\n\treadonly quotePath: readonly BlockId[];\n\treadonly quoteParentPath: readonly BlockId[];\n\treadonly quoteIndex: number;\n\treadonly child: BlockNode;\n\treadonly childIndex: number;\n\treadonly childCount: number;\n\treadonly offset: number;\n}\n\n/**\n * Resolves the caret context when the cursor sits in a direct child of a\n * blockquote. Returns false (not handled) otherwise, so the default keymap and\n * other plugins keep their behavior.\n */\nfunction withBlockquoteChildContext(\n\tcontext: PluginContext,\n\thandler: (ctx: QuoteChildContext) => boolean,\n): boolean {\n\tconst state: EditorState = context.getState();\n\tif (!isTextSelection(state.selection)) return false;\n\tconst sel = state.selection;\n\tif (!isCollapsed(sel)) return false;\n\n\tconst childId: BlockId = sel.anchor.blockId;\n\tconst quote: BlockNode | undefined = state.getParent(childId);\n\tif (!quote || quote.type !== 'blockquote') return false;\n\n\tconst child: BlockNode | undefined = state.getBlock(childId);\n\tif (!child) return false;\n\n\tconst quotePath: BlockId[] | undefined = state.getNodePath(quote.id);\n\tif (!quotePath) return false;\n\tconst parentRef = resolveParentByPath(state.doc, quotePath);\n\tif (!parentRef) return false;\n\n\tconst children: readonly BlockNode[] = getBlockChildren(quote);\n\tconst childIndex: number = children.findIndex((b) => b.id === childId);\n\tif (childIndex < 0) return false;\n\n\treturn handler({\n\t\tstate,\n\t\tquotePath,\n\t\tquoteParentPath: quotePath.slice(0, -1),\n\t\tquoteIndex: parentRef.index,\n\t\tchild,\n\t\tchildIndex,\n\t\tchildCount: children.length,\n\t\toffset: sel.anchor.offset,\n\t});\n}\n\n/** Registers the blockquote container keyboard handlers at context priority. */\nexport function registerBlockquoteKeymaps(context: PluginContext): void {\n\tcontext.registerKeymap(\n\t\t{\n\t\t\tEnter: () => handleEnterExit(context),\n\t\t\tBackspace: () => handleBackspaceLift(context),\n\t\t},\n\t\t{ priority: 'context' },\n\t);\n}\n\n// --- Handlers ---\n\n/**\n * Enter in an empty last child of the blockquote exits the container: a fresh\n * paragraph is created after the quote (or, when that child is the quote's only\n * child, the quote dissolves into that paragraph). Any other case returns false\n * so the default splitBlock creates a new line inside the quote.\n */\nfunction handleEnterExit(context: PluginContext): boolean {\n\treturn withBlockquoteChildContext(context, (ctx) => {\n\t\tif (ctx.child.type === 'list_item') return false;\n\t\tconst isLast: boolean = ctx.childIndex === ctx.childCount - 1;\n\t\tif (!isLast || getBlockLength(ctx.child) > 0) return false;\n\n\t\tconst paragraph: BlockNode = createEmptyParagraph();\n\t\tconst builder = ctx.state.transaction('input');\n\n\t\tif (ctx.childCount === 1) {\n\t\t\t// Sole child: dissolve the quote, replacing it with the paragraph.\n\t\t\tbuilder.removeNode(ctx.quoteParentPath, ctx.quoteIndex);\n\t\t\tbuilder.insertNode(ctx.quoteParentPath, ctx.quoteIndex, paragraph);\n\t\t} else {\n\t\t\t// Drop the empty trailing child and continue after the quote.\n\t\t\tbuilder.removeNode(ctx.quotePath, ctx.childIndex);\n\t\t\tbuilder.insertNode(ctx.quoteParentPath, ctx.quoteIndex + 1, paragraph);\n\t\t}\n\n\t\tbuilder.setSelection(createCollapsedSelection(paragraph.id, 0));\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t});\n}\n\n/**\n * Backspace at the start of the blockquote's first child lifts that child out of\n * the quote (placing it directly before the quote, or dissolving the quote when\n * it was the only child). Inner children at offset 0 fall through to the default\n * merge, which joins adjacent siblings within the quote.\n */\nfunction handleBackspaceLift(context: PluginContext): boolean {\n\treturn withBlockquoteChildContext(context, (ctx) => {\n\t\tif (ctx.offset !== 0 || ctx.childIndex !== 0) return false;\n\t\tif (ctx.child.type === 'list_item') return false;\n\n\t\tconst builder = ctx.state.transaction('input');\n\n\t\tif (ctx.childCount === 1) {\n\t\t\t// Sole child: dissolve the quote, the child takes its place.\n\t\t\tbuilder.removeNode(ctx.quoteParentPath, ctx.quoteIndex);\n\t\t\tbuilder.insertNode(ctx.quoteParentPath, ctx.quoteIndex, ctx.child);\n\t\t} else {\n\t\t\t// Lift the first child out, immediately before the quote.\n\t\t\tbuilder.removeNode(ctx.quotePath, 0);\n\t\t\tbuilder.insertNode(ctx.quoteParentPath, ctx.quoteIndex, ctx.child);\n\t\t}\n\n\t\tbuilder.setSelection(createCollapsedSelection(ctx.child.id, 0));\n\t\tcontext.dispatch(builder.build());\n\t\treturn true;\n\t});\n}\n","/**\n * Locale interface and default English locale for the BlockquotePlugin.\n */\n\nimport { type LocaleModuleMap, loadLocaleModule } from '../shared/LocaleLoader.js';\n\n// --- Locale Interface ---\n\nexport interface BlockquoteLocale {\n\treadonly label: string;\n\treadonly tooltip: (shortcut: string) => string;\n}\n\n// --- Default English Locale ---\n\nexport const BLOCKQUOTE_LOCALE_EN: BlockquoteLocale = {\n\tlabel: 'Blockquote',\n\ttooltip: (shortcut: string) => `Blockquote (${shortcut})`,\n};\n\n// --- Lazy Locale Loader ---\n\nconst localeModules: LocaleModuleMap<BlockquoteLocale> = import.meta.glob<{\n\tdefault: BlockquoteLocale;\n}>('./locales/*.ts', { eager: false });\n\nexport async function loadBlockquoteLocale(lang: string): Promise<BlockquoteLocale> {\n\treturn loadLocaleModule(localeModules, lang, BLOCKQUOTE_LOCALE_EN);\n}\n","/** Blockquote styles using CSS logical properties for RTL support. */\nexport const BLOCKQUOTE_CSS = `\n.notectl-content blockquote {\n\tmargin: 0;\n\tpadding: 2px 0;\n\tpadding-inline-start: 16px;\n\tborder-inline-start: 3px solid var(--notectl-blockquote-border, var(--notectl-border));\n\tbackground: var(--notectl-blockquote-bg, transparent);\n\tcolor: var(--notectl-blockquote-fg, inherit);\n\tmin-height: 1.6em;\n}\n`;\n","/**\n * BlockquotePlugin: registers a blockquote block type with NodeSpec,\n * toggle command, keyboard shortcut, input rule, and a toolbar button.\n */\n\nimport {\n\tliftSelectionFromContainer,\n\twrapSelectionInContainer,\n} from '../../commands/ContainerCommands.js';\nimport type { BlockNode } from '../../model/Document.js';\nimport { createBlockNode, generateBlockId } from '../../model/Document.js';\nimport { hasAncestorOfType } from '../../model/NodeResolver.js';\nimport { isCollapsed, isTextSelection } from '../../model/Selection.js';\nimport { nodeType } from '../../model/TypeBrands.js';\nimport { createBlockElement } from '../../view/DomUtils.js';\nimport type { Plugin, PluginContext } from '../Plugin.js';\nimport { resolveLocale } from '../shared/PluginHelpers.js';\nimport { formatShortcut } from '../shared/ShortcutFormatting.js';\nimport { registerBlockquoteKeymaps } from './BlockquoteKeyboardHandlers.js';\nimport {\n\tBLOCKQUOTE_LOCALE_EN,\n\ttype BlockquoteLocale,\n\tloadBlockquoteLocale,\n} from './BlockquoteLocale.js';\nimport { BLOCKQUOTE_CSS } from './BlockquoteStyles.js';\n\n// --- Attribute Registry Augmentation ---\n\ndeclare module '../../model/AttrRegistry.js' {\n\tinterface NodeAttrRegistry {\n\t\tblockquote: Record<string, never>;\n\t}\n}\n\n// --- Configuration ---\n\nexport interface BlockquoteConfig {\n\treadonly locale?: BlockquoteLocale;\n}\n\nconst DEFAULT_CONFIG: BlockquoteConfig = {};\n\n// --- Plugin ---\n\nexport class BlockquotePlugin implements Plugin {\n\treadonly id = 'blockquote';\n\treadonly name = 'Blockquote';\n\treadonly priority = 35;\n\n\tprivate readonly config: BlockquoteConfig;\n\tprivate locale!: BlockquoteLocale;\n\n\tconstructor(config?: Partial<BlockquoteConfig>) {\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\tasync init(context: PluginContext): Promise<void> {\n\t\tthis.locale = await resolveLocale(\n\t\t\tcontext,\n\t\t\tthis.config.locale,\n\t\t\tBLOCKQUOTE_LOCALE_EN,\n\t\t\tloadBlockquoteLocale,\n\t\t);\n\t\tcontext.registerStyleSheet(BLOCKQUOTE_CSS);\n\t\tthis.registerNodeSpec(context);\n\t\tthis.registerCommands(context);\n\t\tthis.registerKeymap(context);\n\t\tthis.registerInputRule(context);\n\t\tthis.registerToolbarItem(context);\n\t}\n\n\tprivate registerNodeSpec(context: PluginContext): void {\n\t\tcontext.registerNodeSpec({\n\t\t\ttype: 'blockquote',\n\t\t\tgroup: 'block',\n\t\t\t// Container block (issue #136): a blockquote wraps other blocks, mirroring\n\t\t\t// HTML flow-content semantics. `isolating` is intentionally NOT set so the\n\t\t\t// caret can flow across the container boundary (unlike table_cell).\n\t\t\tcontent: {\n\t\t\t\tallow: ['paragraph', 'heading', 'list_item', 'blockquote', 'horizontal_rule', 'code_block'],\n\t\t\t\tmin: 1,\n\t\t\t},\n\t\t\ttoDOM(node) {\n\t\t\t\tconst el = createBlockElement('blockquote', node.id);\n\t\t\t\tel.setAttribute('part', 'blockquote');\n\t\t\t\treturn el;\n\t\t\t},\n\t\t\ttoHTML(_node, content) {\n\t\t\t\treturn `<blockquote>${content || '<br>'}</blockquote>`;\n\t\t\t},\n\t\t\tparseHTML: [{ tag: 'blockquote' }],\n\t\t\tsanitize: { tags: ['blockquote'] },\n\t\t});\n\t}\n\n\tprivate registerCommands(context: PluginContext): void {\n\t\tcontext.registerCommand('toggleBlockquote', () => {\n\t\t\treturn this.toggleBlockquote(context);\n\t\t});\n\n\t\tcontext.registerCommand('setBlockquote', () => {\n\t\t\treturn this.wrapInBlockquote(context);\n\t\t});\n\t}\n\n\tprivate registerKeymap(context: PluginContext): void {\n\t\tcontext.registerKeymap({\n\t\t\t'Mod-Shift->': () => context.executeCommand('toggleBlockquote'),\n\t\t});\n\t\tregisterBlockquoteKeymaps(context);\n\t}\n\n\tprivate registerInputRule(context: PluginContext): void {\n\t\tcontext.registerInputRule({\n\t\t\tpattern: /^> $/,\n\t\t\thandler(state, _match, start, _end) {\n\t\t\t\tconst sel = state.selection;\n\t\t\t\tif (!isTextSelection(sel)) return null;\n\t\t\t\tif (!isCollapsed(sel)) return null;\n\n\t\t\t\tconst block = state.getBlock(sel.anchor.blockId);\n\t\t\t\tif (!block || block.type !== 'paragraph') return null;\n\n\t\t\t\tconst index: number = state.doc.children.findIndex((b) => b.id === block.id);\n\t\t\t\tif (index < 0) return null;\n\n\t\t\t\t// B2: wrap the paragraph into a blockquote container, then strip the\n\t\t\t\t// \"> \" marker from the (now nested) paragraph in the same transaction.\n\t\t\t\tconst container = createBlockNode(nodeType('blockquote'), [block], generateBlockId());\n\t\t\t\treturn state\n\t\t\t\t\t.transaction('input')\n\t\t\t\t\t.removeNode([], index)\n\t\t\t\t\t.insertNode([], index, container)\n\t\t\t\t\t.deleteTextAt(sel.anchor.blockId, start, start + 2)\n\t\t\t\t\t.setSelection(sel)\n\t\t\t\t\t.build();\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate registerToolbarItem(context: PluginContext): void {\n\t\tconst icon =\n\t\t\t'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z\"/></svg>';\n\n\t\tcontext.registerToolbarItem({\n\t\t\tid: 'blockquote',\n\t\t\tgroup: 'block',\n\t\t\ticon,\n\t\t\tlabel: this.locale.label,\n\t\t\ttooltip: this.locale.tooltip(formatShortcut('Mod-Shift->')),\n\t\t\tcommand: 'toggleBlockquote',\n\t\t\tisActive: (state) => {\n\t\t\t\tif (!isTextSelection(state.selection)) return false;\n\t\t\t\treturn hasAncestorOfType(state.doc, state.selection.anchor.blockId, 'blockquote');\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Toggles the blockquote container around the selection.\n\t * If the selection already lives inside a blockquote, its blocks are lifted\n\t * back out; otherwise the selected blocks are wrapped into one blockquote.\n\t */\n\tprivate toggleBlockquote(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\n\t\tconst tr = hasAncestorOfType(state.doc, sel.anchor.blockId, 'blockquote')\n\t\t\t? liftSelectionFromContainer(state, nodeType('blockquote'), sel)\n\t\t\t: wrapSelectionInContainer(state, nodeType('blockquote'), sel, this.isQuoteChild(context));\n\n\t\tif (!tr) return false;\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/** Wraps the selected blocks into a blockquote container (no toggle-off). */\n\tprivate wrapInBlockquote(context: PluginContext): boolean {\n\t\tconst state = context.getState();\n\t\tconst sel = state.selection;\n\t\tif (!isTextSelection(sel)) return false;\n\n\t\tconst tr = wrapSelectionInContainer(\n\t\t\tstate,\n\t\t\tnodeType('blockquote'),\n\t\t\tsel,\n\t\t\tthis.isQuoteChild(context),\n\t\t);\n\t\tif (!tr) return false;\n\t\tcontext.dispatch(tr);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Builds a predicate that reports whether a block may legally become a direct\n\t * child of the blockquote container, derived from the registered NodeSpec's\n\t * `content.allow` (single source of truth). Matches both concrete child types\n\t * and group names (e.g. `block`), so blocks the quote cannot hold (e.g. a\n\t * `table`) are excluded rather than nested into an invalid document.\n\t */\n\tprivate isQuoteChild(context: PluginContext): (block: BlockNode) => boolean {\n\t\tconst registry = context.getSchemaRegistry();\n\t\tconst allow: ReadonlySet<string> = new Set(\n\t\t\tregistry.getNodeSpec(nodeType('blockquote'))?.content?.allow ?? [],\n\t\t);\n\t\treturn (block: BlockNode): boolean => {\n\t\t\tif (allow.has(block.type)) return true;\n\t\t\tconst group: string | undefined = registry.getNodeSpec(block.type)?.group;\n\t\t\treturn group !== undefined && allow.has(group);\n\t\t};\n\t}\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{g as n,h as t,n as o,p as e}from"./Document-r7vLOAGA.mjs";import{i as r,n as i,r as l,t as c}from"./WordBoundary-DxeMBRyP.mjs";import{o as a,u as s}from"./Selection-HYoVFpAx.mjs";import{r as u}from"./DomUtils-Bf7JLFlx.mjs";import{i as f,n as d,r as h}from"./GapCursorNavigation-ycNzuQVH.mjs";import{a as m,i as w,t as g}from"./NavigationQueries-Bt4zZ17v.mjs";import{r as k,t as b}from"./Platform-ByobkiCc.mjs";import{a as I,i as p,n as v,t as y}from"./SelectionSync-BSHIw1EE.mjs";import{a as x,s as B}from"./PluginHelpers-D4quRJ5a.mjs";function C(n){const t=n.selection;if(!s(t))return null;const o=a(t)?t.anchor.blockId:t.head.blockId;return 0===(a(t)?t.anchor.offset:t.head.offset)?null:h(n,o,0)}function M(n){const t=n.selection;if(!s(t))return null;const o=a(t)?t.anchor.blockId:t.head.blockId,r=n.getBlock(o);if(!r)return null;const i=e(r);return(a(t)?t.anchor.offset:t.head.offset)===i?null:h(n,o,i)}function A(n){const t=n.selection;return s(t)?{blockId:t.head.blockId,offset:t.head.offset}:null}function S(n,t,o){const e=n.getBlockOrder(),r=e.indexOf(t);if(r<0)return null;const i="forward"===o?r+1:r-1;return i<0||i>=e.length?null:e[i]??null}function E(r){const i=r.selection;if(!s(i))return null;if(!a(i))return h(r,i.head.blockId,i.head.offset);const c=i.anchor.blockId,u=r.getBlock(c);if(!u)return null;const d=i.anchor.offset;if(d<e(u))return"inline"===n(u,d)?.kind?h(r,c,d+1):h(r,c,d+(l(t(u),o(u,d))||1));const m=S(r,c,"forward");return m&&g(r,c,m)?w(r,m)?f(r,m):h(r,m,0):null}function V(i){const l=i.selection;if(!s(l))return null;if(!a(l))return h(i,l.head.blockId,l.head.offset);const c=l.anchor.blockId,u=i.getBlock(c);if(!u)return null;const d=l.anchor.offset;if(d>0)return"inline"===n(u,d-1)?.kind?h(i,c,d-1):h(i,c,d-(r(t(u),o(u,d))||1));const m=S(i,c,"backward");if(!m)return null;if(!g(i,c,m))return null;if(w(i,m))return f(i,m);const k=i.getBlock(m);return k?h(i,m,e(k)):null}function N(n){const t=n.selection;if(!s(t))return null;const o=n.getBlockOrder()[0];return o?w(n,o)?f(n,o):h(n,o,0):null}function T(n){const t=n.selection;if(!s(t))return null;const o=n.getBlockOrder(),r=o[o.length-1];if(!r)return null;if(w(n,r))return f(n,r);const i=n.getBlock(r);return i?h(n,r,e(i)):null}function j(r){const i=A(r);if(!i)return null;const c=r.selection;if(!s(c))return null;const a=r.getBlock(i.blockId);if(!a)return null;const u=e(a);if(i.offset<u){const e="inline"===n(a,i.offset)?.kind?1:l(t(a),o(a,i.offset))||1;return d(r,c.anchor.blockId,c.anchor.offset,i.blockId,i.offset+e)}const f=S(r,i.blockId,"forward");return f&&g(r,i.blockId,f)?d(r,c.anchor.blockId,c.anchor.offset,f,0):null}function H(i){const l=A(i);if(!l)return null;const c=i.selection;if(!s(c))return null;if(l.offset>0){const e=i.getBlock(l.blockId);if(!e)return null;const a="inline"===n(e,l.offset-1)?.kind?1:r(t(e),o(e,l.offset))||1;return d(i,c.anchor.blockId,c.anchor.offset,l.blockId,l.offset-a)}const a=S(i,l.blockId,"backward");if(!a)return null;if(!g(i,l.blockId,a))return null;const u=i.getBlock(a);return u?d(i,c.anchor.blockId,c.anchor.offset,a,e(u)):null}function O(n){const t=A(n);if(!t)return null;const o=n.selection;return s(o)?0===t.offset?null:d(n,o.anchor.blockId,o.anchor.offset,t.blockId,0):null}function R(n){const t=A(n);if(!t)return null;const o=n.selection;if(!s(o))return null;const r=n.getBlock(t.blockId);if(!r)return null;const i=e(r);return t.offset===i?null:d(n,o.anchor.blockId,o.anchor.offset,t.blockId,i)}function L(n){const t=n.selection;if(!s(t))return null;const o=n.getBlockOrder()[0];return o?t.head.blockId===o&&0===t.head.offset?null:d(n,t.anchor.blockId,t.anchor.offset,o,0):null}function D(n){const t=n.selection;if(!s(t))return null;const o=n.getBlockOrder(),r=o[o.length-1];if(!r)return null;const i=n.getBlock(r);if(!i)return null;const l=e(i);return t.head.blockId===r&&t.head.offset===l?null:d(n,t.anchor.blockId,t.anchor.offset,r,l)}function z(n,t,o){if("caretPositionFromPoint"in n){const e=n.caretPositionFromPoint(t,o);if(e)return{node:e.offsetNode,offset:e.offset}}if("caretRangeFromPoint"in n){const e=n.caretRangeFromPoint(t,o);if(e)return{node:e.startContainer,offset:e.startOffset}}return null}function P(n,t,o,e){return z(n,t,o)??(e&&n!==e?z(e,t,o):null)}function F(n,t,o,r){const i=t.selection;if(!s(i))return!1;if(!a(i))return!1;const l=t.getBlock(i.anchor.blockId);if(!l)return!1;const c=i.anchor.offset,f=e(l),d=n.querySelector(`[data-block-id="${i.anchor.blockId}"]`),h=d instanceof HTMLElement&&"rtl"===b(d);if("left"===o)return h?c===f:0===c;if("right"===o)return h?0===c:c===f;if("up"===o&&0===c)return!0;if("down"===o&&c===f)return!0;const m=v();return m&&m.modify?function(n,t,o,e){const r=p(n,t);if(!r)return!1;const i=e??_(t,n),l="up"===o?"backward":"forward";try{t.modify("move",l,"line");const o=p(n,t);if(!o)return!1;if(u(n,r.focusNode)!==u(n,o.focusNode))return!0;if(o.anchorNode===r.anchorNode&&o.anchorOffset===r.anchorOffset&&o.focusNode===r.focusNode&&o.focusOffset===r.focusOffset)return!0;if(i){const o=_(t,n);if(o&&Math.abs(o.top-i.top)<1)return!0}return!1}finally{try{t.setBaseAndExtent(r.anchorNode,r.anchorOffset,r.focusNode,r.focusOffset)}catch{}}}(n,m,o,r):"up"===o?0===c:c===f}function q(n,t){const o=K(n,t);if(!o)return null;if(o.isVoid)return f(n,o.targetId);const r=n.getBlock(o.targetId);if(!r)return null;const i="right"===t||"down"===t?0:e(r);return h(n,o.targetId,i)}function $(n,t,o,r){const i=K(t,o);if(!i)return null;if(i.isVoid)return f(t,i.targetId);const l=t.getBlock(i.targetId);if(!l)return null;const c=e(l);if(null!==r){const e=function(n,t,o,e){const r=n.querySelector(`[data-block-id="${t}"]`);if(!r)return null;const i=r.getBoundingClientRect(),l=function(n,t,o){if(!(n instanceof HTMLElement))return"down"===o?t.top+2:t.bottom-2;const e=getComputedStyle(n),r=Number.parseFloat(e.paddingTop)||0,i=Number.parseFloat(e.paddingBottom)||0;return"down"===o?t.top+r+2:t.bottom-i-2}(r,i,o),c=Math.min(Math.max(e,i.left),i.right-1),a=P(n.getRootNode(),c,l,n.ownerDocument);if(!a)return null;if(!r.contains(a.node))return null;const s=y(n,a.node,a.offset);return s?s.blockId!==t?null:s:null}(n,i.targetId,o,r);if(e)return h(t,e.blockId,e.offset)}if(s(t.selection)&&a(t.selection)){const n=t.selection.anchor.offset,o=Math.min(n,c);return h(t,i.targetId,o)}const u="down"===o?0:c;return h(t,i.targetId,u)}function U(t,o){if("up"===o||"down"===o)return null;const e=t.selection;if(!s(e))return null;if(!a(e))return null;const r=e.anchor.blockId,i=t.getBlock(r);if(!i)return null;const l=e.anchor.offset;return"right"===o?function(t,o,e,r){const i=n(e,r);return i&&"inline"===i.kind?h(t,o,r+1):null}(t,r,i,l):function(t,o,e,r){if(0===r)return null;const i=n(e,r-1);return i&&"inline"===i.kind?h(t,o,r-1):null}(t,r,i,l)}function _(n,t){if(n.rangeCount>0){const o=n.getRangeAt(0);if(!t||t.contains(o.startContainer)){const n=o.getClientRects();if(n.length>0)return n[0]??null;const t=o.getBoundingClientRect();if(t.height>0)return t}}if(t){const o=p(t,n);if(o)try{const n=document.createRange();n.setStart(o.anchorNode,o.anchorOffset),n.setEnd(o.focusNode,o.focusOffset);const t=n.getClientRects();return t.length>0?t[0]??null:n.getBoundingClientRect()}catch{}}return null}function K(n,t){const o=n.selection;if(!s(o))return null;const e="right"===t||"down"===t;return m(n,o.anchor.blockId,e)}function Q(n,t,o,e){return J(n,t,"move",o,e)}function G(n,t,o,e){return J(n,t,"extend",o,e)}function J(t,o,r,i,l){const c=o.selection;if(!s(c))return null;const a="move"===r?W:X,u=v();if(!u?.modify)return a(o,i,l);const m=p(t,u);if(!m)return a(o,i,l);try{u.modify(r,i,l);const a=I(t);if(!a)return null;const s="move"===r?c.anchor.blockId:c.head.blockId,m="move"===r?a.anchor:a.head,k=m.blockId;if(k!==s&&!g(o,s,k))return null;let b=m.offset;const p=o.getBlock(k);return p&&"inline"===n(p,b)?.kind&&"forward"===i&&(b=Math.min(b+1,e(p))),"move"===r?w(o,k)?f(o,k):h(o,k,b):d(o,c.anchor.blockId,c.anchor.offset,k,b)}finally{try{u.setBaseAndExtent(m.anchorNode,m.anchorOffset,m.focusNode,m.focusOffset)}catch{}}}function W(n,t,o){return"word"===o?function(n,t){const o=n.selection;if(!s(o))return null;const r=a(o)?o.anchor.blockId:o.head.blockId,l=a(o)?o.anchor.offset:o.head.offset,u=n.getBlock(r);if(!u)return null;const d="forward"===t?i(u,l):c(u,l);return d===l?function(n,t,o){const r=m(n,t,"forward"===o);if(!r)return null;if(r.isVoid)return f(n,r.targetId);const i=n.getBlock(r.targetId);if(!i)return null;const l="forward"===o?0:e(i);return h(n,r.targetId,l)}(n,r,t):h(n,r,d)}(n,t):"lineboundary"===o?"forward"===t?M(n):C(n):q(n,"forward"===t?"down":"up")}function X(n,t,o){const r=n.selection;if(!s(r))return null;const l=r.head,a=n.getBlock(l.blockId);if(!a)return null;let u=l.offset;if("word"===o)u="forward"===t?i(a,l.offset):c(a,l.offset);else{if("lineboundary"!==o){const o=m(n,l.blockId,"forward"===t);if(!o)return null;if(o.isVoid)return null;const i=n.getBlock(o.targetId);if(!i)return null;const c="forward"===t?0:e(i);return d(n,r.anchor.blockId,r.anchor.offset,o.targetId,c)}u="forward"===t?e(a):0}return d(n,r.anchor.blockId,r.anchor.offset,l.blockId,u)}function Y(n,t){return Q(n,t,"forward","word")}function Z(n,t){return Q(n,t,"backward","word")}function nn(n,t){return Q(n,t,"backward","lineboundary")}function tn(n,t){return Q(n,t,"forward","lineboundary")}function on(n,t){return Q(n,t,"backward","line")}function en(n,t){return Q(n,t,"forward","line")}function rn(n,t){return G(n,t,"forward","word")}function ln(n,t){return G(n,t,"backward","word")}function cn(n,t){return G(n,t,"backward","lineboundary")}function an(n,t){return G(n,t,"forward","lineboundary")}function sn(n,t){return G(n,t,"backward","line")}function un(n,t){return G(n,t,"forward","line")}var fn={paragraph:"Paragraph",heading1:"Heading 1",heading2:"Heading 2",heading3:"Heading 3",heading4:"Heading 4",heading5:"Heading 5",heading6:"Heading 6",codeBlock:"Code Block",blockquote:"Block Quote",listItem:"List Item",horizontalRule:"Horizontal Rule",image:"Image",table:"Table"},dn={paragraph:"paragraph",code_block:"codeBlock",blockquote:"blockquote",list_item:"listItem",horizontal_rule:"horizontalRule",image:"image",table:"table"},hn=/* #__PURE__ */Object.assign({"./locales/ar.ts":()=>import("./ar-BRX5E_Pw.mjs"),"./locales/de.ts":()=>import("./de-B9zSHWqY.mjs"),"./locales/es.ts":()=>import("./es-CgMfhkJJ.mjs"),"./locales/fr.ts":()=>import("./fr-0qEo3bRP.mjs"),"./locales/hi.ts":()=>import("./hi-CoclKAUM.mjs"),"./locales/pt.ts":()=>import("./pt-CMx2wPPY.mjs"),"./locales/ru.ts":()=>import("./ru-QGX8lOTs.mjs"),"./locales/zh.ts":()=>import("./zh-YfuE_m2y.mjs")});async function mn(n){return B(hn,n,fn)}var wn={"word:forward":Y,"word:backward":Z,"lineboundary:forward":tn,"lineboundary:backward":nn,"line:forward":en,"line:backward":on},gn={"word:forward":rn,"word:backward":ln,"lineboundary:forward":an,"lineboundary:backward":cn,"line:forward":un,"line:backward":sn},kn=class{id="caret-navigation";name="Caret Navigation";priority=4;context=null;lastAnnouncedBlockId=null;announceTimer=null;announce=null;locale=fn;async init(n){this.locale=await x(n,void 0,fn,mn),this.context=n,this.announce=t=>n.announce(t);const t=k(),o={"Shift-ArrowRight":()=>this.extendCharacterVisual("right"),"Shift-ArrowLeft":()=>this.extendCharacterVisual("left"),"Shift-ArrowUp":()=>this.viewExtendCommand("backward","line"),"Shift-ArrowDown":()=>this.viewExtendCommand("forward","line"),...t?{"Alt-ArrowRight":()=>this.viewMoveVisual("right","word"),"Alt-ArrowLeft":()=>this.viewMoveVisual("left","word"),"Shift-Alt-ArrowRight":()=>this.viewExtendVisual("right","word"),"Shift-Alt-ArrowLeft":()=>this.viewExtendVisual("left","word")}:{"Mod-ArrowRight":()=>this.viewMoveVisual("right","word"),"Mod-ArrowLeft":()=>this.viewMoveVisual("left","word"),"Mod-Shift-ArrowRight":()=>this.viewExtendVisual("right","word"),"Mod-Shift-ArrowLeft":()=>this.viewExtendVisual("left","word")},...t?{"Mod-ArrowLeft":()=>this.viewMoveVisual("left","lineboundary"),"Mod-ArrowRight":()=>this.viewMoveVisual("right","lineboundary"),"Mod-Shift-ArrowLeft":()=>this.viewExtendVisual("left","lineboundary"),"Mod-Shift-ArrowRight":()=>this.viewExtendVisual("right","lineboundary")}:{Home:()=>this.viewMoveCommand("backward","lineboundary"),End:()=>this.viewMoveCommand("forward","lineboundary"),"Shift-Home":()=>this.viewExtendCommand("backward","lineboundary"),"Shift-End":()=>this.viewExtendCommand("forward","lineboundary")},...t?{"Mod-ArrowUp":()=>this.modelCommand(N),"Mod-ArrowDown":()=>this.modelCommand(T),"Mod-Shift-ArrowUp":()=>this.modelCommand(L),"Mod-Shift-ArrowDown":()=>this.modelCommand(D)}:{"Mod-Home":()=>this.modelCommand(N),"Mod-End":()=>this.modelCommand(T),"Mod-Shift-Home":()=>this.modelCommand(L),"Mod-Shift-End":()=>this.modelCommand(D)}};n.registerKeymap(o,{priority:"navigation"})}onStateChange(n,t,o){const e=t.selection;if(!a(e)||!s(e))return null!==this.announceTimer&&(clearTimeout(this.announceTimer),this.announceTimer=null),void(this.lastAnnouncedBlockId=null);const r=e.anchor.blockId;r!==this.lastAnnouncedBlockId&&(null!==this.lastAnnouncedBlockId?(this.lastAnnouncedBlockId=r,null!==this.announceTimer&&clearTimeout(this.announceTimer),this.announceTimer=setTimeout(()=>{if(this.announceTimer=null,this.context?.hasAnnouncement())return;const n=t.getBlock(r);if(!n)return;const o=function(n,t,o){if("heading"===t&&o?.level){const t=`heading${o.level}`;if(t in n)return n[t]}const e=dn[t];return e?n[e]:t}(this.locale,n.type,n.attrs);this.announce?.(o)},150)):this.lastAnnouncedBlockId=r)}destroy(){null!==this.announceTimer&&clearTimeout(this.announceTimer),this.announceTimer=null,this.announce=null,this.context=null}modelCommand(n){if(!this.context)return!1;const t=n(this.context.getState());return!!t&&(this.context.dispatch(t),!0)}extendCharacterVisual(n){if(!this.context)return!1;const t=this.context.getState(),o="forward"===this.resolveLogicalHorizontalDirection(t,n)?j(t):H(t);return!!o&&(this.context.dispatch(o),!0)}viewMoveCommand(n,t){return this.dispatchViewCommand(wn,n,t)}viewMoveVisual(n,t){if(!this.context)return!1;const o=this.resolveLogicalHorizontalDirection(this.context.getState(),n);return this.viewMoveCommand(o,t)}viewExtendCommand(n,t){return this.dispatchViewCommand(gn,n,t)}dispatchViewCommand(n,t,o){if(!this.context)return!1;const e=n[`${o}:${t}`];if(!e)return!1;const r=e(this.context.getContainer(),this.context.getState());return!!r&&(this.context.dispatch(r),!0)}viewExtendVisual(n,t){if(!this.context)return!1;const o=this.resolveLogicalHorizontalDirection(this.context.getState(),n);return this.viewExtendCommand(o,t)}resolveLogicalHorizontalDirection(n,t){const o=n.selection;if(!s(o))return"left"===t?"backward":"forward";const e=this.context?.getContainer();if(!e)return"left"===t?"backward":"forward";const r=e.querySelector(`[data-block-id="${o.head.blockId}"]`);return r instanceof HTMLElement&&"rtl"===b(r)?"left"===t?"forward":"backward":"left"===t?"backward":"forward"}};export{V as A,P as C,O as D,R as E,C as F,T as M,N,D as O,M as P,U as S,j as T,Q as _,sn as a,q as b,ln as c,on as d,tn as f,G as g,Y as h,un as i,E as j,L as k,rn as l,Z as m,fn as n,an as o,nn as p,mn as r,cn as s,kn as t,en as u,F as v,H as w,$ as x,_ as y};
2
- //# sourceMappingURL=CaretNavigationPlugin-Bb7W_FMg.mjs.map
1
+ import{g as n,h as t,n as o,p as e}from"./Document-r7vLOAGA.mjs";import{i as r,n as i,r as l,t as c}from"./WordBoundary-DxeMBRyP.mjs";import{o as a,u as s}from"./Selection-HYoVFpAx.mjs";import{r as u}from"./DomUtils-Bf7JLFlx.mjs";import{i as f,n as d,r as h}from"./GapCursorNavigation-ycNzuQVH.mjs";import{a as m,i as w,t as g}from"./NavigationQueries-Bt4zZ17v.mjs";import{r as k,t as b}from"./Platform-ByobkiCc.mjs";import{a as I,i as p,n as v,t as y}from"./SelectionSync-BSHIw1EE.mjs";import{c as x,o as B}from"./PluginHelpers-KDuTlmXm.mjs";function C(n){const t=n.selection;if(!s(t))return null;const o=a(t)?t.anchor.blockId:t.head.blockId;return 0===(a(t)?t.anchor.offset:t.head.offset)?null:h(n,o,0)}function M(n){const t=n.selection;if(!s(t))return null;const o=a(t)?t.anchor.blockId:t.head.blockId,r=n.getBlock(o);if(!r)return null;const i=e(r);return(a(t)?t.anchor.offset:t.head.offset)===i?null:h(n,o,i)}function A(n){const t=n.selection;return s(t)?{blockId:t.head.blockId,offset:t.head.offset}:null}function S(n,t,o){const e=n.getBlockOrder(),r=e.indexOf(t);if(r<0)return null;const i="forward"===o?r+1:r-1;return i<0||i>=e.length?null:e[i]??null}function E(r){const i=r.selection;if(!s(i))return null;if(!a(i))return h(r,i.head.blockId,i.head.offset);const c=i.anchor.blockId,u=r.getBlock(c);if(!u)return null;const d=i.anchor.offset;if(d<e(u))return"inline"===n(u,d)?.kind?h(r,c,d+1):h(r,c,d+(l(t(u),o(u,d))||1));const m=S(r,c,"forward");return m&&g(r,c,m)?w(r,m)?f(r,m):h(r,m,0):null}function V(i){const l=i.selection;if(!s(l))return null;if(!a(l))return h(i,l.head.blockId,l.head.offset);const c=l.anchor.blockId,u=i.getBlock(c);if(!u)return null;const d=l.anchor.offset;if(d>0)return"inline"===n(u,d-1)?.kind?h(i,c,d-1):h(i,c,d-(r(t(u),o(u,d))||1));const m=S(i,c,"backward");if(!m)return null;if(!g(i,c,m))return null;if(w(i,m))return f(i,m);const k=i.getBlock(m);return k?h(i,m,e(k)):null}function N(n){const t=n.selection;if(!s(t))return null;const o=n.getBlockOrder()[0];return o?w(n,o)?f(n,o):h(n,o,0):null}function T(n){const t=n.selection;if(!s(t))return null;const o=n.getBlockOrder(),r=o[o.length-1];if(!r)return null;if(w(n,r))return f(n,r);const i=n.getBlock(r);return i?h(n,r,e(i)):null}function j(r){const i=A(r);if(!i)return null;const c=r.selection;if(!s(c))return null;const a=r.getBlock(i.blockId);if(!a)return null;const u=e(a);if(i.offset<u){const e="inline"===n(a,i.offset)?.kind?1:l(t(a),o(a,i.offset))||1;return d(r,c.anchor.blockId,c.anchor.offset,i.blockId,i.offset+e)}const f=S(r,i.blockId,"forward");return f&&g(r,i.blockId,f)?d(r,c.anchor.blockId,c.anchor.offset,f,0):null}function H(i){const l=A(i);if(!l)return null;const c=i.selection;if(!s(c))return null;if(l.offset>0){const e=i.getBlock(l.blockId);if(!e)return null;const a="inline"===n(e,l.offset-1)?.kind?1:r(t(e),o(e,l.offset))||1;return d(i,c.anchor.blockId,c.anchor.offset,l.blockId,l.offset-a)}const a=S(i,l.blockId,"backward");if(!a)return null;if(!g(i,l.blockId,a))return null;const u=i.getBlock(a);return u?d(i,c.anchor.blockId,c.anchor.offset,a,e(u)):null}function O(n){const t=A(n);if(!t)return null;const o=n.selection;return s(o)?0===t.offset?null:d(n,o.anchor.blockId,o.anchor.offset,t.blockId,0):null}function R(n){const t=A(n);if(!t)return null;const o=n.selection;if(!s(o))return null;const r=n.getBlock(t.blockId);if(!r)return null;const i=e(r);return t.offset===i?null:d(n,o.anchor.blockId,o.anchor.offset,t.blockId,i)}function L(n){const t=n.selection;if(!s(t))return null;const o=n.getBlockOrder()[0];return o?t.head.blockId===o&&0===t.head.offset?null:d(n,t.anchor.blockId,t.anchor.offset,o,0):null}function D(n){const t=n.selection;if(!s(t))return null;const o=n.getBlockOrder(),r=o[o.length-1];if(!r)return null;const i=n.getBlock(r);if(!i)return null;const l=e(i);return t.head.blockId===r&&t.head.offset===l?null:d(n,t.anchor.blockId,t.anchor.offset,r,l)}function z(n,t,o){if("caretPositionFromPoint"in n){const e=n.caretPositionFromPoint(t,o);if(e)return{node:e.offsetNode,offset:e.offset}}if("caretRangeFromPoint"in n){const e=n.caretRangeFromPoint(t,o);if(e)return{node:e.startContainer,offset:e.startOffset}}return null}function P(n,t,o,e){return z(n,t,o)??(e&&n!==e?z(e,t,o):null)}function F(n,t,o,r){const i=t.selection;if(!s(i))return!1;if(!a(i))return!1;const l=t.getBlock(i.anchor.blockId);if(!l)return!1;const c=i.anchor.offset,f=e(l),d=n.querySelector(`[data-block-id="${i.anchor.blockId}"]`),h=d instanceof HTMLElement&&"rtl"===b(d);if("left"===o)return h?c===f:0===c;if("right"===o)return h?0===c:c===f;if("up"===o&&0===c)return!0;if("down"===o&&c===f)return!0;const m=v();return m&&m.modify?function(n,t,o,e){const r=p(n,t);if(!r)return!1;const i=e??_(t,n),l="up"===o?"backward":"forward";try{t.modify("move",l,"line");const o=p(n,t);if(!o)return!1;if(u(n,r.focusNode)!==u(n,o.focusNode))return!0;if(o.anchorNode===r.anchorNode&&o.anchorOffset===r.anchorOffset&&o.focusNode===r.focusNode&&o.focusOffset===r.focusOffset)return!0;if(i){const o=_(t,n);if(o&&Math.abs(o.top-i.top)<1)return!0}return!1}finally{try{t.setBaseAndExtent(r.anchorNode,r.anchorOffset,r.focusNode,r.focusOffset)}catch{}}}(n,m,o,r):"up"===o?0===c:c===f}function q(n,t){const o=K(n,t);if(!o)return null;if(o.isVoid)return f(n,o.targetId);const r=n.getBlock(o.targetId);if(!r)return null;const i="right"===t||"down"===t?0:e(r);return h(n,o.targetId,i)}function $(n,t,o,r){const i=K(t,o);if(!i)return null;if(i.isVoid)return f(t,i.targetId);const l=t.getBlock(i.targetId);if(!l)return null;const c=e(l);if(null!==r){const e=function(n,t,o,e){const r=n.querySelector(`[data-block-id="${t}"]`);if(!r)return null;const i=r.getBoundingClientRect(),l=function(n,t,o){if(!(n instanceof HTMLElement))return"down"===o?t.top+2:t.bottom-2;const e=getComputedStyle(n),r=Number.parseFloat(e.paddingTop)||0,i=Number.parseFloat(e.paddingBottom)||0;return"down"===o?t.top+r+2:t.bottom-i-2}(r,i,o),c=Math.min(Math.max(e,i.left),i.right-1),a=P(n.getRootNode(),c,l,n.ownerDocument);if(!a)return null;if(!r.contains(a.node))return null;const s=y(n,a.node,a.offset);return s?s.blockId!==t?null:s:null}(n,i.targetId,o,r);if(e)return h(t,e.blockId,e.offset)}if(s(t.selection)&&a(t.selection)){const n=t.selection.anchor.offset,o=Math.min(n,c);return h(t,i.targetId,o)}const u="down"===o?0:c;return h(t,i.targetId,u)}function U(t,o){if("up"===o||"down"===o)return null;const e=t.selection;if(!s(e))return null;if(!a(e))return null;const r=e.anchor.blockId,i=t.getBlock(r);if(!i)return null;const l=e.anchor.offset;return"right"===o?function(t,o,e,r){const i=n(e,r);return i&&"inline"===i.kind?h(t,o,r+1):null}(t,r,i,l):function(t,o,e,r){if(0===r)return null;const i=n(e,r-1);return i&&"inline"===i.kind?h(t,o,r-1):null}(t,r,i,l)}function _(n,t){if(n.rangeCount>0){const o=n.getRangeAt(0);if(!t||t.contains(o.startContainer)){const n=o.getClientRects();if(n.length>0)return n[0]??null;const t=o.getBoundingClientRect();if(t.height>0)return t}}if(t){const o=p(t,n);if(o)try{const n=document.createRange();n.setStart(o.anchorNode,o.anchorOffset),n.setEnd(o.focusNode,o.focusOffset);const t=n.getClientRects();return t.length>0?t[0]??null:n.getBoundingClientRect()}catch{}}return null}function K(n,t){const o=n.selection;if(!s(o))return null;const e="right"===t||"down"===t;return m(n,o.anchor.blockId,e)}function Q(n,t,o,e){return J(n,t,"move",o,e)}function G(n,t,o,e){return J(n,t,"extend",o,e)}function J(t,o,r,i,l){const c=o.selection;if(!s(c))return null;const a="move"===r?W:X,u=v();if(!u?.modify)return a(o,i,l);const m=p(t,u);if(!m)return a(o,i,l);try{u.modify(r,i,l);const a=I(t);if(!a)return null;const s="move"===r?c.anchor.blockId:c.head.blockId,m="move"===r?a.anchor:a.head,k=m.blockId;if(k!==s&&!g(o,s,k))return null;let b=m.offset;const p=o.getBlock(k);return p&&"inline"===n(p,b)?.kind&&"forward"===i&&(b=Math.min(b+1,e(p))),"move"===r?w(o,k)?f(o,k):h(o,k,b):d(o,c.anchor.blockId,c.anchor.offset,k,b)}finally{try{u.setBaseAndExtent(m.anchorNode,m.anchorOffset,m.focusNode,m.focusOffset)}catch{}}}function W(n,t,o){return"word"===o?function(n,t){const o=n.selection;if(!s(o))return null;const r=a(o)?o.anchor.blockId:o.head.blockId,l=a(o)?o.anchor.offset:o.head.offset,u=n.getBlock(r);if(!u)return null;const d="forward"===t?i(u,l):c(u,l);return d===l?function(n,t,o){const r=m(n,t,"forward"===o);if(!r)return null;if(r.isVoid)return f(n,r.targetId);const i=n.getBlock(r.targetId);if(!i)return null;const l="forward"===o?0:e(i);return h(n,r.targetId,l)}(n,r,t):h(n,r,d)}(n,t):"lineboundary"===o?"forward"===t?M(n):C(n):q(n,"forward"===t?"down":"up")}function X(n,t,o){const r=n.selection;if(!s(r))return null;const l=r.head,a=n.getBlock(l.blockId);if(!a)return null;let u=l.offset;if("word"===o)u="forward"===t?i(a,l.offset):c(a,l.offset);else{if("lineboundary"!==o){const o=m(n,l.blockId,"forward"===t);if(!o)return null;if(o.isVoid)return null;const i=n.getBlock(o.targetId);if(!i)return null;const c="forward"===t?0:e(i);return d(n,r.anchor.blockId,r.anchor.offset,o.targetId,c)}u="forward"===t?e(a):0}return d(n,r.anchor.blockId,r.anchor.offset,l.blockId,u)}function Y(n,t){return Q(n,t,"forward","word")}function Z(n,t){return Q(n,t,"backward","word")}function nn(n,t){return Q(n,t,"backward","lineboundary")}function tn(n,t){return Q(n,t,"forward","lineboundary")}function on(n,t){return Q(n,t,"backward","line")}function en(n,t){return Q(n,t,"forward","line")}function rn(n,t){return G(n,t,"forward","word")}function ln(n,t){return G(n,t,"backward","word")}function cn(n,t){return G(n,t,"backward","lineboundary")}function an(n,t){return G(n,t,"forward","lineboundary")}function sn(n,t){return G(n,t,"backward","line")}function un(n,t){return G(n,t,"forward","line")}var fn={paragraph:"Paragraph",heading1:"Heading 1",heading2:"Heading 2",heading3:"Heading 3",heading4:"Heading 4",heading5:"Heading 5",heading6:"Heading 6",codeBlock:"Code Block",blockquote:"Block Quote",listItem:"List Item",horizontalRule:"Horizontal Rule",image:"Image",table:"Table"},dn={paragraph:"paragraph",code_block:"codeBlock",blockquote:"blockquote",list_item:"listItem",horizontal_rule:"horizontalRule",image:"image",table:"table"},hn=/* #__PURE__ */Object.assign({"./locales/ar.ts":()=>import("./ar-BRX5E_Pw.mjs"),"./locales/de.ts":()=>import("./de-B9zSHWqY.mjs"),"./locales/es.ts":()=>import("./es-CgMfhkJJ.mjs"),"./locales/fr.ts":()=>import("./fr-0qEo3bRP.mjs"),"./locales/hi.ts":()=>import("./hi-CoclKAUM.mjs"),"./locales/pt.ts":()=>import("./pt-CMx2wPPY.mjs"),"./locales/ru.ts":()=>import("./ru-QGX8lOTs.mjs"),"./locales/zh.ts":()=>import("./zh-YfuE_m2y.mjs")});async function mn(n){return x(hn,n,fn)}var wn={"word:forward":Y,"word:backward":Z,"lineboundary:forward":tn,"lineboundary:backward":nn,"line:forward":en,"line:backward":on},gn={"word:forward":rn,"word:backward":ln,"lineboundary:forward":an,"lineboundary:backward":cn,"line:forward":un,"line:backward":sn},kn=class{id="caret-navigation";name="Caret Navigation";priority=4;context=null;lastAnnouncedBlockId=null;announceTimer=null;announce=null;locale=fn;async init(n){this.locale=await B(n,void 0,fn,mn),this.context=n,this.announce=t=>n.announce(t);const t=k(),o={"Shift-ArrowRight":()=>this.extendCharacterVisual("right"),"Shift-ArrowLeft":()=>this.extendCharacterVisual("left"),"Shift-ArrowUp":()=>this.viewExtendCommand("backward","line"),"Shift-ArrowDown":()=>this.viewExtendCommand("forward","line"),...t?{"Alt-ArrowRight":()=>this.viewMoveVisual("right","word"),"Alt-ArrowLeft":()=>this.viewMoveVisual("left","word"),"Shift-Alt-ArrowRight":()=>this.viewExtendVisual("right","word"),"Shift-Alt-ArrowLeft":()=>this.viewExtendVisual("left","word")}:{"Mod-ArrowRight":()=>this.viewMoveVisual("right","word"),"Mod-ArrowLeft":()=>this.viewMoveVisual("left","word"),"Mod-Shift-ArrowRight":()=>this.viewExtendVisual("right","word"),"Mod-Shift-ArrowLeft":()=>this.viewExtendVisual("left","word")},...t?{"Mod-ArrowLeft":()=>this.viewMoveVisual("left","lineboundary"),"Mod-ArrowRight":()=>this.viewMoveVisual("right","lineboundary"),"Mod-Shift-ArrowLeft":()=>this.viewExtendVisual("left","lineboundary"),"Mod-Shift-ArrowRight":()=>this.viewExtendVisual("right","lineboundary")}:{Home:()=>this.viewMoveCommand("backward","lineboundary"),End:()=>this.viewMoveCommand("forward","lineboundary"),"Shift-Home":()=>this.viewExtendCommand("backward","lineboundary"),"Shift-End":()=>this.viewExtendCommand("forward","lineboundary")},...t?{"Mod-ArrowUp":()=>this.modelCommand(N),"Mod-ArrowDown":()=>this.modelCommand(T),"Mod-Shift-ArrowUp":()=>this.modelCommand(L),"Mod-Shift-ArrowDown":()=>this.modelCommand(D)}:{"Mod-Home":()=>this.modelCommand(N),"Mod-End":()=>this.modelCommand(T),"Mod-Shift-Home":()=>this.modelCommand(L),"Mod-Shift-End":()=>this.modelCommand(D)}};n.registerKeymap(o,{priority:"navigation"})}onStateChange(n,t,o){const e=t.selection;if(!a(e)||!s(e))return null!==this.announceTimer&&(clearTimeout(this.announceTimer),this.announceTimer=null),void(this.lastAnnouncedBlockId=null);const r=e.anchor.blockId;r!==this.lastAnnouncedBlockId&&(null!==this.lastAnnouncedBlockId?(this.lastAnnouncedBlockId=r,null!==this.announceTimer&&clearTimeout(this.announceTimer),this.announceTimer=setTimeout(()=>{if(this.announceTimer=null,this.context?.hasAnnouncement())return;const n=t.getBlock(r);if(!n)return;const o=function(n,t,o){if("heading"===t&&o?.level){const t=`heading${o.level}`;if(t in n)return n[t]}const e=dn[t];return e?n[e]:t}(this.locale,n.type,n.attrs);this.announce?.(o)},150)):this.lastAnnouncedBlockId=r)}destroy(){null!==this.announceTimer&&clearTimeout(this.announceTimer),this.announceTimer=null,this.announce=null,this.context=null}modelCommand(n){if(!this.context)return!1;const t=n(this.context.getState());return!!t&&(this.context.dispatch(t),!0)}extendCharacterVisual(n){if(!this.context)return!1;const t=this.context.getState(),o="forward"===this.resolveLogicalHorizontalDirection(t,n)?j(t):H(t);return!!o&&(this.context.dispatch(o),!0)}viewMoveCommand(n,t){return this.dispatchViewCommand(wn,n,t)}viewMoveVisual(n,t){if(!this.context)return!1;const o=this.resolveLogicalHorizontalDirection(this.context.getState(),n);return this.viewMoveCommand(o,t)}viewExtendCommand(n,t){return this.dispatchViewCommand(gn,n,t)}dispatchViewCommand(n,t,o){if(!this.context)return!1;const e=n[`${o}:${t}`];if(!e)return!1;const r=e(this.context.getContainer(),this.context.getState());return!!r&&(this.context.dispatch(r),!0)}viewExtendVisual(n,t){if(!this.context)return!1;const o=this.resolveLogicalHorizontalDirection(this.context.getState(),n);return this.viewExtendCommand(o,t)}resolveLogicalHorizontalDirection(n,t){const o=n.selection;if(!s(o))return"left"===t?"backward":"forward";const e=this.context?.getContainer();if(!e)return"left"===t?"backward":"forward";const r=e.querySelector(`[data-block-id="${o.head.blockId}"]`);return r instanceof HTMLElement&&"rtl"===b(r)?"left"===t?"forward":"backward":"left"===t?"backward":"forward"}};export{V as A,P as C,O as D,R as E,C as F,T as M,N,D as O,M as P,U as S,j as T,Q as _,sn as a,q as b,ln as c,on as d,tn as f,G as g,Y as h,un as i,E as j,L as k,rn as l,Z as m,fn as n,an as o,nn as p,mn as r,cn as s,kn as t,en as u,F as v,H as w,$ as x,_ as y};
2
+ //# sourceMappingURL=CaretNavigationPlugin-C6XBwp0N.mjs.map