@linkurious/ogma-annotations 2.0.3 → 2.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.
@@ -1 +1 @@
1
- :root{--handle-width: 2px;--point-handle-width: calc(3 * var(--handle-width));--point-handle-border: 2px;--point-handle-total: calc(var(--point-handle-width) + var(--point-handle-border));--handle-color: #38e;--handle-background: #fff;--active-color: #1a70e5;--disabled-color: #999;--hover-color: rgba(56, 136, 238, .2)}svg text{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.handle{position:absolute;background-color:var(--handle-color)}.handle.line{cursor:move}.ogma-annotation-text-editor{display:flex;flex-direction:column;align-items:flex-end;position:relative;width:100%;height:100%}.ogma-annotation-text-editor.animate-width{transition:width .2s ease-out,left .2s ease-out}.ogma-annotation-text-editor textarea{outline:none;padding:0;margin:0;border:0;width:100%;height:100%;cursor:text;z-index:1000;resize:none;white-space:break-spaces;background-color:transparent;overflow:hidden}.ogma-annotation-text-editor textarea::-webkit-scrollbar{width:6px}.ogma-annotation-text-editor textarea::-webkit-scrollbar-track{background:transparent}.ogma-annotation-text-editor textarea::-webkit-scrollbar-thumb{background:#0003;border-radius:3px}.ogma-annotation-text-editor textarea::-webkit-scrollbar-thumb:hover{background:#0000004d}.ogma-send-button{width:24px;height:24px;margin-left:auto;border:none;background:transparent;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:background-color .2s ease;z-index:1001}.ogma-send-button-icon{width:16px;height:16px;display:flex;align-items:center;justify-content:center;color:var(--handle-color, #38e)}.ogma-send-button-icon svg{width:100%;height:100%}.ogma-send-button:not(:disabled):hover{background-color:var(--hover-color);transform:scale(1.05)}.ogma-send-button:not(:disabled):hover .ogma-send-button-icon{color:var(--active-color)}.ogma-send-button:not(:disabled):active{background-color:var(--hover-color);transform:scale(.95)}.ogma-send-button:not(:disabled):active .ogma-send-button-icon{color:var(--active-color)}.ogma-send-button:disabled{cursor:not-allowed;opacity:.3}.ogma-send-button:disabled .ogma-send-button-icon{color:var(--disabled-color)}.annotation-text-handle .noevents{pointer-events:none;z-index:20}.line-handle,.point-handle{z-index:30}.line-handle.top{cursor:ns-resize;height:var(--handle-width);left:0;width:100%;top:calc(var(--handle-width) * -1)}.line-handle.bottom{cursor:ns-resize;height:var(--handle-width);width:100%;left:0;bottom:calc(var(--handle-width) * -1)}.line-handle.left{cursor:ew-resize;height:100%;top:0;left:calc(var(--handle-width) * -1);width:var(--handle-width)}.line-handle.right{cursor:ew-resize;height:100%;right:calc(var(--handle-width) * -1);top:0;width:var(--handle-width)}.line-handle.top,.line-handle.bottom,.line-handle.left,.line-handle.right{cursor:move}.point-handle{border-radius:50%;background-color:#fff;transform-origin:center;transform:translate(-50%,-50%);border:var(--point-handle-border) solid var(--handle-color);width:var(--point-handle-width);height:var(--point-handle-width)}.point-handle.top-left{transform:translate(-55%,-55%)}.point-handle.top-right{transform:translate(-45%,-55%)}.point-handle.bottom-left{transform:translate(-55%,-45%)}.point-handle.bottom-right{transform:translate(-45%,-45%)}.rotated .point-handle.bottom-left,.rotated .point-handle.top-right{display:none}.point-handle.top-left,.point-handle.bottom-right{cursor:nwse-resize}.point-handle.top-right,.point-handle.bottom-left{cursor:nesw-resize}.point-handle.bottom-left,.point-handle.bottom-right{top:100%}.point-handle.top-left,.point-handle.top-right{top:0}.point-handle.bottom-left,.point-handle.top-left{left:0}.point-handle.bottom-right,.point-handle.top-right{left:100%}.arrow-handle>.handle{height:var(--point-handle-width);width:var(--point-handle-width);border-radius:50%;cursor:move;transform:translate(-50%,-50%)}.arrow-handle>.line{height:var(--handle-width);border-radius:0;cursor:move}.arrow-handle>.point{background-color:var(--handle-background);border:2px solid var(--handle-color)}.annotations-hidden-input{position:absolute;bottom:0;left:0;visibility:hidden;display:block}.active{background-color:#38e}.annotation-text{cursor:pointer}.annotation-text:hover>rect{stroke:var(--handle-color)}.annotation-text a{fill:var(--handle-color)}.annotation-text a:hover{text-decoration:underline}.annotation-hovered,.annotation-selected{background:#f5f5f5;background-color:#f5f5f5}
1
+ :root{--handle-width: 2px;--point-handle-width: calc(3 * var(--handle-width));--point-handle-border: 2px;--point-handle-total: calc(var(--point-handle-width) + var(--point-handle-border));--handle-color: #38e;--annotation-link-color: var(--handle-color);--handle-background: #fff;--active-color: #1a70e5;--disabled-color: #999;--hover-color: rgba(56, 136, 238, .2)}svg text{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ogma-annotation-link{fill:var(--annotation-link-color, #38e);color:var(--annotation-link-color, #38e);text-decoration:none;pointer-events:auto;cursor:pointer}.handle{position:absolute;background-color:var(--handle-color)}.handle.line{cursor:move}.ogma-annotation-text-editor{display:flex;flex-direction:column;align-items:flex-end;position:relative;width:100%;height:100%}.ogma-annotation-text-editor.animate-width{transition:width .2s ease-out,left .2s ease-out}.ogma-annotation-text-editor textarea{outline:none;padding:0;margin:0;border:0;width:100%;height:100%;cursor:text;z-index:1000;resize:none;white-space:break-spaces;background-color:transparent;overflow:hidden}.ogma-annotation-text-editor textarea::-webkit-scrollbar{width:6px}.ogma-annotation-text-editor textarea::-webkit-scrollbar-track{background:transparent}.ogma-annotation-text-editor textarea::-webkit-scrollbar-thumb{background:#0003;border-radius:3px}.ogma-annotation-text-editor textarea::-webkit-scrollbar-thumb:hover{background:#0000004d}.ogma-send-button{width:24px;height:24px;margin-left:auto;border:none;background:transparent;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:background-color .2s ease;z-index:1001}.ogma-send-button-icon{width:16px;height:16px;display:flex;align-items:center;justify-content:center;color:var(--handle-color, #38e)}.ogma-send-button-icon svg{width:100%;height:100%}.ogma-send-button:not(:disabled):hover{background-color:var(--hover-color);transform:scale(1.05)}.ogma-send-button:not(:disabled):hover .ogma-send-button-icon{color:var(--active-color)}.ogma-send-button:not(:disabled):active{background-color:var(--hover-color);transform:scale(.95)}.ogma-send-button:not(:disabled):active .ogma-send-button-icon{color:var(--active-color)}.ogma-send-button:disabled{cursor:not-allowed;opacity:.3}.ogma-send-button:disabled .ogma-send-button-icon{color:var(--disabled-color)}.annotation-text-handle .noevents{pointer-events:none;z-index:20}.line-handle,.point-handle{z-index:30}.line-handle.top{cursor:ns-resize;height:var(--handle-width);left:0;width:100%;top:calc(var(--handle-width) * -1)}.line-handle.bottom{cursor:ns-resize;height:var(--handle-width);width:100%;left:0;bottom:calc(var(--handle-width) * -1)}.line-handle.left{cursor:ew-resize;height:100%;top:0;left:calc(var(--handle-width) * -1);width:var(--handle-width)}.line-handle.right{cursor:ew-resize;height:100%;right:calc(var(--handle-width) * -1);top:0;width:var(--handle-width)}.line-handle.top,.line-handle.bottom,.line-handle.left,.line-handle.right{cursor:move}.point-handle{border-radius:50%;background-color:#fff;transform-origin:center;transform:translate(-50%,-50%);border:var(--point-handle-border) solid var(--handle-color);width:var(--point-handle-width);height:var(--point-handle-width)}.point-handle.top-left{transform:translate(-55%,-55%)}.point-handle.top-right{transform:translate(-45%,-55%)}.point-handle.bottom-left{transform:translate(-55%,-45%)}.point-handle.bottom-right{transform:translate(-45%,-45%)}.rotated .point-handle.bottom-left,.rotated .point-handle.top-right{display:none}.point-handle.top-left,.point-handle.bottom-right{cursor:nwse-resize}.point-handle.top-right,.point-handle.bottom-left{cursor:nesw-resize}.point-handle.bottom-left,.point-handle.bottom-right{top:100%}.point-handle.top-left,.point-handle.top-right{top:0}.point-handle.bottom-left,.point-handle.top-left{left:0}.point-handle.bottom-right,.point-handle.top-right{left:100%}.arrow-handle>.handle{height:var(--point-handle-width);width:var(--point-handle-width);border-radius:50%;cursor:move;transform:translate(-50%,-50%)}.arrow-handle>.line{height:var(--handle-width);border-radius:0;cursor:move}.arrow-handle>.point{background-color:var(--handle-background);border:2px solid var(--handle-color)}.annotations-hidden-input{position:absolute;bottom:0;left:0;visibility:hidden;display:block}.active{background-color:#38e}.annotation-text{cursor:pointer}.annotation-text:hover>rect{stroke:var(--handle-color)}.annotation-text a{fill:var(--handle-color)}.annotation-text a:hover{text-decoration:underline}.annotation-hovered,.annotation-selected{background:#f5f5f5;background-color:#f5f5f5}
@@ -128,6 +128,19 @@ export declare type Bounds = [number, number, number, number];
128
128
  export declare interface Box extends AnnotationFeature<Point_2, BoxProperties> {
129
129
  }
130
130
 
131
+ /**
132
+ * Arrow snapped to a rectangular annotation (text, box, comment).
133
+ * nx/ny are center-relative fractions multiplied by width/height:
134
+ * left-center = { nx: -0.5, ny: 0 }
135
+ * right-center = { nx: 0.5, ny: 0 }
136
+ * center = { nx: 0, ny: 0 }
137
+ */
138
+ export declare type BoxMagnet = {
139
+ type: "box";
140
+ nx: number;
141
+ ny: number;
142
+ };
143
+
131
144
  /** Properties specific to box annotations. */
132
145
  export declare interface BoxProperties extends AnnotationProps {
133
146
  type: "box";
@@ -1209,6 +1222,12 @@ declare interface DragEvent_2 {
1209
1222
  }
1210
1223
  export { DragEvent_2 as DragEvent }
1211
1224
 
1225
+ /** Arrow snapped at parametric position t (0–1) along an edge path. */
1226
+ export declare type EdgeMagnet = {
1227
+ type: "edge";
1228
+ t: number;
1229
+ };
1230
+
1212
1231
  export declare const EVT_ADD = "add";
1213
1232
 
1214
1233
  export declare const EVT_CANCEL_DRAWING = "cancelDrawing";
@@ -1239,6 +1258,11 @@ export declare const EVT_UNSELECT = "unselect";
1239
1258
 
1240
1259
  export declare const EVT_UPDATE = "update";
1241
1260
 
1261
+ /**
1262
+ * Serialized link stored inside arrow.properties.link.
1263
+ * Uses plain { x, y } for backward compatibility with saved annotations.
1264
+ * Converted to the internal Magnet type by Links.add().
1265
+ */
1242
1266
  export declare type ExportedLink = {
1243
1267
  id: Id;
1244
1268
  side: Side;
@@ -1540,13 +1564,12 @@ export declare interface Link {
1540
1564
  target: Id;
1541
1565
  /** Text or node */
1542
1566
  targetType: TargetType;
1543
- /**
1544
- * On which point relative to topleft corner the arrow is tighten, in case of
1545
- * node, a 0 vector represents the center, otherwise it can be deduced from the arrow itself
1546
- */
1547
- magnet: Point;
1567
+ /** Typed snap point — semantics depend on targetType, see Magnet union. */
1568
+ magnet: Magnet;
1548
1569
  }
1549
1570
 
1571
+ export declare type Magnet = NodeMagnet | EdgeMagnet | BoxMagnet | PolygonMagnet;
1572
+
1550
1573
  /**
1551
1574
  * Migrates old Polygon-based Box/Text to new Point-based format
1552
1575
  * Called only when annotations are added/loaded
@@ -1554,6 +1577,12 @@ export declare interface Link {
1554
1577
  */
1555
1578
  export declare function migrateBoxOrTextIfNeeded<T extends Annotation>(annotation: T): T;
1556
1579
 
1580
+ /** Arrow snapped to the center or perimeter of a node. */
1581
+ export declare type NodeMagnet = {
1582
+ type: "node";
1583
+ center: boolean;
1584
+ };
1585
+
1557
1586
  export declare const NONE = -1;
1558
1587
 
1559
1588
  export declare function parseColor(color: Color): {
@@ -1575,6 +1604,16 @@ export declare type Point = {
1575
1604
  export declare interface Polygon extends AnnotationFeature<Polygon_2, PolygonProperties> {
1576
1605
  }
1577
1606
 
1607
+ /**
1608
+ * Arrow snapped to a polygon annotation.
1609
+ * rx/ry are 0–1 fractions of the polygon's bounding box from its top-left corner.
1610
+ */
1611
+ export declare type PolygonMagnet = {
1612
+ type: "polygon";
1613
+ rx: number;
1614
+ ry: number;
1615
+ };
1616
+
1578
1617
  export declare interface PolygonProperties extends AnnotationProps {
1579
1618
  type: "polygon";
1580
1619
  style?: PolygonStyle;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linkurious/ogma-annotations",
3
- "version": "2.0.3",
3
+ "version": "2.1.0",
4
4
  "description": "Headless annotation plugin for Ogma",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -88,7 +88,7 @@
88
88
  "@linkurious/ogma": ">=5.3.11"
89
89
  },
90
90
  "dependencies": {
91
- "@borgar/textbox": "1.8.0",
91
+ "@chenglou/pretext": "0.0.7",
92
92
  "eventemitter3": "5.0.1",
93
93
  "geojson": "0.5.0",
94
94
  "rbush": "4.0.1",
@@ -108,9 +108,9 @@
108
108
  "typedoc-vitepress-theme": "1.1.2",
109
109
  "typescript": "5.3.3",
110
110
  "vanilla-colorful": "0.7.2",
111
- "vite": "6.3.5",
111
+ "vite": "6.4.3",
112
112
  "vite-plugin-dts": "^4.1.0",
113
- "vitest": "3.2.4",
113
+ "vitest": "3.2.6",
114
114
  "vitest-canvas-mock": "1.1.3"
115
115
  },
116
116
  "prettier": {