@fulate/ui 1.0.2 → 1.0.5
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/README.md +51 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.js +43 -29
- package/dist/text/block.d.ts +12 -4
- package/dist/text/index.d.ts +2 -2
- package/dist/text/layout.d.ts +7 -1
- package/dist/text/paint.d.ts +8 -2
- package/dist/text/style.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -163,6 +163,57 @@ const metrics = measureTextRun(ctx, text, root.skin.text, 14, 500);
|
|
|
163
163
|
测量所需的文字状态写入 `ctx`,不会调用 `save()` 或 `restore()`;Canvas 生命周期以及业务特有的
|
|
164
164
|
文字顺序、对齐和绘制仍由 Shape 自己拥有。
|
|
165
165
|
|
|
166
|
+
### 组合型多行文本
|
|
167
|
+
|
|
168
|
+
需要在一个非 `Text` Element 中放置可换行文字时,使用公开的 `TextBlock` 组合原语。它与 `Text`
|
|
169
|
+
共用同一份 hard-break、grapheme、`wordWrap`、`maxLines` 和 `ellipsis` 排版实现:
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
import {
|
|
173
|
+
TextBlock,
|
|
174
|
+
getTextBlockVisualBounds,
|
|
175
|
+
paintTextBlock,
|
|
176
|
+
resolveTextStyle
|
|
177
|
+
} from "@fulate/ui";
|
|
178
|
+
|
|
179
|
+
const style = resolveTextStyle(
|
|
180
|
+
{
|
|
181
|
+
fontSize: 14,
|
|
182
|
+
fontWeight: 500,
|
|
183
|
+
textAlign: "left",
|
|
184
|
+
textBaseline: "top",
|
|
185
|
+
verticalAlign: "top",
|
|
186
|
+
wordWrap: true
|
|
187
|
+
},
|
|
188
|
+
root.skin.text
|
|
189
|
+
);
|
|
190
|
+
const block = new TextBlock();
|
|
191
|
+
const snapshot = block.sync({
|
|
192
|
+
text,
|
|
193
|
+
style,
|
|
194
|
+
width: 120,
|
|
195
|
+
height: 80,
|
|
196
|
+
overflow: "visible",
|
|
197
|
+
wordWrap: true,
|
|
198
|
+
ellipsis: false
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
paintTextBlock(ctx, snapshot, style, 120, 80);
|
|
202
|
+
const visualBounds = getTextBlockVisualBounds(snapshot, style, 120, 80);
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`measure()` 只返回紧凑的聚合 metrics;最终宽高确定后调用一次 `sync()`,并把同一个 snapshot
|
|
206
|
+
同时交给 `paintTextBlock()` 和 `getTextBlockVisualBounds()`。`paintTextBlock()` 不会替调用者
|
|
207
|
+
`save()`/`restore()`、安装 clip 或决定坐标变换;组合 owner 自己负责 Canvas 生命周期、裁剪和把
|
|
208
|
+
视觉 bounds 接入自己的 transform/dirty-rect 计算。`overflow: "visible"` 不会自动把文字裁掉,
|
|
209
|
+
也不会自动改变 owner 的 authored 宽高;使用 `overflow: "hidden"` 时,真正的 Canvas clip 仍由
|
|
210
|
+
组合 owner 安装。
|
|
211
|
+
|
|
212
|
+
`TextBlock` 不属于任何 `Element`、`Root`、History 或 frame runtime。组合 owner 负责保存 block、
|
|
213
|
+
在输入或 Skin 变化时调用 `invalidate()`,并在需要响应浏览器字体加载完成时订阅
|
|
214
|
+
`subscribeTextMeasurementChanges()`;返回的函数用于解除订阅。不要绕过 `@fulate/ui` 根入口导入
|
|
215
|
+
`TextBlock` 的内部实现,也不要为同一段文字另建一套换行或测量器。
|
|
216
|
+
|
|
166
217
|
## Editor capabilities
|
|
167
218
|
|
|
168
219
|
UI 元素通过对象 identity token 直接提供 Selection、Transform、Snap、Point 与 Content capability;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
export { measureTextWidth, fitTextWithEllipsis } from "./text/layout";
|
|
1
|
+
export { measureTextWidth, fitTextWithEllipsis, subscribeTextMeasurementChanges } from "./text/layout";
|
|
2
|
+
export type { TextLayoutLine, TextLayoutMetrics, TextLayoutOptions, TextLayoutSnapshot } from "./text/layout";
|
|
2
3
|
export { measureTextRun } from "./text/paint";
|
|
4
|
+
export { paintTextBlock } from "./text/paint";
|
|
3
5
|
export type { TextLineBoxMetrics, TextRunMetrics } from "./text/paint";
|
|
6
|
+
export { TextBlock, getTextBlockVisualBounds } from "./text/block";
|
|
7
|
+
export type { TextBlockLayoutInput } from "./text/block";
|
|
4
8
|
export { Rectangle, RectangleProperties, RectangleTransform } from "./rectangle";
|
|
5
9
|
export type { RectangleOption, RectangleOptionPatch } from "./rectangle";
|
|
6
10
|
export { Circle, CircleTransform } from "./circle";
|
|
@@ -9,8 +13,8 @@ export { Polygon, PolygonTransform } from "./polygon";
|
|
|
9
13
|
export type { PolygonOption } from "./polygon";
|
|
10
14
|
export { VectorPath, VectorPathProperties, VectorPathTransform } from "./vector-path";
|
|
11
15
|
export type { VectorPathCommand, VectorPathGeometry, VectorPathOption } from "./vector-path";
|
|
12
|
-
export { Text, TextProperties, TextTransform } from "./text";
|
|
13
|
-
export type { TextOption } from "./text";
|
|
16
|
+
export { Text, TextProperties, TextTransform, resolveTextStyle } from "./text";
|
|
17
|
+
export type { TextOption, TextStyleConfig, TextStyleKey, ResolvedTextStyle } from "./text";
|
|
14
18
|
export { Image, ImageProperties, ImageTransform } from "./image";
|
|
15
19
|
export type { ImageOption, ImageResizeOption, ImageResizeMode } from "./image";
|
|
16
20
|
export { Bitmap } from "./bitmap";
|
package/dist/index.js
CHANGED
|
@@ -12,13 +12,21 @@ function invalidateFontMeasurements() {
|
|
|
12
12
|
clearCache();
|
|
13
13
|
for (const listener of measurementListeners) listener();
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Subscribe a non-Text owner to browser font measurement completion.
|
|
17
|
+
*
|
|
18
|
+
* TextBlock has no Root lifecycle of its own, so composite owners use this
|
|
19
|
+
* hook to invalidate their block and publish the resulting visual change.
|
|
20
|
+
*/
|
|
15
21
|
function subscribeTextMeasurementChanges(listener) {
|
|
16
22
|
if (!observesFontLoading && document.fonts) {
|
|
17
23
|
observesFontLoading = true;
|
|
18
24
|
document.fonts.addEventListener("loadingdone", invalidateFontMeasurements);
|
|
19
25
|
}
|
|
20
26
|
measurementListeners.add(listener);
|
|
21
|
-
return () =>
|
|
27
|
+
return () => {
|
|
28
|
+
measurementListeners.delete(listener);
|
|
29
|
+
};
|
|
22
30
|
}
|
|
23
31
|
function normalizeText(text) {
|
|
24
32
|
return text.replace(/\r\n/g, "\n").replace(/[\r\f]/g, "\n");
|
|
@@ -749,7 +757,7 @@ var TEXT_STYLE_KEYS = Object.keys(TEXT_STYLE_DEFAULTS);
|
|
|
749
757
|
function buildFontString(style, fontSize = style.fontSize, fontWeight = style.fontWeight) {
|
|
750
758
|
return `${style.fontStyle} ${fontWeight} ${fontSize}px ${style.fontFamily}`;
|
|
751
759
|
}
|
|
752
|
-
function resolveTextStyle(instance, defaults) {
|
|
760
|
+
function resolveTextStyle(instance, defaults = TEXT_STYLE_DEFAULTS) {
|
|
753
761
|
const resolved = {};
|
|
754
762
|
for (const key of TEXT_STYLE_KEYS) {
|
|
755
763
|
const authored = instance[key];
|
|
@@ -841,7 +849,13 @@ function measureTextLineBoxMetrics(text, style) {
|
|
|
841
849
|
height: lineHeight
|
|
842
850
|
};
|
|
843
851
|
}
|
|
844
|
-
/**
|
|
852
|
+
/**
|
|
853
|
+
* Paint a previously synchronized text block.
|
|
854
|
+
*
|
|
855
|
+
* The painter deliberately does not call `save()`/`restore()` or install a
|
|
856
|
+
* clip. The owner chooses the transform and clipping policy, then uses the
|
|
857
|
+
* same snapshot for `getTextBlockVisualBounds`.
|
|
858
|
+
*/
|
|
845
859
|
function paintTextBlock(ctx, layout, style, width, height) {
|
|
846
860
|
if (layout.lines.length === 0) return;
|
|
847
861
|
const font = buildFontString(style);
|
|
@@ -952,17 +966,18 @@ function paintTextContent(self, ctx, offsetY = 0) {
|
|
|
952
966
|
ctx.restore();
|
|
953
967
|
}
|
|
954
968
|
//#endregion
|
|
955
|
-
//#region packages/ui/src/paint/circle.ts
|
|
956
|
-
/** 在当前 Canvas path 中加入圆形;不创建场景或 Geometry 对象。 */
|
|
957
|
-
function traceCirclePath(ctx, center, radius) {
|
|
958
|
-
ctx.arc(center.x, center.y, radius, 0, Math.PI * 2);
|
|
959
|
-
}
|
|
960
|
-
//#endregion
|
|
961
969
|
//#region packages/ui/src/text/block.ts
|
|
962
970
|
function sameLayoutKey(left, right) {
|
|
963
971
|
return left !== null && left.text === right.text && left.font === right.font && left.letterSpacing === right.letterSpacing && left.width === right.width && left.height === right.height && left.lineHeight === right.lineHeight && left.wordWrap === right.wordWrap && left.maxLines === right.maxLines && left.overflow === right.overflow && left.ellipsis === right.ellipsis;
|
|
964
972
|
}
|
|
965
|
-
/**
|
|
973
|
+
/**
|
|
974
|
+
* The canonical layout owner for a non-Element text block.
|
|
975
|
+
*
|
|
976
|
+
* A block owns prepared text and the latest final snapshot only; it does not
|
|
977
|
+
* own an Element, Root, transform, clip, dirty rectangle, or History entry.
|
|
978
|
+
* Composite owners should call `measure()` for aggregate metrics, then call
|
|
979
|
+
* `sync()` with the final width/height before painting or computing bounds.
|
|
980
|
+
*/
|
|
966
981
|
var TextBlock = class {
|
|
967
982
|
prepared = null;
|
|
968
983
|
metrics = null;
|
|
@@ -1023,7 +1038,7 @@ var TextBlock = class {
|
|
|
1023
1038
|
};
|
|
1024
1039
|
}
|
|
1025
1040
|
};
|
|
1026
|
-
/**
|
|
1041
|
+
/** Return visual bounds for the same snapshot consumed by `paintTextBlock`. */
|
|
1027
1042
|
function getTextBlockVisualBounds(layout, style, width, height) {
|
|
1028
1043
|
if (layout.lines.length === 0) return null;
|
|
1029
1044
|
let left = Infinity;
|
|
@@ -1059,6 +1074,12 @@ function getTextBlockVisualBounds(layout, style, width, height) {
|
|
|
1059
1074
|
};
|
|
1060
1075
|
}
|
|
1061
1076
|
//#endregion
|
|
1077
|
+
//#region packages/ui/src/paint/circle.ts
|
|
1078
|
+
/** 在当前 Canvas path 中加入圆形;不创建场景或 Geometry 对象。 */
|
|
1079
|
+
function traceCirclePath(ctx, center, radius) {
|
|
1080
|
+
ctx.arc(center.x, center.y, radius, 0, Math.PI * 2);
|
|
1081
|
+
}
|
|
1082
|
+
//#endregion
|
|
1062
1083
|
//#region packages/ui/src/connection-port-decoration.ts
|
|
1063
1084
|
var DOT_RADIUS = 4;
|
|
1064
1085
|
var LABEL_GAP = 3;
|
|
@@ -1165,16 +1186,15 @@ var ConnectionPortDecoration = class {
|
|
|
1165
1186
|
const { slot, block } = entry;
|
|
1166
1187
|
if (!block) return null;
|
|
1167
1188
|
const definition = slot.definition;
|
|
1168
|
-
const edgePosition = this.host.getEdgePosition(slot.edge, slot.ratio);
|
|
1169
1189
|
const position = slot.localPosition;
|
|
1170
|
-
const
|
|
1171
|
-
const slotSpan =
|
|
1190
|
+
const { nx, ny, edgeLength } = slot.geometry;
|
|
1191
|
+
const slotSpan = edgeLength / (slot.edgeCount + 1);
|
|
1172
1192
|
const horizontalEdge = slot.edge === "top" || slot.edge === "bottom";
|
|
1173
1193
|
const width = horizontalEdge ? Math.max(0, Math.min(definition.labelWidth ?? DEFAULT_LABEL_WIDTH, slotSpan - LABEL_GAP * 2)) : Math.max(0, definition.labelWidth ?? DEFAULT_LABEL_WIDTH);
|
|
1174
1194
|
if (width === 0) return null;
|
|
1175
1195
|
const localAlign = slot.edge === "left" ? "right" : slot.edge === "right" ? "left" : "center";
|
|
1176
1196
|
const upright = definition.keepLabelUpright !== false;
|
|
1177
|
-
const worldNormal = upright ? transformVector(this.host.transform.getWorldMatrixView(),
|
|
1197
|
+
const worldNormal = upright ? transformVector(this.host.transform.getWorldMatrixView(), nx, ny) : null;
|
|
1178
1198
|
const align = worldNormal ? Math.abs(worldNormal.x) >= Math.abs(worldNormal.y) ? worldNormal.x >= 0 ? "left" : "right" : "center" : localAlign;
|
|
1179
1199
|
const style = this.getStyle(entry, align);
|
|
1180
1200
|
const lineHeight = style.fontSize * style.lineHeight;
|
|
@@ -1215,7 +1235,7 @@ var ConnectionPortDecoration = class {
|
|
|
1215
1235
|
width,
|
|
1216
1236
|
height
|
|
1217
1237
|
};
|
|
1218
|
-
const uprightMatrix = upright ? this.buildUprightMatrix(position,
|
|
1238
|
+
const uprightMatrix = upright ? this.buildUprightMatrix(position, nx, ny, width, height) : null;
|
|
1219
1239
|
if (upright && !uprightMatrix) return null;
|
|
1220
1240
|
return {
|
|
1221
1241
|
entry,
|
|
@@ -1246,7 +1266,7 @@ var ConnectionPortDecoration = class {
|
|
|
1246
1266
|
}
|
|
1247
1267
|
buildUprightMatrix(position, nx, ny, width, height) {
|
|
1248
1268
|
const matrix = this.host.transform.getWorldMatrixView();
|
|
1249
|
-
const worldPosition = transformPoint
|
|
1269
|
+
const worldPosition = transformPoint(matrix, position);
|
|
1250
1270
|
const normal = transformVector(matrix, nx, ny);
|
|
1251
1271
|
const normalLength = Math.hypot(normal.x, normal.y);
|
|
1252
1272
|
const scaleX = Math.hypot(matrix.a, matrix.b);
|
|
@@ -1281,12 +1301,6 @@ var ConnectionPortDecoration = class {
|
|
|
1281
1301
|
}
|
|
1282
1302
|
}
|
|
1283
1303
|
};
|
|
1284
|
-
function transformPoint$1(matrix, point) {
|
|
1285
|
-
return {
|
|
1286
|
-
x: matrix.a * point.x + matrix.c * point.y + matrix.e,
|
|
1287
|
-
y: matrix.b * point.x + matrix.d * point.y + matrix.f
|
|
1288
|
-
};
|
|
1289
|
-
}
|
|
1290
1304
|
function transformVector(matrix, x, y) {
|
|
1291
1305
|
return {
|
|
1292
1306
|
x: matrix.a * x + matrix.c * y,
|
|
@@ -1297,19 +1311,19 @@ function projectRect(matrix, rect) {
|
|
|
1297
1311
|
const right = rect.left + rect.width;
|
|
1298
1312
|
const bottom = rect.top + rect.height;
|
|
1299
1313
|
return Bound.fromPoints([
|
|
1300
|
-
transformPoint
|
|
1314
|
+
transformPoint(matrix, {
|
|
1301
1315
|
x: rect.left,
|
|
1302
1316
|
y: rect.top
|
|
1303
1317
|
}),
|
|
1304
|
-
transformPoint
|
|
1318
|
+
transformPoint(matrix, {
|
|
1305
1319
|
x: right,
|
|
1306
1320
|
y: rect.top
|
|
1307
1321
|
}),
|
|
1308
|
-
transformPoint
|
|
1322
|
+
transformPoint(matrix, {
|
|
1309
1323
|
x: right,
|
|
1310
1324
|
y: bottom
|
|
1311
1325
|
}),
|
|
1312
|
-
transformPoint
|
|
1326
|
+
transformPoint(matrix, {
|
|
1313
1327
|
x: rect.left,
|
|
1314
1328
|
y: bottom
|
|
1315
1329
|
})
|
|
@@ -2916,7 +2930,7 @@ var TextTransform = class extends RectangleTransform {
|
|
|
2916
2930
|
}
|
|
2917
2931
|
buildVisualOutline(snapshot) {
|
|
2918
2932
|
if (this.element.overflow !== "visible") return super.buildVisualOutline(snapshot);
|
|
2919
|
-
const bounds = this.
|
|
2933
|
+
const bounds = this.getLocalVisualBoundsView();
|
|
2920
2934
|
if (!bounds) return [];
|
|
2921
2935
|
return [
|
|
2922
2936
|
createPointView(bounds.left, bounds.top),
|
|
@@ -5953,4 +5967,4 @@ function applyLineTreeTopologyDelta(topology, delta, direction) {
|
|
|
5953
5967
|
};
|
|
5954
5968
|
}
|
|
5955
5969
|
//#endregion
|
|
5956
|
-
export { BaseLine, Bitmap, Circle, CircleTransform, ContentEditingCapabilityToken, DEFAULT_LINE_TREE_BRANCH_STYLE, EMPTY_LINE_TREE_TOPOLOGY, EditorFrameFlush, EndpointRelationIndex, Group, GroupTransform, Image, ImageProperties, ImageTransform, Line, LineTransform, LineTree, LineTreeProperties, LineTreeTransform, PointEditingCapabilityToken, Polygon, PolygonTransform, Rectangle, RectangleProperties, RectangleTransform, RippleOverlay, ScrollView, ScrollViewTransform, SelectionBehaviorCapabilityToken, SelectionBehaviorMode, SelectionDiveMode, SelectionSnapMode, SnapSourceCapabilityToken, Text, TextProperties, TextTransform, TransformInteractionCapabilityToken, Triangle, TriangleTransform, VectorPath, VectorPathProperties, VectorPathTransform, WorkerSurfacePool, Workspace, WorkspaceProperties, addLineTreeBranchAtTail, applyLineTreeTopologyDelta, arrow, autoPlacement, computePosition, connectEndpoint, connectionPortAccepts, createFloatingPlatform, createLineTreeTopology, createLineTreeTopologyDelta, defineEditorCapability, detectOverflow, disconnectEndpoint, fitTextWithEllipsis, fitWorkspace, flip, getEditorCapability, getEditorFrameFlush, getEndpointRelationIndex, getLineTreeBindableEndpoints, getLineTreeBranch, getLineTreeEndpointRelationBindings, getLineTreeJunctionAnchorIds, getLineTreePoint, getLineTreePointReferenceCounts, hasConnectionPortCapacity, hide, insertLineTreePoint, isEditorCapabilityHost, isEndpointRelationSource, limitShift, measureTextRun, measureTextWidth, moveLineTreePoint, offset, remapLineTreeRelations, removeLineTreeBranch, removeLineTreePoint, resolveConnectEndpointChange, resolveConnectionPortChanges, resolveDisconnectEndpointChanges, scaleLineTreeTopology, shift, size, updateLineTreeBranchStyle, workspaceFocusInsetsKey };
|
|
5970
|
+
export { BaseLine, Bitmap, Circle, CircleTransform, ContentEditingCapabilityToken, DEFAULT_LINE_TREE_BRANCH_STYLE, EMPTY_LINE_TREE_TOPOLOGY, EditorFrameFlush, EndpointRelationIndex, Group, GroupTransform, Image, ImageProperties, ImageTransform, Line, LineTransform, LineTree, LineTreeProperties, LineTreeTransform, PointEditingCapabilityToken, Polygon, PolygonTransform, Rectangle, RectangleProperties, RectangleTransform, RippleOverlay, ScrollView, ScrollViewTransform, SelectionBehaviorCapabilityToken, SelectionBehaviorMode, SelectionDiveMode, SelectionSnapMode, SnapSourceCapabilityToken, Text, TextBlock, TextProperties, TextTransform, TransformInteractionCapabilityToken, Triangle, TriangleTransform, VectorPath, VectorPathProperties, VectorPathTransform, WorkerSurfacePool, Workspace, WorkspaceProperties, addLineTreeBranchAtTail, applyLineTreeTopologyDelta, arrow, autoPlacement, computePosition, connectEndpoint, connectionPortAccepts, createFloatingPlatform, createLineTreeTopology, createLineTreeTopologyDelta, defineEditorCapability, detectOverflow, disconnectEndpoint, fitTextWithEllipsis, fitWorkspace, flip, getEditorCapability, getEditorFrameFlush, getEndpointRelationIndex, getLineTreeBindableEndpoints, getLineTreeBranch, getLineTreeEndpointRelationBindings, getLineTreeJunctionAnchorIds, getLineTreePoint, getLineTreePointReferenceCounts, getTextBlockVisualBounds, hasConnectionPortCapacity, hide, insertLineTreePoint, isEditorCapabilityHost, isEndpointRelationSource, limitShift, measureTextRun, measureTextWidth, moveLineTreePoint, offset, paintTextBlock, remapLineTreeRelations, removeLineTreeBranch, removeLineTreePoint, resolveConnectEndpointChange, resolveConnectionPortChanges, resolveDisconnectEndpointChanges, resolveTextStyle, scaleLineTreeTopology, shift, size, subscribeTextMeasurementChanges, updateLineTreeBranchStyle, workspaceFocusInsetsKey };
|
package/dist/text/block.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { Rect } from "@fulate/share";
|
|
2
2
|
import { TextLayoutSnapshot, type TextLayoutMetrics } from "./layout";
|
|
3
3
|
import { type ResolvedTextStyle } from "./style";
|
|
4
|
+
/** Input for one composite text layout owner. */
|
|
4
5
|
export interface TextBlockLayoutInput {
|
|
5
6
|
readonly text: string;
|
|
6
|
-
readonly style: ResolvedTextStyle
|
|
7
|
+
readonly style: Readonly<ResolvedTextStyle>;
|
|
7
8
|
readonly width?: number;
|
|
8
9
|
readonly height?: number;
|
|
9
10
|
readonly overflow: "hidden" | "visible";
|
|
@@ -11,7 +12,14 @@ export interface TextBlockLayoutInput {
|
|
|
11
12
|
readonly maxLines?: number;
|
|
12
13
|
readonly ellipsis?: boolean;
|
|
13
14
|
}
|
|
14
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* The canonical layout owner for a non-Element text block.
|
|
17
|
+
*
|
|
18
|
+
* A block owns prepared text and the latest final snapshot only; it does not
|
|
19
|
+
* own an Element, Root, transform, clip, dirty rectangle, or History entry.
|
|
20
|
+
* Composite owners should call `measure()` for aggregate metrics, then call
|
|
21
|
+
* `sync()` with the final width/height before painting or computing bounds.
|
|
22
|
+
*/
|
|
15
23
|
export declare class TextBlock {
|
|
16
24
|
private prepared;
|
|
17
25
|
private metrics;
|
|
@@ -27,5 +35,5 @@ export declare class TextBlock {
|
|
|
27
35
|
private getPrepared;
|
|
28
36
|
private getLayoutKey;
|
|
29
37
|
}
|
|
30
|
-
/**
|
|
31
|
-
export declare function getTextBlockVisualBounds(layout: TextLayoutSnapshot, style: ResolvedTextStyle
|
|
38
|
+
/** Return visual bounds for the same snapshot consumed by `paintTextBlock`. */
|
|
39
|
+
export declare function getTextBlockVisualBounds(layout: TextLayoutSnapshot, style: Readonly<ResolvedTextStyle>, width: number, height: number): Rect | null;
|
package/dist/text/index.d.ts
CHANGED
|
@@ -2,10 +2,10 @@ import { ChangeImpact, type ElementTransformClass, type GeometrySnapshot, type L
|
|
|
2
2
|
import { Rectangle, RectangleProperties, RectangleTransform, type RectangleOption } from "../rectangle";
|
|
3
3
|
import { type BackgroundColor, type PointView, type Rect } from "@fulate/share";
|
|
4
4
|
import { type TextLineBoxMetrics } from "./paint";
|
|
5
|
-
import { TEXT_STYLE_DEFAULTS, type TextStyleKey, type TextStyleConfig, type ResolvedTextStyle, buildFontString } from "./style";
|
|
5
|
+
import { TEXT_STYLE_DEFAULTS, type TextStyleKey, type TextStyleConfig, type ResolvedTextStyle, buildFontString, resolveTextStyle } from "./style";
|
|
6
6
|
import { type ContentEditingConsumer, type ContentEditingSession, type EditorCapabilityToken } from "../editor/capability";
|
|
7
7
|
export type { TextStyleConfig, TextStyleKey, ResolvedTextStyle };
|
|
8
|
-
export { buildFontString, TEXT_STYLE_DEFAULTS };
|
|
8
|
+
export { buildFontString, resolveTextStyle, TEXT_STYLE_DEFAULTS };
|
|
9
9
|
export { measureTextRun } from "./paint";
|
|
10
10
|
export type { TextLineBoxMetrics, TextRunMetrics } from "./paint";
|
|
11
11
|
/**
|
package/dist/text/layout.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { type LayoutLine } from "@chenglou/pretext";
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Subscribe a non-Text owner to browser font measurement completion.
|
|
4
|
+
*
|
|
5
|
+
* TextBlock has no Root lifecycle of its own, so composite owners use this
|
|
6
|
+
* hook to invalidate their block and publish the resulting visual change.
|
|
7
|
+
*/
|
|
8
|
+
export declare function subscribeTextMeasurementChanges(listener: () => void): () => void;
|
|
3
9
|
export interface TextLayoutLine {
|
|
4
10
|
readonly text: string;
|
|
5
11
|
readonly width: number;
|
package/dist/text/paint.d.ts
CHANGED
|
@@ -54,6 +54,12 @@ export interface TextLineBoxMetrics {
|
|
|
54
54
|
}
|
|
55
55
|
/** Measure the line box produced by the existing Text painter. */
|
|
56
56
|
export declare function measureTextLineBoxMetrics(text: string, style: ResolvedTextStyle): TextLineBoxMetrics;
|
|
57
|
-
/**
|
|
58
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Paint a previously synchronized text block.
|
|
59
|
+
*
|
|
60
|
+
* The painter deliberately does not call `save()`/`restore()` or install a
|
|
61
|
+
* clip. The owner chooses the transform and clipping policy, then uses the
|
|
62
|
+
* same snapshot for `getTextBlockVisualBounds`.
|
|
63
|
+
*/
|
|
64
|
+
export declare function paintTextBlock(ctx: CanvasRenderingContext2D, layout: TextLayoutSnapshot, style: Readonly<ResolvedTextStyle>, width: number, height: number): void;
|
|
59
65
|
export declare function paintTextContent(self: Text, ctx: CanvasRenderingContext2D, offsetY?: number): void;
|
package/dist/text/style.d.ts
CHANGED
|
@@ -10,4 +10,4 @@ export declare function buildFontString(style: {
|
|
|
10
10
|
fontSize?: number;
|
|
11
11
|
fontFamily?: string;
|
|
12
12
|
}, fontSize?: number, fontWeight?: string | number): string;
|
|
13
|
-
export declare function resolveTextStyle(instance:
|
|
13
|
+
export declare function resolveTextStyle(instance: Partial<TextStyleConfig>, defaults?: Readonly<Required<TextStyleConfig>>): ResolvedTextStyle;
|