@leafer-ui/text 1.0.0-beta.8 → 1.0.0-rc.10

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.
package/package.json CHANGED
@@ -1,28 +1,31 @@
1
1
  {
2
2
  "name": "@leafer-ui/text",
3
- "version": "1.0.0-beta.8",
3
+ "version": "1.0.0-rc.10",
4
4
  "description": "@leafer-ui/text",
5
5
  "author": "Chao (Leafer) Wan",
6
6
  "license": "MIT",
7
7
  "main": "src/index.ts",
8
+ "types": "types/index.d.ts",
8
9
  "files": [
9
- "src"
10
+ "src",
11
+ "types",
12
+ "dist"
10
13
  ],
11
14
  "repository": {
12
15
  "type": "git",
13
16
  "url": "https://github.com/leaferjs/ui.git"
14
17
  },
15
- "homepage": "https://github.com/leaferjs/ui/tree/main/packages/text",
18
+ "homepage": "https://github.com/leaferjs/ui/tree/main/packages/partner/text",
16
19
  "bugs": "https://github.com/leaferjs/ui/issues",
17
20
  "keywords": [
18
21
  "leafer-ui",
19
22
  "leaferjs"
20
23
  ],
21
24
  "dependencies": {
22
- "@leafer-ui/core": "1.0.0-beta.8"
25
+ "@leafer/core": "1.0.0-rc.10"
23
26
  },
24
27
  "devDependencies": {
25
- "@leafer/interface": "1.0.0-beta.8",
26
- "@leafer-ui/interface": "1.0.0-beta.8"
28
+ "@leafer/interface": "1.0.0-rc.10",
29
+ "@leafer-ui/interface": "1.0.0-rc.10"
27
30
  }
28
31
  }
package/src/CharLayout.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { ITextCharData, ITextData, ITextDrawData } from '@leafer-ui/interface'
1
+ import { ITextCharData, ITextData, ITextDrawData, ITextRowData } from '@leafer-ui/interface'
2
2
 
3
3
 
4
4
  const CharMode = 0 // data: [{char:'a', x: 0}, {char:'b', x: 5}, {char:'d', x:20}]
5
5
  const WordMode = 1 // data: [{ char:'ab', x: 0}, { char:'d', x:20}]
6
- const RowMode = 2 // text: 'ab c'
6
+ const TextMode = 2 // text: 'ab c'
7
7
 
