import { clamp , EditorState , extractPixelSize , isNumber , last , NodeWithPosition , Shape , Static , Transaction , } from '@remirror/core' ; import { ExtensionNodeFormattingMessages as Messages } from '@remirror/messages' ; export const increaseIndentOptions = { label : ( { t } ) => t ( Messages . INCREASE_INDENT_LABEL ) , icon : 'indentIncrease' , } ; export const decreaseIndentOptions = { label : ( { t } ) => t ( Messages . DECREASE_INDENT_LABEL ) , icon : 'indentDecrease' , } ; export const centerAlignOptions = { label : ( { t } ) => t ( Messages . CENTER_ALIGN_LABEL ) , icon : 'alignCenter' , active : createActiveCheck ( ( { node } ) => node . attrs . textAlign === 'center' ) , } ; export const justifyAlignOptions = { label : ( { t } ) => t ( Messages . JUSTIFY_ALIGN_LABEL ) , icon : 'alignJustify' , active : createActiveCheck ( ( { node } ) => node . attrs . textAlign === 'justify' ) , } ; export const rightAlignOptions = { label : ( { t } ) => t ( Messages . RIGHT_ALIGN_LABEL ) , icon : 'alignRight' , active : createActiveCheck ( ( { node } ) => node . attrs . textAlign === 'right' ) , } ; export const leftAlignOptions = { label : ( { t } ) => t ( Messages . LEFT_ALIGN_LABEL ) , icon : 'alignLeft' , active : createActiveCheck ( ( { node } ) => node . attrs . textAlign === 'left' ) , } ; function createActiveCheck ( predicate ) { return ( { excludeNodes } , store ) => { const { getState , nodeTags } = store ; const gatheredNodes = gatherNodes ( getState ( ) , nodeTags . formattingNode , excludeNodes ) ; return gatheredNodes . some ( predicate ) ; } ; } export function gatherNodes ( state , included , excluded ) { const gatheredNodes = [ ] ; state . doc . nodesBetween ( state . selection . from , state . selection . to , ( node , pos ) => { if ( excluded . includes ( node . type . name ) || ! included . includes ( node . type . name ) ) { return ; } gatheredNodes . push ( { node , pos } ) ; } ) ; return gatheredNodes ; } /**
 * The data attribute for an indented node attribute.
 */ export const NODE_INDENT_ATTRIBUTE = 'data-node-indent' ; /**
 * The data attribute text alignment within a block node which accepts
 * formatting.
 */ export const NODE_TEXT_ALIGNMENT_ATTRIBUTE = 'data-node-text-align' ; /**
 * The data attribute for the line height of a node.
 */ export const NODE_LINE_HEIGHT_ATTRIBUTE = 'data-line-height-align' ; export interface NodeFormattingOptions { /**
     * The nodes to exclude from being included in the formattable collection.
     */ excludeNodes ? : Static < string [ ] > ; /**
     * The list of available indent levels.
     *
     * The first item (0-index) is ignored. By default the indents start at index
     * `1`.
     */ indents ? : Static < string [ ] > ; } export type NodeTextAlignment = 'none' | 'left' | 'right' | 'center' | 'justify' | 'start' | 'end' ; /**
 * Extract the indent index from a list of indents and left margin.
 */ export function extractIndent ( indents , marginLeft ) { const largestIndent = extractPixelSize ( last ( indents ) ) ; const value = extractPixelSize ( marginLeft ?? '0' ) ; const max = indents . length ?? 1 ; const indentIncrement = largestIndent / max ; return clamp ( { max , min : 0 , value : Math . floor ( value / indentIncrement ) } ) ; } const NUMERIC_REGEX = /^\d+(?:\.\d+)?$/ ; const PERCENT_REGEX = /^(\d+(?:\.\d+)?)%$/ ; /**
 * Extract the line height from numeric or percentage line-height values
 */ export function extractLineHeight ( lineHeight ) { if ( isNumber ( lineHeight ) ) { return lineHeight ; } if ( ! lineHeight ) { return null ; } const lineHeightStr = lineHeight . trim ( ) ; const percentMatch = lineHeightStr . match ( PERCENT_REGEX ) ; if ( percentMatch ) { return Number . parseFloat ( percentMatch [ 1 ] as string ) / 100 ; } const numberMatch = lineHeightStr . match ( NUMERIC_REGEX ) ; if ( numberMatch ) { return Number . parseFloat ( numberMatch [ 0 ] as string ) ; } return null ; }