chat-layout 1.0.0-2 → 1.0.0-4
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 +64 -203
- package/example/build.ts +12 -0
- package/example/chat.ts +403 -0
- package/example/test.ts +215 -0
- package/index.d.mts +240 -1
- package/index.mjs +141 -0
- package/index.mjs.map +1 -1
- package/package.json +1 -1
package/example/test.ts
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DebugRenderer,
|
|
3
|
+
Flex,
|
|
4
|
+
MultilineText,
|
|
5
|
+
PaddingBox,
|
|
6
|
+
Place,
|
|
7
|
+
Text,
|
|
8
|
+
Wrapper,
|
|
9
|
+
type Context,
|
|
10
|
+
type DynValue,
|
|
11
|
+
type HitTest,
|
|
12
|
+
type Node,
|
|
13
|
+
} from "chat-layout";
|
|
14
|
+
|
|
15
|
+
type C = CanvasRenderingContext2D;
|
|
16
|
+
|
|
17
|
+
class RoundedBox extends PaddingBox<C> {
|
|
18
|
+
readonly radii: number | DOMPointInit | (number | DOMPointInit)[];
|
|
19
|
+
readonly stroke: DynValue<C, string | undefined>;
|
|
20
|
+
readonly fill: DynValue<C, string | undefined>;
|
|
21
|
+
|
|
22
|
+
constructor(
|
|
23
|
+
inner: Node<C>,
|
|
24
|
+
{
|
|
25
|
+
radii,
|
|
26
|
+
stroke,
|
|
27
|
+
fill,
|
|
28
|
+
...options
|
|
29
|
+
}: {
|
|
30
|
+
top: number;
|
|
31
|
+
bottom: number;
|
|
32
|
+
left: number;
|
|
33
|
+
right: number;
|
|
34
|
+
stroke?: DynValue<C, string | undefined>;
|
|
35
|
+
fill?: DynValue<C, string | undefined>;
|
|
36
|
+
radii: number | DOMPointInit | (number | DOMPointInit)[];
|
|
37
|
+
},
|
|
38
|
+
) {
|
|
39
|
+
super(inner, options);
|
|
40
|
+
this.radii = radii;
|
|
41
|
+
this.stroke = stroke;
|
|
42
|
+
this.fill = fill;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
draw(ctx: Context<C>, x: number, y: number): boolean {
|
|
46
|
+
// Reuse the current layout constraints so the background matches wrapped text.
|
|
47
|
+
const { width, height } = ctx.measureNode(this, ctx.constraints);
|
|
48
|
+
ctx.with((g) => {
|
|
49
|
+
const fill = this.fill == null ? undefined : ctx.resolveDynValue(this.fill);
|
|
50
|
+
const stroke = this.stroke == null ? undefined : ctx.resolveDynValue(this.stroke);
|
|
51
|
+
g.beginPath();
|
|
52
|
+
g.roundRect(x, y, width, height, this.radii);
|
|
53
|
+
if (fill != null) {
|
|
54
|
+
g.fillStyle = fill;
|
|
55
|
+
}
|
|
56
|
+
if (stroke != null) {
|
|
57
|
+
g.strokeStyle = stroke;
|
|
58
|
+
}
|
|
59
|
+
if (fill != null) {
|
|
60
|
+
g.fill();
|
|
61
|
+
}
|
|
62
|
+
if (stroke != null) {
|
|
63
|
+
g.stroke();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return super.draw(ctx, x, y);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const canvas = document.createElement("canvas");
|
|
71
|
+
document.body.appendChild(canvas);
|
|
72
|
+
canvas.width = canvas.clientWidth * devicePixelRatio;
|
|
73
|
+
canvas.height = canvas.clientHeight * devicePixelRatio;
|
|
74
|
+
|
|
75
|
+
const context = canvas.getContext("2d");
|
|
76
|
+
if (context == null) {
|
|
77
|
+
throw new Error("Failed to initial canvas");
|
|
78
|
+
}
|
|
79
|
+
const ctx: C = context;
|
|
80
|
+
ctx.scale(devicePixelRatio, devicePixelRatio);
|
|
81
|
+
|
|
82
|
+
const renderer = new DebugRenderer(ctx, {});
|
|
83
|
+
|
|
84
|
+
let color = "green";
|
|
85
|
+
|
|
86
|
+
class ClickDetect extends Wrapper<C> {
|
|
87
|
+
hittest(_ctx: Context<C>, _test: HitTest): boolean {
|
|
88
|
+
color = "red";
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const node = new RoundedBox(
|
|
94
|
+
new Flex<C>(
|
|
95
|
+
[
|
|
96
|
+
new Place(
|
|
97
|
+
new MultilineText("测试居中".repeat(20), {
|
|
98
|
+
lineHeight: 20,
|
|
99
|
+
font: "400 16px monospace",
|
|
100
|
+
align: "center",
|
|
101
|
+
style: "black",
|
|
102
|
+
}),
|
|
103
|
+
{ align: "center" },
|
|
104
|
+
),
|
|
105
|
+
new Place(
|
|
106
|
+
new RoundedBox(
|
|
107
|
+
new Flex<C>(
|
|
108
|
+
[
|
|
109
|
+
new ClickDetect(
|
|
110
|
+
new RoundedBox(
|
|
111
|
+
new Text("测试3".repeat(2), {
|
|
112
|
+
lineHeight: 20,
|
|
113
|
+
font: "400 16px monospace",
|
|
114
|
+
style: () => color,
|
|
115
|
+
}),
|
|
116
|
+
{
|
|
117
|
+
left: 14,
|
|
118
|
+
right: 14,
|
|
119
|
+
bottom: 10,
|
|
120
|
+
top: 10,
|
|
121
|
+
fill: "#aaa",
|
|
122
|
+
radii: 8,
|
|
123
|
+
},
|
|
124
|
+
),
|
|
125
|
+
),
|
|
126
|
+
new RoundedBox(
|
|
127
|
+
new MultilineText("测试2".repeat(5), {
|
|
128
|
+
lineHeight: 16,
|
|
129
|
+
font: "400 12px monospace",
|
|
130
|
+
align: "center",
|
|
131
|
+
style: "black",
|
|
132
|
+
}),
|
|
133
|
+
{
|
|
134
|
+
left: 10,
|
|
135
|
+
right: 10,
|
|
136
|
+
bottom: 5,
|
|
137
|
+
top: 5,
|
|
138
|
+
fill: "#aaa",
|
|
139
|
+
radii: 8,
|
|
140
|
+
},
|
|
141
|
+
),
|
|
142
|
+
],
|
|
143
|
+
{
|
|
144
|
+
direction: "row",
|
|
145
|
+
reverse: true,
|
|
146
|
+
gap: 10,
|
|
147
|
+
},
|
|
148
|
+
),
|
|
149
|
+
{
|
|
150
|
+
left: 10,
|
|
151
|
+
right: 10,
|
|
152
|
+
bottom: 10,
|
|
153
|
+
top: 10,
|
|
154
|
+
fill: "#ddd",
|
|
155
|
+
radii: 16,
|
|
156
|
+
},
|
|
157
|
+
),
|
|
158
|
+
{ align: "center" },
|
|
159
|
+
),
|
|
160
|
+
new Place(
|
|
161
|
+
new RoundedBox(
|
|
162
|
+
new MultilineText("文本右对齐".repeat(10), {
|
|
163
|
+
lineHeight: 20,
|
|
164
|
+
font: "400 16px monospace",
|
|
165
|
+
physicalAlign: "right",
|
|
166
|
+
style: "black",
|
|
167
|
+
}),
|
|
168
|
+
{
|
|
169
|
+
left: 10,
|
|
170
|
+
right: 10,
|
|
171
|
+
bottom: 10,
|
|
172
|
+
top: 10,
|
|
173
|
+
fill: "#ccc",
|
|
174
|
+
radii: 16,
|
|
175
|
+
},
|
|
176
|
+
),
|
|
177
|
+
{ align: "center" },
|
|
178
|
+
),
|
|
179
|
+
],
|
|
180
|
+
{
|
|
181
|
+
direction: "column",
|
|
182
|
+
gap: 10,
|
|
183
|
+
},
|
|
184
|
+
),
|
|
185
|
+
{
|
|
186
|
+
left: 10,
|
|
187
|
+
right: 10,
|
|
188
|
+
bottom: 10,
|
|
189
|
+
top: 10,
|
|
190
|
+
fill: "#eee",
|
|
191
|
+
radii: 20,
|
|
192
|
+
},
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
console.log(renderer.measureNode(node));
|
|
196
|
+
renderer.draw(node);
|
|
197
|
+
|
|
198
|
+
function drawFrame(): void {
|
|
199
|
+
renderer.draw(node);
|
|
200
|
+
requestAnimationFrame(drawFrame);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
requestAnimationFrame(drawFrame);
|
|
204
|
+
|
|
205
|
+
canvas.addEventListener("pointermove", (e) => {
|
|
206
|
+
const { top, left } = canvas.getBoundingClientRect();
|
|
207
|
+
const result = renderer.hittest(node, {
|
|
208
|
+
x: e.clientX - left,
|
|
209
|
+
y: e.clientY - top,
|
|
210
|
+
type: "hover",
|
|
211
|
+
});
|
|
212
|
+
if (!result) {
|
|
213
|
+
color = "green";
|
|
214
|
+
}
|
|
215
|
+
});
|