@@ -6,6 +6,10 @@ import { generateOrderedListIndex } from '@helpers/orderedListUtils.js';
66import { getListItemStyleDefinitions } from '@helpers/list-numbering-helpers.js' ;
77import { docxNumberigHelpers } from '@/core/super-converter/v2/importer/listImporter.js' ;
88
9+ const MARKER_PADDING = 6 ;
10+ const MARKER_OFFSET_RIGHT = 4 ;
11+ const MIN_MARKER_WIDTH = 20 ;
12+
913const IS_DEBUGGING = false ;
1014
1115/**
@@ -60,7 +64,7 @@ export class ListItemNodeView {
6064 }
6165
6266 const pos = this . getPos ( ) ;
63- const { fontSize, fontFamily } = getTextStyleMarksFromLinkedStyles ( {
67+ const { fontSize, fontFamily, lineHeight } = getTextStyleMarksFromLinkedStyles ( {
6468 node : this . node ,
6569 pos,
6670 editor : this . editor ,
@@ -71,6 +75,7 @@ export class ListItemNodeView {
7175 this . dom . className = 'sd-editor-list-item-node-view' ;
7276 this . dom . style . fontSize = fontSize ;
7377 this . dom . style . fontFamily = fontFamily ? fontFamily : 'inherit' ;
78+ this . dom . style . lineHeight = lineHeight || '' ;
7479 this . dom . setAttribute ( 'data-marker-type' , orderMarker ) ;
7580 this . dom . setAttribute ( 'data-num-id' , numId ) ;
7681 this . dom . setAttribute ( 'data-list-level' , JSON . stringify ( listLevel ) ) ;
@@ -99,27 +104,44 @@ export class ListItemNodeView {
99104 const { attrs } = this . node ;
100105 const { styleId, numId, level, indent : inlineIndent } = attrs ;
101106
102- // Gather visible indents
103107 const defs = getListItemStyleDefinitions ( { styleId, node : this . node , numId, level, editor : this . editor } ) ;
104108 const visibleIndent = getVisibleIndent ( defs . stylePpr , defs . numDefPpr , inlineIndent ) ;
105-
106- let absoluteLeft = visibleIndent . left - ( visibleIndent . hanging || 0 ) ;
107- if ( ! absoluteLeft && absoluteLeft !== 0 ) absoluteLeft = 0 ;
108-
109- // Place the content at the visible indent left
110- let contentLeft = visibleIndent . left ;
111- if ( IS_DEBUGGING ) {
112- console . debug ( '[ListItemNodeView] absoluteLeft' , absoluteLeft ) ;
113- console . debug ( '[ListItemNodeView] contentLeft' , contentLeft ) ;
114- }
115-
116- if ( visibleIndent . left === absoluteLeft ) {
117- absoluteLeft -= 24 ;
118- }
119-
120- // Apply the styling
121- this . contentDOM . style . marginLeft = `${ contentLeft } px` ;
122- this . numberingDOM . style . left = `${ absoluteLeft } px` ;
109+ const lvlJc = defs . numLvlJs ?. attributes ?. [ 'w:val' ] || 'left' ;
110+
111+ const contentLeft = visibleIndent . left || 0 ;
112+ const hanging = visibleIndent . hanging || 0 ;
113+
114+ const handlers = {
115+ right : ( ) => {
116+ const calculatedWidth = calculateMarkerWidth ( this . dom , this . numberingDOM ) ;
117+ const minMarkerWidth = Math . max ( calculatedWidth , MIN_MARKER_WIDTH ) ;
118+ const effectiveHanging = Math . max ( hanging , minMarkerWidth ) ;
119+ const markerLeft = contentLeft - effectiveHanging - MARKER_OFFSET_RIGHT ;
120+ this . contentDOM . style . marginLeft = `${ contentLeft } px` ;
121+ this . numberingDOM . style . left = `${ markerLeft } px` ;
122+ this . numberingDOM . style . width = `${ effectiveHanging } px` ;
123+ this . numberingDOM . style . textAlign = 'right' ;
124+ } ,
125+ left : ( ) => {
126+ const calculatedWidth = calculateMarkerWidth ( this . dom , this . numberingDOM ) ;
127+ const minMarkerWidth = Math . max ( calculatedWidth , MIN_MARKER_WIDTH ) ;
128+ let markerLeft = contentLeft - hanging ;
129+ if ( markerLeft === contentLeft ) {
130+ markerLeft -= minMarkerWidth ;
131+ } else if ( minMarkerWidth > hanging ) {
132+ const diff = minMarkerWidth - hanging ;
133+ markerLeft -= diff ;
134+ }
135+ this . contentDOM . style . marginLeft = `${ contentLeft } px` ;
136+ this . numberingDOM . style . left = `${ markerLeft } px` ;
137+ this . numberingDOM . style . width = '' ;
138+ this . numberingDOM . style . textAlign = '' ;
139+ } ,
140+ } ;
141+
142+ const handleStyles = handlers [ lvlJc ] ?? handlers . left ;
143+
144+ handleStyles ( ) ;
123145 }
124146
125147 handleNumberingClick = ( ) => {
@@ -131,13 +153,14 @@ export class ListItemNodeView {
131153 this . node = node ;
132154 this . decorations = decorations ;
133155
134- const { fontSize, fontFamily } = getTextStyleMarksFromLinkedStyles ( {
156+ const { fontSize, fontFamily, lineHeight } = getTextStyleMarksFromLinkedStyles ( {
135157 node,
136158 pos : this . getPos ( ) ,
137159 editor : this . editor ,
138160 } ) ;
139161 this . dom . style . fontSize = fontSize ;
140162 this . dom . style . fontFamily = fontFamily || 'inherit' ;
163+ this . dom . style . lineHeight = lineHeight || '' ;
141164 }
142165
143166 destroy ( ) {
@@ -164,12 +187,14 @@ export function refreshAllListItemNodeViews() {
164187 * Get the text style marks from a list item
165188 * @param {Node } listItem - The list item node
166189 * @param {MarkType } markType - The mark type to look for
167- * @returns {Array } An array of text style marks
190+ * @returns {Object } An array of text style marks and attrs object
168191 */
169192function getListItemTextStyleMarks ( listItem , markType ) {
170193 let textStyleMarks = [ ] ;
194+ let attrs = { } ;
171195 listItem . forEach ( ( childNode ) => {
172196 if ( childNode . type . name !== 'paragraph' ) return ;
197+ attrs . lineHeight = childNode . attrs . lineHeight ;
173198 childNode . forEach ( ( textNode ) => {
174199 let isTextNode = textNode . type . name === 'text' ;
175200 let hasTextStyleMarks = markType . isInSet ( textNode . marks ) ;
@@ -179,7 +204,10 @@ function getListItemTextStyleMarks(listItem, markType) {
179204 }
180205 } ) ;
181206 } ) ;
182- return textStyleMarks ;
207+ return {
208+ marks : textStyleMarks ,
209+ attrs,
210+ } ;
183211}
184212
185213/**
@@ -199,12 +227,13 @@ function getTextStyleMarksFromLinkedStyles({ node, pos, editor }) {
199227
200228 // 2. Find all textStyle marks on this node
201229 const textStyleType = getMarkType ( 'textStyle' , editor . schema ) ;
202- const allMarks = getListItemTextStyleMarks ( node , textStyleType ) ;
230+ const { marks : allMarks , attrs : allAttrs } = getListItemTextStyleMarks ( node , textStyleType ) ;
203231 const styleMarks = allMarks . filter ( ( m ) => m . type === textStyleType ) ;
204232
205233 // 3. Helpers to find the first mark that has a fontSize / fontFamily attr
206234 const sizeMark = styleMarks . find ( ( m ) => m . attrs . fontSize ) ;
207235 const familyMark = styleMarks . find ( ( m ) => m . attrs . fontFamily ) ;
236+ const lineHeight = allAttrs . lineHeight ;
208237
209238 // 4. Compute final fontSize (parse it, fall back to default if invalid)
210239 let fontSize = sizeMark
@@ -233,7 +262,7 @@ function getTextStyleMarksFromLinkedStyles({ node, pos, editor }) {
233262 }
234263 }
235264
236- return { fontSize, fontFamily } ;
265+ return { fontSize, fontFamily, lineHeight } ;
237266}
238267
239268/**
@@ -252,7 +281,7 @@ const getStylesFromLinkedStyles = ({ node, pos, editor }) => {
252281 const decorationsInPlace = linkedStyles ?. find ( pos , pos + node . nodeSize ) ;
253282 // We are looking from the end as there may be several decorations
254283 // and we need to find the most specific one.
255- const styleDeco = decorationsInPlace ?. findLast ( ( dec ) => dec . type . attrs ?. style ) ;
284+ const styleDeco = decorationsInPlace ?. find ( ( dec ) => dec . type . attrs ?. style ) ;
256285 const style = styleDeco ?. type . attrs ?. style ;
257286
258287 const stylesArray = style ?. split ( ';' ) || [ ] ;
@@ -291,5 +320,32 @@ export const getVisibleIndent = (stylePpr, numDefPpr, inlineIndent) => {
291320 if ( IS_DEBUGGING ) console . debug ( '[getVisibleIndent] numDefIndent' , numDefIndent , numDefIndentTag , '\n\n' ) ;
292321
293322 const indent = combineIndents ( styleIndent , numDefIndent ) ;
294- return combineIndents ( indent , inlineIndent ) ;
323+ const result = combineIndents ( indent , inlineIndent ) ;
324+
325+ return result ;
295326} ;
327+
328+ function calculateMarkerWidth ( dom , numberingDOM , { withPadding = true } = { } ) {
329+ const markerText = numberingDOM . textContent || '' ;
330+ const fontSize = dom . style . fontSize || '10pt' ;
331+ const fontValue = dom . style . fontFamily ;
332+ const fontFamily = fontValue && fontValue !== 'inherit' ? fontValue : 'Arial' ;
333+
334+ if ( ! markerText . trim ( ) ) return 0 ;
335+
336+ try {
337+ const canvas = document . createElement ( 'canvas' ) ;
338+ const context = canvas . getContext ( '2d' ) ;
339+
340+ const fontSizePx = fontSize . includes ( 'pt' ) ? Number . parseFloat ( fontSize ) * 1.33 : Number . parseFloat ( fontSize ) ;
341+
342+ context . font = `${ fontSizePx } px ${ fontFamily } ` ;
343+
344+ const textWidth = context . measureText ( markerText ) . width ;
345+ const resultWidth = withPadding ? Math . ceil ( textWidth + MARKER_PADDING ) : Math . ceil ( textWidth ) ;
346+
347+ return resultWidth ;
348+ } catch ( err ) {
349+ return 0 ;
350+ }
351+ }
0 commit comments