@elicdavis/node-flow 0.1.19 → 0.2.0
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/dist/index.d.mts +386 -227
- package/dist/index.d.ts +386 -227
- package/dist/index.js +1884 -1076
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1867 -1075
- package/dist/index.mjs.map +1 -1
- package/index.html +1134 -329
- package/package.json +1 -1
- package/src/connection.ts +30 -5
- package/src/contextMenu.ts +66 -34
- package/src/graph.ts +12 -10
- package/src/index.ts +26 -12
- package/src/markdown/entry.ts +11 -15
- package/src/markdown/syntaxParser.ts +2 -1
- package/src/node.ts +162 -111
- package/src/nodes/subsystem.ts +123 -29
- package/src/notes/note.ts +9 -1
- package/src/organize.ts +540 -111
- package/src/popup.ts +4 -2
- package/src/port.ts +83 -6
- package/src/styles/bevel.ts +31 -0
- package/src/styles/cursor.ts +1 -0
- package/src/styles/text.ts +4 -4
- package/src/theme.ts +179 -92
- package/src/types/text.ts +5 -1
- package/src/utils/color.ts +1 -1
- package/src/widgets/button.ts +52 -107
- package/src/widgets/color.ts +91 -150
- package/src/widgets/factory.ts +89 -46
- package/src/widgets/field.ts +99 -0
- package/src/widgets/image.ts +107 -165
- package/src/widgets/inplace.ts +84 -0
- package/src/widgets/number.ts +122 -154
- package/src/widgets/row.ts +138 -0
- package/src/widgets/slider.ts +101 -216
- package/src/widgets/string.ts +39 -130
- package/src/widgets/text.ts +81 -92
- package/src/widgets/toggle.ts +62 -207
- package/src/widgets/value.ts +127 -0
- package/src/widgets/widget.ts +180 -34
- package/test/context_menu.test.ts +82 -0
- package/test/cursor.test.ts +17 -0
- package/test/hidden_port.test.ts +125 -0
- package/test/hover_after_removal.test.ts +72 -0
- package/test/markdown.test.ts +2 -2
- package/test/markdown_code_block.test.ts +58 -0
- package/test/multi_input.test.ts +124 -0
- package/test/organize.test.ts +117 -1
- package/test/property_binding.test.ts +49 -0
- package/test/support.ts +175 -0
- package/test/theme.test.ts +86 -0
- package/test/widget_click.test.ts +111 -97
- package/test/widget_construction.test.ts +5 -4
- package/test/widgets.test.ts +333 -0
- package/test/wire_follows_camera.test.ts +57 -0
package/package.json
CHANGED
package/src/connection.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FlowNode } from "./node";
|
|
2
2
|
import { Port } from "./port";
|
|
3
|
-
import { BoxCenter, InBox } from "./types/box";
|
|
3
|
+
import { Box, BoxCenter, InBox } from "./types/box";
|
|
4
4
|
import { Vector2, Zero } from "./types/vector2";
|
|
5
5
|
import { Clamp01 } from "./utils/math";
|
|
6
6
|
|
|
@@ -134,7 +134,7 @@ export class Connection {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
if (this.#inNode !== null) {
|
|
137
|
-
const inPortBox = this.#
|
|
137
|
+
const inPortBox = this.#inSlotBox();
|
|
138
138
|
if (inPortBox === undefined) {
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
@@ -202,7 +202,7 @@ export class Connection {
|
|
|
202
202
|
this.clearOutput();
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
-
setInput(node: FlowNode, portIndex: number, replace?: boolean): void {
|
|
205
|
+
setInput(node: FlowNode, portIndex: number, replace?: boolean, insertAt?: number): void {
|
|
206
206
|
this.#inNode = node;
|
|
207
207
|
this.#inNodePortIndex = portIndex;
|
|
208
208
|
|
|
@@ -210,7 +210,7 @@ export class Connection {
|
|
|
210
210
|
if(!!replace && port.connections().length > 0) {
|
|
211
211
|
port.replaceConnection(this, 0);
|
|
212
212
|
} else {
|
|
213
|
-
port.addConnection(this);
|
|
213
|
+
port.addConnection(this, insertAt);
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
|
|
@@ -232,9 +232,34 @@ export class Connection {
|
|
|
232
232
|
this.#outNodePortIndex = -1;
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
+
/**
|
|
236
|
+
* The part of the input port this wire lands on: the whole port, or its
|
|
237
|
+
* own slot on a port holding several wires.
|
|
238
|
+
*/
|
|
239
|
+
#inSlotBox(): Box | undefined {
|
|
240
|
+
if (this.#inNode === null) {
|
|
241
|
+
return undefined;
|
|
242
|
+
}
|
|
243
|
+
const box = this.#inNode.inputPortPosition(this.#inNodePortIndex);
|
|
244
|
+
const port = this.#inNode.inputPort(this.#inNodePortIndex);
|
|
245
|
+
const slots = port.slots();
|
|
246
|
+
if (box === undefined || slots === 1) {
|
|
247
|
+
return box;
|
|
248
|
+
}
|
|
249
|
+
const index = port.connections().indexOf(this);
|
|
250
|
+
if (index === -1) {
|
|
251
|
+
return box;
|
|
252
|
+
}
|
|
253
|
+
const height = box.Size.y / slots;
|
|
254
|
+
return {
|
|
255
|
+
Position: { x: box.Position.x, y: box.Position.y + (index * height) },
|
|
256
|
+
Size: { x: box.Size.x, y: height },
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
235
260
|
mouseOverPort(mousePosition: Vector2): Port | null {
|
|
236
261
|
if (this.#inNode !== null) {
|
|
237
|
-
const inPortBox = this.#
|
|
262
|
+
const inPortBox = this.#inSlotBox();
|
|
238
263
|
if (inPortBox !== undefined && InBox(inPortBox, mousePosition)) {
|
|
239
264
|
return this.#inNode.inputPort(this.#inNodePortIndex)
|
|
240
265
|
}
|
package/src/contextMenu.ts
CHANGED
|
@@ -259,11 +259,23 @@ export class ContextMenu {
|
|
|
259
259
|
|
|
260
260
|
#openSubMenu: ContextMenu | undefined;
|
|
261
261
|
|
|
262
|
+
#bounds: Box | null = null;
|
|
262
263
|
|
|
263
|
-
|
|
264
|
+
#contains(point: Vector2): boolean {
|
|
265
|
+
if (this.#bounds !== null && InBox(this.#bounds, point)) {
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
return this.#openSubMenu !== undefined && this.#openSubMenu.#contains(point);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* A submenu is anchored to its parent's left edge and told the parent's
|
|
273
|
+
* width, so it can open on whichever side has room.
|
|
274
|
+
*/
|
|
275
|
+
public render(ctx: CanvasRenderingContext2D, anchor: Vector2, graphScale: number, mousePosition: Vector2 | undefined, openRight: boolean, parentWidth: number = 0): ContextEntry | null {
|
|
264
276
|
const menuScale = 1.25;
|
|
265
277
|
const scaledEntryHeight = menuScale * contextEntryHeight;
|
|
266
|
-
const scaledEntryWidth = (menuScale * 40) + (this.#getMaxWidthForText(ctx, menuScale));
|
|
278
|
+
const scaledEntryWidth = (menuScale * 40) + (this.#getMaxWidthForText(ctx, menuScale));
|
|
267
279
|
|
|
268
280
|
let totalScaledHeight = 0
|
|
269
281
|
for (let i = 0; i < this.#groups.Count(); i++) {
|
|
@@ -271,23 +283,41 @@ export class ContextMenu {
|
|
|
271
283
|
}
|
|
272
284
|
totalScaledHeight *= menuScale;
|
|
273
285
|
|
|
274
|
-
const
|
|
275
|
-
|
|
286
|
+
const canvasWidth = ctx.canvas.clientWidth;
|
|
287
|
+
const position = { x: anchor.x, y: anchor.y };
|
|
288
|
+
let opensRight = openRight;
|
|
276
289
|
|
|
277
|
-
if (
|
|
278
|
-
|
|
290
|
+
if (parentWidth === 0) {
|
|
291
|
+
if (!openRight) {
|
|
292
|
+
position.x -= scaledEntryWidth;
|
|
293
|
+
}
|
|
294
|
+
if (openRight && position.x + scaledEntryWidth > canvasWidth) {
|
|
295
|
+
position.x = canvasWidth - scaledEntryWidth;
|
|
296
|
+
opensRight = false;
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
const rightOfParent = anchor.x + parentWidth;
|
|
300
|
+
const leftOfParent = anchor.x - scaledEntryWidth;
|
|
301
|
+
const fitsRight = rightOfParent + scaledEntryWidth <= canvasWidth;
|
|
302
|
+
const fitsLeft = leftOfParent >= 0;
|
|
303
|
+
opensRight = openRight ? (fitsRight || !fitsLeft) : (!fitsLeft && fitsRight);
|
|
304
|
+
position.x = opensRight ? rightOfParent : leftOfParent;
|
|
305
|
+
position.x = Math.max(0, Math.min(position.x, canvasWidth - scaledEntryWidth));
|
|
279
306
|
}
|
|
280
307
|
|
|
281
|
-
// Clamp the position so it's not spilling off the canvas
|
|
282
308
|
if (position.y + totalScaledHeight > ctx.canvas.clientHeight) {
|
|
283
309
|
position.y = ctx.canvas.clientHeight - totalScaledHeight;
|
|
284
310
|
}
|
|
311
|
+
position.y = Math.max(0, position.y);
|
|
285
312
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
313
|
+
this.#bounds = {
|
|
314
|
+
Position: { x: position.x, y: position.y },
|
|
315
|
+
Size: { x: scaledEntryWidth, y: totalScaledHeight },
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
const pointer = mousePosition !== undefined && this.#openSubMenu !== undefined && this.#openSubMenu.#contains(mousePosition)
|
|
319
|
+
? undefined
|
|
320
|
+
: mousePosition;
|
|
291
321
|
|
|
292
322
|
this.#tempBox.Size.x = scaledEntryWidth;
|
|
293
323
|
this.#tempBox.Size.y = scaledEntryHeight;
|
|
@@ -305,13 +335,27 @@ export class ContextMenu {
|
|
|
305
335
|
this.#tempBox.Position.y,
|
|
306
336
|
scaledEntryWidth,
|
|
307
337
|
totalScaledHeight,
|
|
308
|
-
|
|
338
|
+
Theme.ContextMenu.BorderRadius * menuScale
|
|
309
339
|
);
|
|
310
340
|
ctx.fill();
|
|
311
341
|
ctx.shadowBlur = 0;
|
|
312
342
|
|
|
313
343
|
let mouseIsOver: ContextEntry | null = null;
|
|
314
|
-
|
|
344
|
+
if (pointer !== undefined) {
|
|
345
|
+
let row = 0;
|
|
346
|
+
for (let groupIndex = 0; groupIndex < this.#groups.Count(); groupIndex++) {
|
|
347
|
+
for (const entry of this.#groups.At(groupIndex).entries) {
|
|
348
|
+
this.#tempBox.Position.y = position.y + (scaledEntryHeight * row);
|
|
349
|
+
if (InBox(this.#tempBox, pointer)) {
|
|
350
|
+
mouseIsOver = entry;
|
|
351
|
+
this.#openSubMenu = entry.subMenu;
|
|
352
|
+
this.#submenuPosition.x = position.x;
|
|
353
|
+
this.#submenuPosition.y = this.#tempBox.Position.y;
|
|
354
|
+
}
|
|
355
|
+
row++;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
315
359
|
|
|
316
360
|
let optionsRendered = 0;
|
|
317
361
|
for (let groupIndex = 0; groupIndex < this.#groups.Count(); groupIndex++) {
|
|
@@ -321,27 +365,13 @@ export class ContextMenu {
|
|
|
321
365
|
|
|
322
366
|
this.#tempBox.Position.y = position.y + (scaledEntryHeight * optionsRendered);
|
|
323
367
|
|
|
324
|
-
|
|
325
|
-
if (mousePosition !== undefined && InBox(this.#tempBox, mousePosition)) {
|
|
326
|
-
mouseIsOver = entry;
|
|
327
|
-
entryMousedOver = true
|
|
328
|
-
if (entry.subMenu !== undefined) {
|
|
329
|
-
this.#openSubMenu = entry.subMenu;
|
|
330
|
-
this.#submenuPosition.x = position.x
|
|
331
|
-
this.#submenuPosition.y = this.#tempBox.Position.y;
|
|
332
|
-
if (submenuOpenRight) {
|
|
333
|
-
this.#submenuPosition.x += scaledEntryWidth
|
|
334
|
-
}
|
|
335
|
-
subOpenedThisFrame = true;
|
|
336
|
-
} else {
|
|
337
|
-
this.#openSubMenu = undefined;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
368
|
+
const entryMousedOver = entry === mouseIsOver;
|
|
340
369
|
|
|
341
370
|
const itemDisabled = entry.item !== undefined
|
|
342
371
|
&& entry.item.state() === ContextMenuItemState.Disabled;
|
|
343
372
|
|
|
344
|
-
|
|
373
|
+
const highlighted = !itemDisabled && (entryMousedOver || (this.#openSubMenu !== undefined && entry.subMenu === this.#openSubMenu));
|
|
374
|
+
if (highlighted) {
|
|
345
375
|
ctx.fillStyle = Theme.ContextMenu.HighlightColor;
|
|
346
376
|
ctx.beginPath();
|
|
347
377
|
ctx.roundRect(
|
|
@@ -349,7 +379,7 @@ export class ContextMenu {
|
|
|
349
379
|
this.#tempBox.Position.y + (scaledEntryHeight / 10),
|
|
350
380
|
scaledEntryWidth - (scaledEntryHeight / 5),
|
|
351
381
|
scaledEntryHeight - (scaledEntryHeight / 5),
|
|
352
|
-
|
|
382
|
+
Theme.ContextMenu.BorderRadius * menuScale
|
|
353
383
|
);
|
|
354
384
|
ctx.fill();
|
|
355
385
|
}
|
|
@@ -357,13 +387,15 @@ export class ContextMenu {
|
|
|
357
387
|
this.#textStyle.setupStyle(ctx, menuScale);
|
|
358
388
|
if (itemDisabled) {
|
|
359
389
|
ctx.fillStyle = Theme.ContextMenu.DisabledFontColor;
|
|
390
|
+
} else if (highlighted) {
|
|
391
|
+
ctx.fillStyle = Theme.ContextMenu.HighlightFontColor;
|
|
360
392
|
}
|
|
361
393
|
ctx.fillText(entry.text, position.x + (scaledEntryHeight / 5), this.#tempBox.Position.y + (scaledEntryHeight / 2))
|
|
362
394
|
|
|
363
395
|
// Render arrows
|
|
364
396
|
if (entry.subMenu !== undefined) {
|
|
365
397
|
ctx.beginPath()
|
|
366
|
-
ctx.strokeStyle = Theme.ContextMenu.FontColor;
|
|
398
|
+
ctx.strokeStyle = highlighted ? Theme.ContextMenu.HighlightFontColor : Theme.ContextMenu.FontColor;
|
|
367
399
|
ctx.lineWidth = 1 * menuScale;
|
|
368
400
|
ctx.lineTo(position.x + scaledEntryWidth - (scaledEntryHeight / 2.5), this.#tempBox.Position.y + (scaledEntryHeight / 3))
|
|
369
401
|
ctx.lineTo(position.x + scaledEntryWidth - (scaledEntryHeight / 4), this.#tempBox.Position.y + (scaledEntryHeight / 2))
|
|
@@ -388,7 +420,7 @@ export class ContextMenu {
|
|
|
388
420
|
}
|
|
389
421
|
|
|
390
422
|
if (this.#openSubMenu !== undefined) {
|
|
391
|
-
const mouseOverSub = this.#openSubMenu.render(ctx, this.#submenuPosition, menuScale, mousePosition,
|
|
423
|
+
const mouseOverSub = this.#openSubMenu.render(ctx, this.#submenuPosition, menuScale, mousePosition, opensRight, scaledEntryWidth)
|
|
392
424
|
if (mouseOverSub !== null) {
|
|
393
425
|
mouseIsOver = mouseOverSub;
|
|
394
426
|
}
|
package/src/graph.ts
CHANGED
|
@@ -23,17 +23,19 @@ import { Minimap, MinimapConfig } from './minimap';
|
|
|
23
23
|
|
|
24
24
|
export type GraphRenderer = (canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, position: Vector2, scale: number) => void;
|
|
25
25
|
|
|
26
|
-
function BuildBackgroundRenderer(backgroundColor: string): GraphRenderer {
|
|
26
|
+
function BuildBackgroundRenderer(backgroundColor: string | undefined): GraphRenderer {
|
|
27
27
|
return (canvas: HTMLCanvasElement, context: CanvasRenderingContext2D, position: Vector2, scale: number): void => {
|
|
28
|
-
context.fillStyle = backgroundColor;
|
|
28
|
+
context.fillStyle = backgroundColor ?? Theme.Graph.BackgroundColor;
|
|
29
29
|
context.fillRect(0, 0, canvas.width, canvas.height);
|
|
30
30
|
|
|
31
|
-
const alpha =
|
|
31
|
+
const alpha = Clamp01(scale - 0.3);
|
|
32
32
|
if (alpha <= 0) {
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
context.
|
|
36
|
+
context.save();
|
|
37
|
+
context.globalAlpha = alpha;
|
|
38
|
+
context.fillStyle = Theme.Graph.DotColor;
|
|
37
39
|
const spacing = 100;
|
|
38
40
|
const pi2 = 2 * Math.PI
|
|
39
41
|
const dotScale = 2 * scale;
|
|
@@ -46,6 +48,7 @@ function BuildBackgroundRenderer(backgroundColor: string): GraphRenderer {
|
|
|
46
48
|
context.fill();
|
|
47
49
|
}
|
|
48
50
|
}
|
|
51
|
+
context.restore();
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
54
|
|
|
@@ -75,7 +78,7 @@ interface OpenQuickMenu {
|
|
|
75
78
|
Position: Vector2
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
class GraphView {
|
|
81
|
+
export class GraphView {
|
|
79
82
|
|
|
80
83
|
#subsystems: Array<GraphSubsystem>;
|
|
81
84
|
|
|
@@ -138,9 +141,9 @@ class GraphView {
|
|
|
138
141
|
const results: RenderResults = {};
|
|
139
142
|
for (let i = 0; i < this.#subsystems.length; i++) {
|
|
140
143
|
TimeExecution("Render_Subsystem_" + i, () => {
|
|
141
|
-
|
|
142
|
-
if (
|
|
143
|
-
results.cursorStyle =
|
|
144
|
+
const layer = this.#subsystems[i].render(ctx, camera, mousePosition);
|
|
145
|
+
if (layer?.cursorStyle) {
|
|
146
|
+
results.cursorStyle = layer.cursorStyle;
|
|
144
147
|
}
|
|
145
148
|
})
|
|
146
149
|
}
|
|
@@ -224,8 +227,7 @@ export class NodeFlowGraph {
|
|
|
224
227
|
if (config?.backgroundRenderer !== undefined) {
|
|
225
228
|
this.#backgroundRenderer = config?.backgroundRenderer
|
|
226
229
|
} else {
|
|
227
|
-
|
|
228
|
-
this.#backgroundRenderer = BuildBackgroundRenderer(backgroundColor);
|
|
230
|
+
this.#backgroundRenderer = BuildBackgroundRenderer(config?.backgroundColor);
|
|
229
231
|
}
|
|
230
232
|
|
|
231
233
|
this.#minimap = new Minimap(config?.minimap);
|
package/src/index.ts
CHANGED
|
@@ -4,8 +4,9 @@ export * from './node';
|
|
|
4
4
|
import { ContextMenuConfig, ContextMenuItemConfig, ContextMenuItemState } from './contextMenu';
|
|
5
5
|
export { ContextMenuConfig, ContextMenuItemConfig, ContextMenuItemState };
|
|
6
6
|
|
|
7
|
-
import { Theme } from './theme';
|
|
8
|
-
export { Theme };
|
|
7
|
+
import { Theme, DefaultTheme, setTheme, themeVersion, onThemeChange, ThemeConfig, ThemeValues, BevelColors } from './theme';
|
|
8
|
+
export { Theme, DefaultTheme, setTheme, themeVersion, onThemeChange };
|
|
9
|
+
export type { ThemeConfig, ThemeValues, BevelColors };
|
|
9
10
|
|
|
10
11
|
import { Publisher, PublisherConfig } from './nodes/publisher';
|
|
11
12
|
export { Publisher, PublisherConfig };
|
|
@@ -53,30 +54,43 @@ import { NodeCreatedCallback, NodeFactory, NodeFactoryConfig } from './nodes/fac
|
|
|
53
54
|
export { NodeCreatedCallback, NodeFactory, NodeFactoryConfig };
|
|
54
55
|
|
|
55
56
|
// Widgets
|
|
56
|
-
import { Widget } from './widgets/widget';
|
|
57
|
-
import {
|
|
57
|
+
import { Widget, WidgetBase, WidgetPointer } from './widgets/widget';
|
|
58
|
+
import { ValueWidget, ValueWidgetConfig } from './widgets/value';
|
|
59
|
+
import { NumberWidget, NumberWidgetConfig, formatNumber } from './widgets/number';
|
|
58
60
|
import { ColorWidget, ColorWidgetConfig } from './widgets/color';
|
|
59
61
|
import { StringWidget, StringWidgetConfig } from './widgets/string';
|
|
60
62
|
import { TextWidget, TextWidgetConfig } from './widgets/text';
|
|
61
63
|
import { ButtonWidget, ButtonWidgetConfig } from './widgets/button';
|
|
62
|
-
import { ToggleWidget, ToggleWidgetConfig
|
|
64
|
+
import { ToggleWidget, ToggleWidgetConfig } from './widgets/toggle';
|
|
63
65
|
import { SliderWidget, SliderWidgetConfig } from './widgets/slider';
|
|
64
66
|
import { ImageWidget, ImageWidgetConfig } from './widgets/image';
|
|
67
|
+
import { RowWidget, RowWidgetConfig } from './widgets/row';
|
|
68
|
+
import { drawField, drawFieldBox, drawFieldText, FieldLook, widgetFont } from './widgets/field';
|
|
69
|
+
import { editInPlace, InPlaceEditConfig } from './widgets/inplace';
|
|
65
70
|
export {
|
|
66
|
-
|
|
71
|
+
WidgetBase, ValueWidget,
|
|
67
72
|
NumberWidget, ColorWidget, StringWidget, TextWidget,
|
|
68
|
-
ButtonWidget, ToggleWidget, SliderWidget, ImageWidget
|
|
73
|
+
ButtonWidget, ToggleWidget, SliderWidget, ImageWidget, RowWidget,
|
|
74
|
+
drawField, drawFieldBox, drawFieldText, widgetFont, editInPlace, formatNumber,
|
|
69
75
|
};
|
|
70
76
|
export type {
|
|
77
|
+
Widget, WidgetPointer, ValueWidgetConfig, FieldLook, InPlaceEditConfig,
|
|
71
78
|
NumberWidgetConfig, ColorWidgetConfig, StringWidgetConfig, TextWidgetConfig,
|
|
72
|
-
ButtonWidgetConfig, ToggleWidgetConfig,
|
|
73
|
-
ImageWidgetConfig
|
|
79
|
+
ButtonWidgetConfig, ToggleWidgetConfig, SliderWidgetConfig,
|
|
80
|
+
ImageWidgetConfig, RowWidgetConfig,
|
|
74
81
|
};
|
|
75
82
|
|
|
76
|
-
import {
|
|
83
|
+
import {
|
|
84
|
+
GlobalWidgetFactory, WidgetBuilder, WidgetFactory,
|
|
85
|
+
WidgetConfig, WidgetConfigs, WidgetTypes, RowWidgetFactoryConfig,
|
|
86
|
+
} from './widgets/factory';
|
|
77
87
|
export { GlobalWidgetFactory, WidgetFactory };
|
|
78
|
-
export type { WidgetBuilder };
|
|
88
|
+
export type { WidgetBuilder, WidgetConfig, WidgetConfigs, WidgetTypes, RowWidgetFactoryConfig };
|
|
89
|
+
|
|
90
|
+
import { CursorStyle } from './styles/cursor';
|
|
91
|
+
export { CursorStyle };
|
|
79
92
|
|
|
80
|
-
import { Box } from './types/box';
|
|
93
|
+
import { Box, InBox } from './types/box';
|
|
81
94
|
import { Vector2 } from './types/vector2';
|
|
95
|
+
export { InBox };
|
|
82
96
|
export type { Box, Vector2 };
|
package/src/markdown/entry.ts
CHANGED
|
@@ -82,28 +82,26 @@ export class CodeBlockEntry {
|
|
|
82
82
|
render(ctx: CanvasRenderingContext2D, position: Vector2, scale: number, maxWidth: number): number {
|
|
83
83
|
this.#calculateLayout(ctx, maxWidth);
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
const padding = Theme.Note.CodeBlock.Padding * scale;
|
|
86
|
+
const lineCount = this.#calculatedEntries.Count();
|
|
87
|
+
const lastTop = lineCount === 0 ? 0 : this.#calculatedPositions.At(lineCount - 1).y;
|
|
88
|
+
const contentHeight = lineCount === 0 ? 0 : (lastTop + this.#text.style().getSize()) * scale;
|
|
89
|
+
const height = contentHeight + (padding * 2);
|
|
86
90
|
|
|
87
|
-
let max = 0;
|
|
88
|
-
for (let i = 0; i < this.#calculatedEntries.Count(); i++) {
|
|
89
|
-
const pos = this.#calculatedPositions.At(i);
|
|
90
|
-
max = Math.max(max, pos.y * scale)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const y = position.y + max + (scale * 5)
|
|
94
91
|
ctx.fillStyle = Theme.Note.CodeBlock.BackgroundColor;
|
|
95
92
|
ctx.beginPath();
|
|
96
93
|
ctx.roundRect(
|
|
97
94
|
position.x,
|
|
98
95
|
position.y,
|
|
99
96
|
maxWidth * scale,
|
|
100
|
-
|
|
97
|
+
height,
|
|
101
98
|
Theme.Note.CodeBlock.BorderRadius * scale
|
|
102
99
|
);
|
|
103
100
|
ctx.fill();
|
|
104
101
|
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
const baseline = ctx.textBaseline;
|
|
103
|
+
ctx.textBaseline = "top";
|
|
104
|
+
for (let i = 0; i < lineCount; i++) {
|
|
107
105
|
const entry = this.#calculatedEntries.At(i);
|
|
108
106
|
const pos = this.#calculatedPositions.At(i);
|
|
109
107
|
|
|
@@ -111,12 +109,10 @@ export class CodeBlockEntry {
|
|
|
111
109
|
x: (pos.x * scale) + position.x + padding,
|
|
112
110
|
y: (pos.y * scale) + position.y + padding
|
|
113
111
|
});
|
|
114
|
-
|
|
115
|
-
max = Math.max(max, pos.y * scale)
|
|
116
112
|
}
|
|
113
|
+
ctx.textBaseline = baseline;
|
|
117
114
|
|
|
118
|
-
|
|
119
|
-
return max + (padding * 2);
|
|
115
|
+
return height;
|
|
120
116
|
}
|
|
121
117
|
}
|
|
122
118
|
|
|
@@ -314,9 +314,10 @@ export class MarkdownSyntaxParser {
|
|
|
314
314
|
this.#inc(); // puts us on the 3rd
|
|
315
315
|
this.#inc(); // puts us on the next token
|
|
316
316
|
|
|
317
|
-
const codeBlockText = this.#originalText.substring(start as number, end);
|
|
317
|
+
const codeBlockText = this.#originalText.substring(start as number, end).replace(/\r?\n$/, "");
|
|
318
318
|
const entryText = new Text(codeBlockText);
|
|
319
319
|
this.#assignStandardStyling([entryText])
|
|
320
|
+
entryText.setColor(Theme.Note.CodeBlock.FontColor);
|
|
320
321
|
return new CodeBlockEntry(entryText)
|
|
321
322
|
}
|
|
322
323
|
|