@@ -6,8 +6,12 @@ import {
66 type Transaction ,
77} from "@mxm-editor/pm" ;
88import type { Editor } from "../Editor" ;
9- import type { RawCommands } from "../types" ;
9+ import type {
10+ Range ,
11+ RawCommands ,
12+ } from "../types" ;
1013import { getMarkRange } from "../helpers" ;
14+ import { clamp } from "../utilities" ;
1115
1216function normalizeAttributeNames ( attributes : string | string [ ] ) {
1317 return Array . isArray ( attributes ) ? attributes : [ attributes ] ;
@@ -307,7 +311,42 @@ function resetNodeAttributes(
307311 return true ;
308312}
309313
310- type AttributeCommands = Pick < RawCommands , "updateAttributes" | "resetAttributes" > ;
314+ function resolveRange (
315+ transaction : Transaction ,
316+ position ?: number | Range ,
317+ ) {
318+ if ( typeof position === "number" ) {
319+ const nextPosition = clamp ( position , 0 , transaction . doc . content . size ) ;
320+
321+ return {
322+ from : nextPosition ,
323+ to : nextPosition ,
324+ } ;
325+ }
326+
327+ if ( position ) {
328+ const from = clamp ( position . from , 0 , transaction . doc . content . size ) ;
329+ const to = clamp ( position . to , from , transaction . doc . content . size ) ;
330+
331+ return {
332+ from,
333+ to,
334+ } ;
335+ }
336+
337+ return {
338+ from : transaction . selection . from ,
339+ to : transaction . selection . to ,
340+ } ;
341+ }
342+
343+ type AttributeCommands = Pick <
344+ RawCommands ,
345+ | "updateAttributes"
346+ | "resetAttributes"
347+ | "setTextDirection"
348+ | "unsetTextDirection"
349+ > ;
311350
312351export function createAttributeCommands ( editor : Editor ) : AttributeCommands {
313352 return {
@@ -356,5 +395,58 @@ export function createAttributeCommands(editor: Editor): AttributeCommands {
356395
357396 return false ;
358397 } ,
398+ setTextDirection :
399+ (
400+ direction : "ltr" | "rtl" | "auto" ,
401+ position ?: number | Range ,
402+ ) =>
403+ ( { tr, dispatch } ) => {
404+ const range = resolveRange ( tr , position ) ;
405+
406+ if ( ! dispatch ) {
407+ return true ;
408+ }
409+
410+ tr . doc . nodesBetween ( range . from , range . to , ( node , pos ) => {
411+ if ( node . isText || ! node . type . spec . attrs ?. dir ) {
412+ return true ;
413+ }
414+
415+ tr . setNodeMarkup ( pos , undefined , {
416+ ...node . attrs ,
417+ dir : direction ,
418+ } ) ;
419+
420+ return true ;
421+ } ) ;
422+
423+ return true ;
424+ } ,
425+ unsetTextDirection :
426+ ( position ?: number | Range ) =>
427+ ( { tr, dispatch } ) => {
428+ const range = resolveRange ( tr , position ) ;
429+
430+ if ( ! dispatch ) {
431+ return true ;
432+ }
433+
434+ tr . doc . nodesBetween ( range . from , range . to , ( node , pos ) => {
435+ if ( node . isText || ! node . type . spec . attrs ?. dir ) {
436+ return true ;
437+ }
438+
439+ const nextAttributes = {
440+ ...node . attrs ,
441+ } ;
442+
443+ delete nextAttributes . dir ;
444+ tr . setNodeMarkup ( pos , undefined , nextAttributes ) ;
445+
446+ return true ;
447+ } ) ;
448+
449+ return true ;
450+ } ,
359451 } ;
360452}
0 commit comments