@@ -148,6 +148,16 @@ export default ({ editorInstance, controls }) => {
148148 return object
149149 }
150150
151+ /**
152+ * Возвращает текстовый target для UI: обычный textbox или текст внутри активного shape.
153+ */
154+ const getActiveTextTarget = ( ) => {
155+ const activeText = getActiveText ( )
156+ if ( activeText ) return activeText
157+
158+ return editorInstance . shapeManager . getTextNode ( )
159+ }
160+
151161 /**
152162 * Проверяет, считается ли значение жирным начертанием.
153163 */
@@ -432,17 +442,69 @@ export default ({ editorInstance, controls }) => {
432442 const applyTextStyle = ( { style, options = { } } ) => {
433443 if ( isSyncingControls ) return
434444
435- const target = getActiveText ( )
436- if ( ! target ) return
445+ const activeText = getActiveText ( )
446+ if ( activeText ) {
447+ const updated = editorInstance . textManager . updateText ( {
448+ target : activeText ,
449+ style,
450+ ...options
451+ } )
452+ if ( ! updated ) return
453+
454+ syncTextControls ( updated )
455+ return
456+ }
437457
438- const updated = editorInstance . textManager . updateText ( {
439- target,
458+ const updatedShape = editorInstance . shapeManager . updateTextStyle ( {
440459 style,
441460 ...options
442461 } )
443- if ( ! updated ) return
462+ if ( ! updatedShape ) return
444463
445- syncTextControls ( updated )
464+ const updatedText = editorInstance . shapeManager . getTextNode ( {
465+ target : updatedShape
466+ } )
467+ if ( ! updatedText ) return
468+
469+ syncTextControls ( updatedText )
470+ }
471+
472+ /**
473+ * Применяет горизонтальное выравнивание к активному тексту или тексту внутри активного shape.
474+ */
475+ const applyTextAlign = ( { align } ) => {
476+ const activeText = getActiveText ( )
477+ if ( activeText ) {
478+ applyTextStyle ( { style : { align } } )
479+ return
480+ }
481+
482+ const updatedShape = editorInstance . shapeManager . setTextAlign ( {
483+ horizontal : align
484+ } )
485+ if ( ! updatedShape ) return
486+
487+ const updatedText = editorInstance . shapeManager . getTextNode ( {
488+ target : updatedShape
489+ } )
490+ if ( ! updatedText ) return
491+
492+ syncTextControls ( updatedText )
493+ }
494+
495+ /**
496+ * Возвращает последовательность align-значений для текущего активного target.
497+ */
498+ const getAlignSequenceForActiveTarget = ( ) => {
499+ const activeText = getActiveText ( )
500+ if ( activeText ) return ALIGN_SEQUENCE
501+
502+ const activeShapeText = editorInstance . shapeManager . getTextNode ( )
503+ if ( activeShapeText ) {
504+ return [ 'left' , 'center' , 'right' ]
505+ }
506+
507+ return ALIGN_SEQUENCE
446508 }
447509
448510 /**
@@ -621,7 +683,7 @@ export default ({ editorInstance, controls }) => {
621683 } )
622684 textColorInput . value = color
623685 setPaletteSelection ( { buttons : fillButtons , color } )
624- if ( ! getActiveText ( ) ) return
686+ if ( ! getActiveTextTarget ( ) ) return
625687
626688 applyTextStyle ( { style : { color } } )
627689 } )
@@ -638,9 +700,14 @@ export default ({ editorInstance, controls }) => {
638700 setPaletteSelection ( { buttons : strokeButtons , color } )
639701
640702 const width = getStrokeWidthFromInput ( )
641- if ( ! getActiveText ( ) || width <= 0 ) return
703+ if ( ! getActiveTextTarget ( ) || width <= 0 ) return
642704
643- applyTextStyle ( { style : { strokeColor : color } } )
705+ applyTextStyle ( {
706+ style : {
707+ strokeColor : color ,
708+ strokeWidth : width
709+ }
710+ } )
644711 } )
645712 }
646713 }
@@ -658,7 +725,7 @@ export default ({ editorInstance, controls }) => {
658725
659726 textContentInput . addEventListener ( 'input' , ( event ) => {
660727 if ( isSyncingControls ) return
661- if ( ! getActiveText ( ) ) return
728+ if ( ! getActiveTextTarget ( ) ) return
662729
663730 applyTextStyle ( {
664731 style : { text : event . target . value } ,
@@ -667,14 +734,14 @@ export default ({ editorInstance, controls }) => {
667734 } )
668735
669736 textContentInput . addEventListener ( 'change' , ( event ) => {
670- if ( ! getActiveText ( ) ) return
737+ if ( ! getActiveTextTarget ( ) ) return
671738 applyTextStyle ( { style : { text : event . target . value } } )
672739 } )
673740
674741 textFontFamilySelect . addEventListener ( 'change' , ( event ) => {
675742 const { value : family } = event . target
676743 ensureFontOption ( { family } )
677- if ( ! getActiveText ( ) ) return
744+ if ( ! getActiveTextTarget ( ) ) return
678745
679746 applyTextStyle ( { style : { fontFamily : family } } )
680747 } )
@@ -683,7 +750,7 @@ export default ({ editorInstance, controls }) => {
683750 const rawValue = Number ( event . target . value )
684751 const value = Math . max ( 1 , Number . isNaN ( rawValue ) ? 1 : Math . round ( rawValue ) )
685752 event . target . value = value
686- if ( ! getActiveText ( ) ) return
753+ if ( ! getActiveTextTarget ( ) ) return
687754
688755 applyTextStyle ( { style : { fontSize : value } } )
689756 } )
@@ -705,20 +772,21 @@ export default ({ editorInstance, controls }) => {
705772 button . addEventListener ( 'click' , ( ) => {
706773 const nextState = ! isButtonActive ( button )
707774 setToggleActive ( { button, isActive : nextState } )
708- if ( ! getActiveText ( ) ) return
775+ if ( ! getActiveTextTarget ( ) ) return
709776
710777 applyTextStyle ( { style : { [ key ] : nextState } } )
711778 } )
712779 }
713780
714781 textAlignToggle . addEventListener ( 'click' , ( ) => {
782+ const alignSequence = getAlignSequenceForActiveTarget ( )
715783 const currentAlign = textAlignToggle . dataset . align ?? 'left'
716- const currentIndex = ALIGN_SEQUENCE . indexOf ( currentAlign )
717- const nextAlign = ALIGN_SEQUENCE [ ( currentIndex + 1 ) % ALIGN_SEQUENCE . length ]
784+ const currentIndex = alignSequence . indexOf ( currentAlign )
785+ const nextAlign = alignSequence [ ( currentIndex + 1 ) % alignSequence . length ]
718786 updateAlignButtonDisplay ( { align : nextAlign } )
719- if ( ! getActiveText ( ) ) return
787+ if ( ! getActiveTextTarget ( ) ) return
720788
721- applyTextStyle ( { style : { align : nextAlign } } )
789+ applyTextAlign ( { align : nextAlign } )
722790 } )
723791 }
724792
@@ -733,7 +801,7 @@ export default ({ editorInstance, controls }) => {
733801 } )
734802 event . target . value = color
735803 setPaletteSelection ( { buttons : textColorButtons , color } )
736- if ( ! getActiveText ( ) ) return
804+ if ( ! getActiveTextTarget ( ) ) return
737805
738806 applyTextStyle ( { style : { color } } )
739807 } )
@@ -747,16 +815,21 @@ export default ({ editorInstance, controls }) => {
747815 setPaletteSelection ( { buttons : textStrokeButtons , color } )
748816
749817 const width = getStrokeWidthFromInput ( )
750- if ( ! getActiveText ( ) || width <= 0 ) return
818+ if ( ! getActiveTextTarget ( ) || width <= 0 ) return
751819
752- applyTextStyle ( { style : { strokeColor : color } } )
820+ applyTextStyle ( {
821+ style : {
822+ strokeColor : color ,
823+ strokeWidth : width
824+ }
825+ } )
753826 } )
754827
755828 textStrokeWidthInput . addEventListener ( 'input' , ( event ) => {
756829 const rawWidth = Number ( event . target . value )
757830 const width = Math . max ( 0 , Number . isNaN ( rawWidth ) ? 0 : Math . round ( rawWidth ) )
758831 setStrokeWidthUI ( { width } )
759- if ( ! getActiveText ( ) ) return
832+ if ( ! getActiveTextTarget ( ) ) return
760833
761834 if ( width === 0 ) {
762835 applyTextStyle ( {
@@ -779,7 +852,7 @@ export default ({ editorInstance, controls }) => {
779852 const rawWidth = Number ( event . target . value )
780853 const width = Math . max ( 0 , Number . isNaN ( rawWidth ) ? 0 : Math . round ( rawWidth ) )
781854 setStrokeWidthUI ( { width } )
782- if ( ! getActiveText ( ) ) return
855+ if ( ! getActiveTextTarget ( ) ) return
783856
784857 if ( width === 0 ) {
785858 applyTextStyle ( { style : { strokeWidth : 0 } } )
@@ -799,7 +872,7 @@ export default ({ editorInstance, controls }) => {
799872 const opacityPercent = Math . max ( 0 , Math . min ( 100 , Number . isNaN ( rawOpacity ) ? 0 : rawOpacity ) )
800873 event . target . value = opacityPercent
801874 textOpacityValue . textContent = `${ opacityPercent } %`
802- if ( ! getActiveText ( ) ) return
875+ if ( ! getActiveTextTarget ( ) ) return
803876
804877 applyTextStyle ( {
805878 style : { opacity : opacityPercent / 100 } ,
@@ -812,7 +885,7 @@ export default ({ editorInstance, controls }) => {
812885 const opacityPercent = Math . max ( 0 , Math . min ( 100 , Number . isNaN ( rawOpacity ) ? 0 : rawOpacity ) )
813886 event . target . value = opacityPercent
814887 textOpacityValue . textContent = `${ opacityPercent } %`
815- if ( ! getActiveText ( ) ) return
888+ if ( ! getActiveTextTarget ( ) ) return
816889
817890 applyTextStyle ( { style : { opacity : opacityPercent / 100 } } )
818891 } )
@@ -825,7 +898,7 @@ export default ({ editorInstance, controls }) => {
825898 textBackgroundEnabledCheckbox . addEventListener ( 'change' , ( ) => {
826899 const enabled = Boolean ( textBackgroundEnabledCheckbox . checked )
827900 setBackgroundControlsEnabled ( { enabled } )
828- if ( ! getActiveText ( ) ) return
901+ if ( ! getActiveTextTarget ( ) ) return
829902
830903 if ( ! enabled ) {
831904 applyTextStyle ( { style : { backgroundColor : '' } } )
@@ -841,7 +914,7 @@ export default ({ editorInstance, controls }) => {
841914 fallback : textBackgroundColorInput . value
842915 } )
843916 event . target . value = color
844- if ( ! getActiveText ( ) ) return
917+ if ( ! getActiveTextTarget ( ) ) return
845918 if ( ! textBackgroundEnabledCheckbox . checked ) return
846919
847920 applyTextStyle ( { style : { backgroundColor : color } } )
@@ -855,7 +928,7 @@ export default ({ editorInstance, controls }) => {
855928 fallback : 100
856929 } )
857930 textBackgroundOpacityValue . textContent = `${ opacityPercent } %`
858- if ( ! getActiveText ( ) ) return
931+ if ( ! getActiveTextTarget ( ) ) return
859932 if ( ! textBackgroundEnabledCheckbox . checked ) return
860933
861934 applyTextStyle ( {
@@ -872,7 +945,7 @@ export default ({ editorInstance, controls }) => {
872945 fallback : 100
873946 } )
874947 textBackgroundOpacityValue . textContent = `${ opacityPercent } %`
875- if ( ! getActiveText ( ) ) return
948+ if ( ! getActiveTextTarget ( ) ) return
876949 if ( ! textBackgroundEnabledCheckbox . checked ) return
877950
878951 applyTextStyle ( { style : { backgroundOpacity : opacityPercent / 100 } } )
@@ -893,7 +966,7 @@ export default ({ editorInstance, controls }) => {
893966 for ( const { input, key } of paddingInputs ) {
894967 input . addEventListener ( 'input' , ( ) => {
895968 const value = parseNumberInput ( { input, min : 0 , fallback : 0 } )
896- if ( ! getActiveText ( ) ) return
969+ if ( ! getActiveTextTarget ( ) ) return
897970 if ( ! textBackgroundEnabledCheckbox . checked ) return
898971
899972 applyTextStyle ( {
@@ -904,7 +977,7 @@ export default ({ editorInstance, controls }) => {
904977
905978 input . addEventListener ( 'change' , ( ) => {
906979 const value = parseNumberInput ( { input, min : 0 , fallback : 0 } )
907- if ( ! getActiveText ( ) ) return
980+ if ( ! getActiveTextTarget ( ) ) return
908981 if ( ! textBackgroundEnabledCheckbox . checked ) return
909982
910983 applyTextStyle ( { style : { [ key ] : value } } )
@@ -926,7 +999,7 @@ export default ({ editorInstance, controls }) => {
926999 for ( const { input, key } of radiusInputs ) {
9271000 input . addEventListener ( 'input' , ( ) => {
9281001 const value = parseNumberInput ( { input, min : 0 , fallback : 0 } )
929- if ( ! getActiveText ( ) ) return
1002+ if ( ! getActiveTextTarget ( ) ) return
9301003 if ( ! textBackgroundEnabledCheckbox . checked ) return
9311004
9321005 applyTextStyle ( {
@@ -937,7 +1010,7 @@ export default ({ editorInstance, controls }) => {
9371010
9381011 input . addEventListener ( 'change' , ( ) => {
9391012 const value = parseNumberInput ( { input, min : 0 , fallback : 0 } )
940- if ( ! getActiveText ( ) ) return
1013+ if ( ! getActiveTextTarget ( ) ) return
9411014 if ( ! textBackgroundEnabledCheckbox . checked ) return
9421015
9431016 applyTextStyle ( { style : { [ key ] : value } } )
@@ -956,6 +1029,7 @@ export default ({ editorInstance, controls }) => {
9561029
9571030 return {
9581031 getActiveText,
1032+ getActiveTextTarget,
9591033 syncTextControls,
9601034 isTextboxObject
9611035 }
0 commit comments