@canvas-harness/core 0.0.4 → 0.1.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.cjs +56 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -6
- package/dist/index.d.ts +18 -6
- package/dist/index.js +56 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -106,7 +106,7 @@ type EdgeStyle = Style & {
|
|
|
106
106
|
* Built-in node types — see ARCHITECTURE.md §3.5.
|
|
107
107
|
* Custom node types are arbitrary strings registered via defineNode.
|
|
108
108
|
*/
|
|
109
|
-
type BuiltInNodeType = 'rect' | 'ellipse' | 'diamond' | 'tag' | 'capsule' | 'thought-cloud' | 'layered-rect' | 'layered-ellipse' | 'layered-diamond' | 'text' | 'image' | 'icon' | 'frame';
|
|
109
|
+
type BuiltInNodeType = 'rect' | 'ellipse' | 'diamond' | 'tag' | 'capsule' | 'thought-cloud' | 'layered-rect' | 'layered-ellipse' | 'layered-diamond' | 'soft-diamond' | 'text' | 'image' | 'icon' | 'frame';
|
|
110
110
|
type NodeType = BuiltInNodeType | (string & {
|
|
111
111
|
readonly __nodeType?: never;
|
|
112
112
|
});
|
|
@@ -1495,14 +1495,21 @@ interface CanvasStore {
|
|
|
1495
1495
|
* Adds a node. Returns its id. If `node.style.autoFit !== false` and
|
|
1496
1496
|
* `node.content` is set, height is grown to fit.
|
|
1497
1497
|
*
|
|
1498
|
+
* `z` is optional — omit to land on top of the current stack (uses
|
|
1499
|
+
* the internal `topZ` counter). Pass a literal value (incl. `0` or
|
|
1500
|
+
* negative) to place the node at that exact z.
|
|
1501
|
+
*
|
|
1498
1502
|
* @example
|
|
1503
|
+
* // Omit z → goes on top of the current stack.
|
|
1499
1504
|
* const id = store.addNode({
|
|
1500
1505
|
* id: asNodeId(store.generateId()),
|
|
1501
1506
|
* type: 'rect', x: 0, y: 0, w: 200, h: 100,
|
|
1502
|
-
* angle: 0,
|
|
1507
|
+
* angle: 0, groups: [],
|
|
1503
1508
|
* })
|
|
1504
1509
|
*/
|
|
1505
|
-
addNode(node: Node
|
|
1510
|
+
addNode(node: Omit<Node, 'z'> & {
|
|
1511
|
+
z?: number;
|
|
1512
|
+
}): NodeId;
|
|
1506
1513
|
/**
|
|
1507
1514
|
* Patches fields on an existing node. Captures the previous slice on
|
|
1508
1515
|
* the op so undo is free. Autofit re-runs when `content` or font
|
|
@@ -1566,8 +1573,13 @@ interface CanvasStore {
|
|
|
1566
1573
|
alt?: string;
|
|
1567
1574
|
style?: Style;
|
|
1568
1575
|
}): Promise<NodeId>;
|
|
1569
|
-
/**
|
|
1570
|
-
|
|
1576
|
+
/**
|
|
1577
|
+
* Adds an edge. Returns its id. `z` is optional — same auto-top
|
|
1578
|
+
* semantics as {@link CanvasStore.addNode}.
|
|
1579
|
+
*/
|
|
1580
|
+
addEdge(edge: Omit<Edge, 'z'> & {
|
|
1581
|
+
z?: number;
|
|
1582
|
+
}): EdgeId;
|
|
1571
1583
|
/** Patches fields on an existing edge. */
|
|
1572
1584
|
updateEdge(id: EdgeId, patch: Partial<Edge>): void;
|
|
1573
1585
|
/** Removes an edge. */
|
|
@@ -2034,7 +2046,7 @@ type AtomicPrimitive = 'rect' | 'ellipse' | 'diamond' | 'tag' | 'thought-cloud';
|
|
|
2034
2046
|
* circle and the rect body reads as two stacked hand-drawn shapes
|
|
2035
2047
|
* (medicine-pill aesthetic), which we want to keep.
|
|
2036
2048
|
*/
|
|
2037
|
-
type CompositePrimitive = 'capsule' | 'layered-rect' | 'layered-ellipse' | 'layered-diamond';
|
|
2049
|
+
type CompositePrimitive = 'capsule' | 'layered-rect' | 'layered-ellipse' | 'layered-diamond' | 'soft-diamond';
|
|
2038
2050
|
type PrimitiveType = AtomicPrimitive | CompositePrimitive;
|
|
2039
2051
|
/** Returns true if `node.type` is one of the built-ins drawShape can render. */
|
|
2040
2052
|
declare const isDrawablePrimitive: (type: string) => type is PrimitiveType;
|
package/dist/index.d.ts
CHANGED
|
@@ -106,7 +106,7 @@ type EdgeStyle = Style & {
|
|
|
106
106
|
* Built-in node types — see ARCHITECTURE.md §3.5.
|
|
107
107
|
* Custom node types are arbitrary strings registered via defineNode.
|
|
108
108
|
*/
|
|
109
|
-
type BuiltInNodeType = 'rect' | 'ellipse' | 'diamond' | 'tag' | 'capsule' | 'thought-cloud' | 'layered-rect' | 'layered-ellipse' | 'layered-diamond' | 'text' | 'image' | 'icon' | 'frame';
|
|
109
|
+
type BuiltInNodeType = 'rect' | 'ellipse' | 'diamond' | 'tag' | 'capsule' | 'thought-cloud' | 'layered-rect' | 'layered-ellipse' | 'layered-diamond' | 'soft-diamond' | 'text' | 'image' | 'icon' | 'frame';
|
|
110
110
|
type NodeType = BuiltInNodeType | (string & {
|
|
111
111
|
readonly __nodeType?: never;
|
|
112
112
|
});
|
|
@@ -1495,14 +1495,21 @@ interface CanvasStore {
|
|
|
1495
1495
|
* Adds a node. Returns its id. If `node.style.autoFit !== false` and
|
|
1496
1496
|
* `node.content` is set, height is grown to fit.
|
|
1497
1497
|
*
|
|
1498
|
+
* `z` is optional — omit to land on top of the current stack (uses
|
|
1499
|
+
* the internal `topZ` counter). Pass a literal value (incl. `0` or
|
|
1500
|
+
* negative) to place the node at that exact z.
|
|
1501
|
+
*
|
|
1498
1502
|
* @example
|
|
1503
|
+
* // Omit z → goes on top of the current stack.
|
|
1499
1504
|
* const id = store.addNode({
|
|
1500
1505
|
* id: asNodeId(store.generateId()),
|
|
1501
1506
|
* type: 'rect', x: 0, y: 0, w: 200, h: 100,
|
|
1502
|
-
* angle: 0,
|
|
1507
|
+
* angle: 0, groups: [],
|
|
1503
1508
|
* })
|
|
1504
1509
|
*/
|
|
1505
|
-
addNode(node: Node
|
|
1510
|
+
addNode(node: Omit<Node, 'z'> & {
|
|
1511
|
+
z?: number;
|
|
1512
|
+
}): NodeId;
|
|
1506
1513
|
/**
|
|
1507
1514
|
* Patches fields on an existing node. Captures the previous slice on
|
|
1508
1515
|
* the op so undo is free. Autofit re-runs when `content` or font
|
|
@@ -1566,8 +1573,13 @@ interface CanvasStore {
|
|
|
1566
1573
|
alt?: string;
|
|
1567
1574
|
style?: Style;
|
|
1568
1575
|
}): Promise<NodeId>;
|
|
1569
|
-
/**
|
|
1570
|
-
|
|
1576
|
+
/**
|
|
1577
|
+
* Adds an edge. Returns its id. `z` is optional — same auto-top
|
|
1578
|
+
* semantics as {@link CanvasStore.addNode}.
|
|
1579
|
+
*/
|
|
1580
|
+
addEdge(edge: Omit<Edge, 'z'> & {
|
|
1581
|
+
z?: number;
|
|
1582
|
+
}): EdgeId;
|
|
1571
1583
|
/** Patches fields on an existing edge. */
|
|
1572
1584
|
updateEdge(id: EdgeId, patch: Partial<Edge>): void;
|
|
1573
1585
|
/** Removes an edge. */
|
|
@@ -2034,7 +2046,7 @@ type AtomicPrimitive = 'rect' | 'ellipse' | 'diamond' | 'tag' | 'thought-cloud';
|
|
|
2034
2046
|
* circle and the rect body reads as two stacked hand-drawn shapes
|
|
2035
2047
|
* (medicine-pill aesthetic), which we want to keep.
|
|
2036
2048
|
*/
|
|
2037
|
-
type CompositePrimitive = 'capsule' | 'layered-rect' | 'layered-ellipse' | 'layered-diamond';
|
|
2049
|
+
type CompositePrimitive = 'capsule' | 'layered-rect' | 'layered-ellipse' | 'layered-diamond' | 'soft-diamond';
|
|
2038
2050
|
type PrimitiveType = AtomicPrimitive | CompositePrimitive;
|
|
2039
2051
|
/** Returns true if `node.type` is one of the built-ins drawShape can render. */
|
|
2040
2052
|
declare const isDrawablePrimitive: (type: string) => type is PrimitiveType;
|
package/dist/index.js
CHANGED
|
@@ -1053,7 +1053,8 @@ var COMPOSITE = /* @__PURE__ */ new Set([
|
|
|
1053
1053
|
"capsule",
|
|
1054
1054
|
"layered-rect",
|
|
1055
1055
|
"layered-ellipse",
|
|
1056
|
-
"layered-diamond"
|
|
1056
|
+
"layered-diamond",
|
|
1057
|
+
"soft-diamond"
|
|
1057
1058
|
]);
|
|
1058
1059
|
var isCompositePrimitive = (type) => COMPOSITE.has(type);
|
|
1059
1060
|
var isDrawablePrimitive = (type) => ATOMIC.has(type) || COMPOSITE.has(type);
|
|
@@ -1159,6 +1160,30 @@ var compositeLayout = (node) => {
|
|
|
1159
1160
|
const front = { atomic, x: 0, y: 0, w, h };
|
|
1160
1161
|
return [back, front];
|
|
1161
1162
|
}
|
|
1163
|
+
case "soft-diamond": {
|
|
1164
|
+
const backScale = 1.08;
|
|
1165
|
+
const frontScale = 0.96;
|
|
1166
|
+
const bw = w * backScale;
|
|
1167
|
+
const bh = h * backScale;
|
|
1168
|
+
const fw = w * frontScale;
|
|
1169
|
+
const fh = h * frontScale;
|
|
1170
|
+
const back = {
|
|
1171
|
+
atomic: "diamond",
|
|
1172
|
+
x: (w - bw) / 2,
|
|
1173
|
+
y: (h - bh) / 2,
|
|
1174
|
+
w: bw,
|
|
1175
|
+
h: bh,
|
|
1176
|
+
style: darkenedStyle(node.style)
|
|
1177
|
+
};
|
|
1178
|
+
const front = {
|
|
1179
|
+
atomic: "diamond",
|
|
1180
|
+
x: (w - fw) / 2,
|
|
1181
|
+
y: (h - fh) / 2,
|
|
1182
|
+
w: fw,
|
|
1183
|
+
h: fh
|
|
1184
|
+
};
|
|
1185
|
+
return [back, front];
|
|
1186
|
+
}
|
|
1162
1187
|
}
|
|
1163
1188
|
return [];
|
|
1164
1189
|
};
|
|
@@ -3217,8 +3242,15 @@ var createCanvasStore = (opts = {}) => {
|
|
|
3217
3242
|
};
|
|
3218
3243
|
const incidentEdges = /* @__PURE__ */ new Map();
|
|
3219
3244
|
let topZ = 0;
|
|
3220
|
-
|
|
3221
|
-
for (const
|
|
3245
|
+
let bottomZ = 0;
|
|
3246
|
+
for (const n of Object.values(initial.nodes)) {
|
|
3247
|
+
if (n.z > topZ) topZ = n.z;
|
|
3248
|
+
if (n.z < bottomZ) bottomZ = n.z;
|
|
3249
|
+
}
|
|
3250
|
+
for (const e of Object.values(initial.edges)) {
|
|
3251
|
+
if (e.z > topZ) topZ = e.z;
|
|
3252
|
+
if (e.z < bottomZ) bottomZ = e.z;
|
|
3253
|
+
}
|
|
3222
3254
|
const getNodeForGeo = (id) => nodeAtoms.get(id)?.value;
|
|
3223
3255
|
let currentBatchOps = null;
|
|
3224
3256
|
let batchDepth = 0;
|
|
@@ -3307,6 +3339,8 @@ var createCanvasStore = (opts = {}) => {
|
|
|
3307
3339
|
nodeAtoms.set(op.node.id, a);
|
|
3308
3340
|
nodeIdsAtom.update((ids) => [...ids, op.node.id]);
|
|
3309
3341
|
reindexNode(op.node);
|
|
3342
|
+
if (op.node.z > topZ) topZ = op.node.z;
|
|
3343
|
+
if (op.node.z < bottomZ) bottomZ = op.node.z;
|
|
3310
3344
|
if (op.node.type === "frame") {
|
|
3311
3345
|
frameOrderAtom.update((ids) => ids.includes(op.node.id) ? ids : [...ids, op.node.id]);
|
|
3312
3346
|
}
|
|
@@ -3318,6 +3352,10 @@ var createCanvasStore = (opts = {}) => {
|
|
|
3318
3352
|
const next = { ...a.value, ...op.patch };
|
|
3319
3353
|
a.set(next);
|
|
3320
3354
|
reindexNode(next);
|
|
3355
|
+
if (op.patch.z !== void 0) {
|
|
3356
|
+
if (op.patch.z > topZ) topZ = op.patch.z;
|
|
3357
|
+
if (op.patch.z < bottomZ) bottomZ = op.patch.z;
|
|
3358
|
+
}
|
|
3321
3359
|
const incident = incidentEdges.get(op.id);
|
|
3322
3360
|
if (incident) {
|
|
3323
3361
|
for (const eid of incident) {
|
|
@@ -3346,6 +3384,8 @@ var createCanvasStore = (opts = {}) => {
|
|
|
3346
3384
|
trackIncidence(op.edge);
|
|
3347
3385
|
bumpEdgeVersion(op.edge.id);
|
|
3348
3386
|
reindexEdge(op.edge);
|
|
3387
|
+
if (op.edge.z > topZ) topZ = op.edge.z;
|
|
3388
|
+
if (op.edge.z < bottomZ) bottomZ = op.edge.z;
|
|
3349
3389
|
break;
|
|
3350
3390
|
}
|
|
3351
3391
|
case "edge.update": {
|
|
@@ -3358,6 +3398,10 @@ var createCanvasStore = (opts = {}) => {
|
|
|
3358
3398
|
a.set(next);
|
|
3359
3399
|
bumpEdgeVersion(op.id);
|
|
3360
3400
|
reindexEdge(next);
|
|
3401
|
+
if (op.patch.z !== void 0) {
|
|
3402
|
+
if (op.patch.z > topZ) topZ = op.patch.z;
|
|
3403
|
+
if (op.patch.z < bottomZ) bottomZ = op.patch.z;
|
|
3404
|
+
}
|
|
3361
3405
|
break;
|
|
3362
3406
|
}
|
|
3363
3407
|
case "edge.remove": {
|
|
@@ -3445,9 +3489,8 @@ var createCanvasStore = (opts = {}) => {
|
|
|
3445
3489
|
clientId,
|
|
3446
3490
|
generateId: () => idGenerator(),
|
|
3447
3491
|
addNode(node) {
|
|
3448
|
-
const
|
|
3449
|
-
|
|
3450
|
-
const fitted = withAutoFitHeight(withZ);
|
|
3492
|
+
const z = node.z ?? ++topZ;
|
|
3493
|
+
const fitted = withAutoFitHeight({ ...node, z });
|
|
3451
3494
|
enqueueOp({ type: "node.add", node: fitted });
|
|
3452
3495
|
return fitted.id;
|
|
3453
3496
|
},
|
|
@@ -3510,7 +3553,6 @@ var createCanvasStore = (opts = {}) => {
|
|
|
3510
3553
|
w,
|
|
3511
3554
|
h,
|
|
3512
3555
|
angle: 0,
|
|
3513
|
-
z: 0,
|
|
3514
3556
|
groups: [],
|
|
3515
3557
|
style: opts2.style,
|
|
3516
3558
|
data: { src, naturalW, naturalH, alt: opts2.alt }
|
|
@@ -3533,7 +3575,6 @@ var createCanvasStore = (opts = {}) => {
|
|
|
3533
3575
|
w,
|
|
3534
3576
|
h,
|
|
3535
3577
|
angle: 0,
|
|
3536
|
-
z: 0,
|
|
3537
3578
|
groups: [],
|
|
3538
3579
|
...mergedStyle ? { style: mergedStyle } : {},
|
|
3539
3580
|
data: { src: sanitized, alt: opts2.alt }
|
|
@@ -3541,8 +3582,8 @@ var createCanvasStore = (opts = {}) => {
|
|
|
3541
3582
|
return id;
|
|
3542
3583
|
},
|
|
3543
3584
|
addEdge(edge) {
|
|
3544
|
-
const
|
|
3545
|
-
|
|
3585
|
+
const z = edge.z ?? ++topZ;
|
|
3586
|
+
const withZ = { ...edge, z };
|
|
3546
3587
|
enqueueOp({ type: "edge.add", edge: withZ });
|
|
3547
3588
|
return withZ.id;
|
|
3548
3589
|
},
|
|
@@ -3565,29 +3606,10 @@ var createCanvasStore = (opts = {}) => {
|
|
|
3565
3606
|
});
|
|
3566
3607
|
},
|
|
3567
3608
|
sendToBack(ids) {
|
|
3568
|
-
const targets = new Set(ids);
|
|
3569
|
-
let minZ = 0;
|
|
3570
|
-
let initialized = false;
|
|
3571
|
-
for (const a of nodeAtoms.values()) {
|
|
3572
|
-
if (targets.has(a.value.id)) continue;
|
|
3573
|
-
if (!initialized || a.value.z < minZ) {
|
|
3574
|
-
minZ = a.value.z;
|
|
3575
|
-
initialized = true;
|
|
3576
|
-
}
|
|
3577
|
-
}
|
|
3578
|
-
for (const a of edgeAtoms.values()) {
|
|
3579
|
-
if (targets.has(a.value.id)) continue;
|
|
3580
|
-
if (!initialized || a.value.z < minZ) {
|
|
3581
|
-
minZ = a.value.z;
|
|
3582
|
-
initialized = true;
|
|
3583
|
-
}
|
|
3584
|
-
}
|
|
3585
3609
|
this.batch(() => {
|
|
3586
|
-
let next = (initialized ? minZ : 0) - 1;
|
|
3587
3610
|
for (const id of ids) {
|
|
3588
|
-
if (nodeAtoms.has(id)) this.updateNode(id, { z:
|
|
3589
|
-
else if (edgeAtoms.has(id)) this.updateEdge(id, { z:
|
|
3590
|
-
next -= 1;
|
|
3611
|
+
if (nodeAtoms.has(id)) this.updateNode(id, { z: --bottomZ });
|
|
3612
|
+
else if (edgeAtoms.has(id)) this.updateEdge(id, { z: --bottomZ });
|
|
3591
3613
|
}
|
|
3592
3614
|
});
|
|
3593
3615
|
},
|
|
@@ -3605,7 +3627,6 @@ var createCanvasStore = (opts = {}) => {
|
|
|
3605
3627
|
if (currentZ === void 0) continue;
|
|
3606
3628
|
const idx = binaryFirstGreater(allZ, currentZ);
|
|
3607
3629
|
const nextZ = idx >= 0 ? allZ[idx] + 1 : currentZ + 1;
|
|
3608
|
-
if (nextZ > topZ) topZ = nextZ;
|
|
3609
3630
|
if (node) this.updateNode(id, { z: nextZ });
|
|
3610
3631
|
else this.updateEdge(id, { z: nextZ });
|
|
3611
3632
|
}
|
|
@@ -4266,7 +4287,7 @@ var paintBackground = (ctx, opts) => {
|
|
|
4266
4287
|
}
|
|
4267
4288
|
};
|
|
4268
4289
|
var paintDots = (ctx, minX, minY, maxX, maxY, gap, color, zoom) => {
|
|
4269
|
-
const sizeWorld = Math.max(1,
|
|
4290
|
+
const sizeWorld = Math.max(1, 1.6 / zoom);
|
|
4270
4291
|
const half = sizeWorld / 2;
|
|
4271
4292
|
ctx.save();
|
|
4272
4293
|
ctx.fillStyle = color;
|
|
@@ -4547,7 +4568,8 @@ var contentBounds = (node) => {
|
|
|
4547
4568
|
return { x: rectX, y: 0, w: Math.max(0, w - rectX), h };
|
|
4548
4569
|
}
|
|
4549
4570
|
case "diamond":
|
|
4550
|
-
case "layered-diamond":
|
|
4571
|
+
case "layered-diamond":
|
|
4572
|
+
case "soft-diamond": {
|
|
4551
4573
|
const cw = w * SQRT2_INV;
|
|
4552
4574
|
const ch = h * SQRT2_INV;
|
|
4553
4575
|
return { x: (w - cw) / 2, y: (h - ch) / 2, w: cw, h: ch };
|