8
8
  export function layoutChar(drawData: ITextDrawData, style: ITextData, width: number, _height: number): void {
9
9
 
@@ -16,18 +16,13 @@ export function layoutChar(drawData: ITextDrawData, style: ITextData, width: num
16
16
 
17
17
  indentWidth = paraIndent && row.paraStart ? paraIndent : 0
18
18
  addWordWidth = (width && textAlign === 'justify' && row.words.length > 1) ? (width - row.width - indentWidth) / (row.words.length - 1) : 0
19
- mode = (letterSpacing || row.isOverflow) ? CharMode : (addWordWidth > 0.01 ? WordMode : RowMode)
19
+ mode = (letterSpacing || row.isOverflow) ? CharMode : (addWordWidth > 0.01 ? WordMode : TextMode)
20
+ if (row.isOverflow && !letterSpacing) row.textMode = true
20
21
 
21
- if (mode === RowMode) {
22
+ if (mode === TextMode) {
22
23
 
23
- row.text = ''
24
24
  row.x += indentWidth
25
-
26
- row.words.forEach(word => {
27
- word.data.forEach(char => {
28
- row.text += char.char
29
- })
30
- })
25
+ toTextChar(row)
31
26
 
32
27
  } else {
33
28
 
@@ -63,6 +58,15 @@ export function layoutChar(drawData: ITextDrawData, style: ITextData, width: num
63
58
 
64
59
  }
65
60
 
61
+ function toTextChar(row: ITextRowData): void {
62
+ row.text = ''
63
+ row.words.forEach(word => {
64
+ word.data.forEach(char => {
65
+ row.text += char.char
66
+ })
67
+ })
68
+ }
69
+
66
70
  function toWordChar(data: ITextCharData[], charX: number, wordChar: ITextCharData): number {
67
71
  data.forEach(char => {
68
72
  wordChar.char += char.char
package/src/TextClip.ts CHANGED
@@ -1,39 +1,59 @@
1
1
  import { Platform } from '@leafer/core'
2
2
 
3
- import { IOverflow, ITextCharData, ITextDrawData } from '@leafer-ui/interface'
3
+ import { ITextCharData, ITextData, ITextDrawData, ITextRowData } from '@leafer-ui/interface'
4
4
 
5
5
 
6
- export function clipText(drawData: ITextDrawData, textOverflow: IOverflow | string): void {
6
+ export function clipText(drawData: ITextDrawData, style: ITextData): void {
7
7
 
8
8
  const { rows, overflow } = drawData
9
+ let { textOverflow } = style
9
10
  rows.splice(overflow)
10
11
 
12
+
11
13
  if (textOverflow !== 'hide') {
12
14
  if (textOverflow === 'ellipsis') textOverflow = '...'
13
15
 
16
+ let char: ITextCharData, charRight: number
14
17
  const ellipsisWidth = Platform.canvas.measureText(textOverflow).width
15
- const row = rows[overflow - 1]
16
-
17
- let char: ITextCharData, end = row.data.length - 1, charRight: number
18
-
19
- const { x, width } = drawData.bounds
20
- const right = x + width - ellipsisWidth
21
-
22
- for (let i = end; i > -1; i--) {
23
- char = row.data[i]
24
- charRight = char.x + char.width
25
- if (i === end && charRight < right) {
26
- break
27
- } else if (charRight < right && char.char !== ' ') {
28
- row.data.splice(i + 1)
29
- row.width -= char.width
30
- break
18
+ const right = style.x + style.width - ellipsisWidth
19
+ const list = style.textWrap === 'none' ? rows : [rows[overflow - 1]]
20
+
21
+ list.forEach(row => {
22
+
23
+ if (row.isOverflow && row.data) {
24
+
25
+ let end = row.data.length - 1
26
+
27
+ for (let i = end; i > -1; i--) {
28
+ char = row.data[i]
29
+ charRight = char.x + char.width
30
+ if (i === end && charRight < right) {
31
+ break
32
+ } else if (charRight < right && char.char !== ' ') {
33
+ row.data.splice(i + 1)
34
+ row.width -= char.width
35
+ break
36
+ }
37
+ row.width -= char.width
38
+ }
39
+
40
+ row.width += ellipsisWidth
41
+ row.data.push({ char: textOverflow, x: charRight })
42
+
43
+ if (row.textMode) toTextChar(row)
31
44
  }
32
- row.width -= char.width
33
- }
34
45
 
35
- row.width += ellipsisWidth
36
- row.data.push({ char: textOverflow, x: charRight })
46
+
47
+ })
48
+
37
49
  }
38
50
 
51
+ }
52
+
53
+ function toTextChar(row: ITextRowData): void {
54
+ row.text = ''
55
+ row.data.forEach(char => {
56
+ row.text += char.char
57
+ })
58
+ row.data = null
39
59
  }
@@ -1,4 +1,4 @@
1
- import { MathHelper, Platform } from '@leafer/core'
1
+ import { Platform, Direction4 } from '@leafer/core'
2
2
 
3
3
  import { ITextData, ITextDrawData } from '@leafer-ui/interface'
4
4
 
@@ -9,48 +9,79 @@ import { clipText } from './TextClip'
9
9
  import { decorationText } from './TextDecoration'
10
10
 
11
11
 
12
- export const TextConvert = {
12
+ const { top, right, bottom, left } = Direction4
13
13
 
14
- getDrawData(content: string, style: ITextData): ITextDrawData {
14
+ export function getDrawData(content: string, style: ITextData): ITextDrawData {
15
15
 
16
- if (typeof content !== 'string') content = String(content)
16
+ if (typeof content !== 'string') content = String(content)
17
17
 
18
- let x = 0, y = 0
19
- let { width, height, padding } = style
20
- const { textDecoration, textOverflow, __font } = style
21
- if (!width) width = 0
18
+ let x = 0, y = 0
22
19
 
23
- if (padding) {
24
- const [top, right, bottom, left] = MathHelper.fourNumber(padding)
25
- if (width) {
26
- x = left
27
- width -= (right + left)
28
- }
29
- if (height) {
30
- y = top
31
- height -= (top + bottom)
32
- }
33
- }
20
+ let width = style.__getInput('width') || 0
21
+ let height = style.__getInput('height') || 0
22
+
23
+ const { textDecoration, __font, __padding: padding } = style
34
24
 
35
- const drawData: ITextDrawData = {
36
- bounds: { x, y, width, height },
37
- rows: [],
38
- paraNumber: 0,
39
- font: Platform.canvas.font = __font
25
+ if (padding) {
26
+ if (width) {
27
+ x = padding[left]
28
+ width -= (padding[right] + padding[left])
40
29
  }
30
+ if (height) {
31
+ y = padding[top]
32
+ height -= (padding[top] + padding[bottom])
33
+ }
34
+ }
35
+
36
+ const drawData: ITextDrawData = {
37
+ bounds: { x, y, width, height },
38
+ rows: [],
39
+ paraNumber: 0,
40
+ font: Platform.canvas.font = __font
41
+ }
42
+
43
+ createRows(drawData, content, style) // set rows, paraNumber
41
44
 
42
- createRows(drawData, content, style) // set rows, paraNumber
45
+ if (padding) padAutoText(padding, drawData, style, width, height)
43
46
 
44
- layoutText(drawData, style) // set bounds
47
+ layoutText(drawData, style) // set bounds
45
48
 
46
- layoutChar(drawData, style, width, height) // set char.x
49
+ layoutChar(drawData, style, width, height) // set char.x
47
50
 
48
- if (drawData.overflow) clipText(drawData, textOverflow)
51
+ if (drawData.overflow) clipText(drawData, style)
49
52
 
50
- if (textDecoration !== 'none') decorationText(drawData, style)
53
+ if (textDecoration !== 'none') decorationText(drawData, style)
51
54
 
52
- return drawData
55
+ return drawData
53
56
 
57
+ }
58
+
59
+
60
+ function padAutoText(padding: number[], drawData: ITextDrawData, style: ITextData, width: number, height: number): void {
61
+ if (!width) {
62
+ switch (style.textAlign) {
63
+ case 'left':
64
+ offsetText(drawData, 'x', padding[left])
65
+ break
66
+ case 'right':
67
+ offsetText(drawData, 'x', -padding[right])
68
+ }
54
69
  }
55
70
 
71
+ if (!height) {
72
+ switch (style.verticalAlign) {
73
+ case 'top':
74
+ offsetText(drawData, 'y', padding[top])
75
+ break
76
+ case 'bottom':
77
+ offsetText(drawData, 'y', -padding[bottom])
78
+ }
79
+ }
80
+ }
81
+
82
+
83
+ function offsetText(drawData: ITextDrawData, attrName: 'x' | 'y', value: number): void {
84
+ const { bounds, rows } = drawData
85
+ bounds[attrName] += value
86
+ for (let i = 0; i < rows.length; i++) rows[i][attrName] += value
56
87
  }
package/src/TextLayout.ts CHANGED
@@ -4,32 +4,30 @@ import { ITextData, ITextDrawData, ITextRowData } from '@leafer-ui/interface'
4
4
  export function layoutText(drawData: ITextDrawData, style: ITextData): void {
5
5
 
6
6
  const { rows, bounds } = drawData
7
- const { __lineHeight, __baseLine, textAlign, verticalAlign, paraSpacing, textOverflow } = style
7
+ const { __lineHeight, __baseLine, __letterSpacing, __clipText, textAlign, verticalAlign, paraSpacing } = style
8
8
 
9
9
  let { x, y, width, height } = bounds, realHeight = __lineHeight * rows.length + (paraSpacing ? paraSpacing * (drawData.paraNumber - 1) : 0)
10
10
  let starY: number = __baseLine
11
11
 
12
12
  // verticalAlign
13
13
 
14
- if (height) {
15
- if (textOverflow !== 'show' && realHeight > height) {
16
- realHeight = Math.max(height, __lineHeight)
17
- drawData.overflow = rows.length
18
- } else {
19
- switch (verticalAlign) {
20
- case 'middle':
21
- y += (height - realHeight) / 2
22
- break
23
- case 'bottom':
24
- y += (height - realHeight)
25
- }
14
+ if (__clipText && realHeight > height) {
15
+ realHeight = Math.max(height, __lineHeight)
16
+ drawData.overflow = rows.length
17
+ } else {
18
+ switch (verticalAlign) {
19
+ case 'middle':
20
+ y += (height - realHeight) / 2
21
+ break
22
+ case 'bottom':
23
+ y += (height - realHeight)
26
24
  }
27
- starY += y
28
25
  }
26
+ starY += y
29
27
 
30
28
  // textAlign
31
29
 
32
- let row: ITextRowData
30
+ let row: ITextRowData, rowX: number, rowWidth: number
33
31
 
34
32
  for (let i = 0, len = rows.length; i < len; i++) {
35
33
  row = rows[i]
@@ -54,7 +52,27 @@ export function layoutText(drawData: ITextDrawData, style: ITextData): void {
54
52
  drawData.overflow = i + 1
55
53
  }
56
54
 
57
- if (row.width > bounds.width) bounds.width = row.width
55
+ rowX = row.x
56
+ rowWidth = row.width
57
+
58
+ if (__letterSpacing < 0) { // letterSpacing < 0, like -20% -100%
59
+ if (row.width < 0) {
60
+ rowWidth = -row.width + style.fontSize + __letterSpacing
61
+ rowX -= rowWidth
62
+ rowWidth += style.fontSize
63
+ } else {
64
+ rowWidth -= __letterSpacing
65
+ }
66
+ }
67
+
68
+ if (rowX < bounds.x) bounds.x = rowX
69
+ if (rowWidth > bounds.width) bounds.width = rowWidth
70
+
71
+ // clip nowrap
72
+ if (__clipText && width && width < rowWidth) {
73
+ row.isOverflow = true
74
+ if (!drawData.overflow) drawData.overflow = rows.length
75
+ }
58
76
  }
59
77
 
60
78
  bounds.y = y
package/src/TextRows.ts CHANGED
@@ -11,7 +11,7 @@ const { trimRight } = TextRowHelper
11
11
  const { Letter, Single, Before, After, Symbol, Break } = CharType
12
12
 
13
13
  let word: ITextWordData, row: ITextRowData, wordWidth: number, rowWidth: number, realWidth: number
14
- let char: string, charWidth: number, charType: CharType, lastCharType: CharType, langBreak: boolean, afterBreak: boolean, paraStart: boolean
14
+ let char: string, charWidth: number, startCharSize: number, charSize: number, charType: CharType, lastCharType: CharType, langBreak: boolean, afterBreak: boolean, paraStart: boolean
15
15
  let textDrawData: ITextDrawData, rows: ITextRowData[] = [], bounds: IBoundsData
16
16
 
17
17
  export function createRows(drawData: ITextDrawData, content: string, style: ITextData): void {
@@ -27,9 +27,12 @@ export function createRows(drawData: ITextDrawData, content: string, style: ITex
27
27
 
28
28
  if (charMode) {
29
29
 
30
+ const wrap = style.textWrap !== 'none'
31
+ const breakAll = style.textWrap === 'break'
32
+
30
33
  paraStart = true
31
34
  lastCharType = null
32
- wordWidth = rowWidth = 0
35
+ startCharSize = charWidth = charSize = wordWidth = rowWidth = 0
33
36
  word = { data: [] }, row = { words: [] }
34
37
 
35
38
  for (let i = 0, len = content.length; i < len; i++) {
@@ -51,30 +54,44 @@ export function createRows(drawData: ITextDrawData, content: string, style: ITex
51
54
  if (charType === Letter && textCase !== 'none') char = getTextCase(char, textCase, !wordWidth)
52
55
 
53
56
  charWidth = canvas.measureText(char).width
54
- if (__letterSpacing) charWidth += __letterSpacing
57
+ if (__letterSpacing) {
58
+ if (__letterSpacing < 0) charSize = charWidth
59
+ charWidth += __letterSpacing
60
+ }
55
61
 
56
62
  langBreak = (charType === Single && (lastCharType === Single || lastCharType === Letter)) || (lastCharType === Single && charType !== After) // break U字 文字 or 字U 字( 字* exclude 字。
57
63
  afterBreak = ((charType === Before || charType === Single) && (lastCharType === Symbol || lastCharType === After)) // split >( =文 。哈 ;文
58
64
 
59
65
  realWidth = paraStart && paraIndent ? width - paraIndent : width
60
66
 
61
- if (width && rowWidth + wordWidth + charWidth > realWidth) { // wrap
62
-
63
- if (!afterBreak) afterBreak = charType === Letter && lastCharType == After // split ,S
67
+ if (wrap && (width && rowWidth + wordWidth + charWidth > realWidth)) { // wrap
64
68
 
65
- if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
69
+ if (breakAll) {
66
70
 
67
71
  if (wordWidth) addWord() // break
68
72
  addRow()
69
73
 
70
74
  } else {
75
+ if (!afterBreak) afterBreak = charType === Letter && lastCharType == After // split ,S
71
76
 
72
- addRow()
77
+ if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
78
+
79
+ if (wordWidth) addWord() // break
80
+ addRow()
81
+
82
+ } else {
83
+
84
+ addRow()
85
+ }
73
86
  }
74
87
 
75
88
  }
76
89
 
77
- if (!(char === ' ' && (rowWidth + wordWidth) === 0)) {
90
+ if (char === ' ' && paraStart !== true && (rowWidth + wordWidth) === 0) {
91
+
92
+ // trim space
93
+
94
+ } else {
78
95
 
79
96
  if (charType === Break) {
80
97
 
@@ -117,6 +134,7 @@ export function createRows(drawData: ITextDrawData, content: string, style: ITex
117
134
 
118
135
 
119
136
  function addChar(char: string, width: number): void {
137
+ if (charSize && !startCharSize) startCharSize = charSize
120
138
  word.data.push({ char, width })
121
139
  wordWidth += width
122
140
  }
@@ -135,6 +153,13 @@ function addRow(): void {
135
153
  row.paraStart = true
136
154
  paraStart = false
137
155
  }
156
+
157
+ if (charSize) { // letterSpacing < 0, like -20% -100%
158
+ row.startCharSize = startCharSize
159
+ row.endCharSize = charSize
160
+ startCharSize = 0
161
+ }
162
+
138
163
  row.width = rowWidth
139
164
  if (bounds.width) trimRight(row)
140
165
  rows.push(row)
package/src/index.ts CHANGED
@@ -1 +1,7 @@
1
- export { TextConvert } from './TextConvert'
1
+ import { ITextConvertModule } from '@leafer-ui/interface'
2
+
3
+ import { getDrawData } from './TextConvert'
4
+
5
+ export const TextConvertModule: ITextConvertModule = {
6
+ getDrawData
7
+ }
@@ -0,0 +1,5 @@
1
+ import { ITextConvertModule } from '@leafer-ui/interface';
2
+
3
+ declare const TextConvertModule: ITextConvertModule;
4
+
5
+ export { TextConvertModule };