@mhkeller/layercake-annotations 0.1.1 → 0.2.1

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 CHANGED
@@ -50,6 +50,14 @@ pnpm add @mhkeller/layercake-annotations
50
50
  | `annotations` | `Annotation[]` | `[]` | Array of annotation objects (bindable) |
51
51
  | `editable` | `boolean` | `true` | Enable editing. Set `false` for read-only display |
52
52
 
53
+ **Note:** The `annotations` prop uses Svelte 5's `$bindable` for two-way binding. For edits to persist, the parent component must store annotations in a `$state` variable:
54
+
55
+ ```svelte
56
+ let annotations = $state([]); // ✓ edits persist
57
+ let annotations = []; // ✗ edits won't persist
58
+ import annotations from 'annotations.js' // ✗ edits won't persist
59
+ ```
60
+
53
61
  ## Annotation Data Structure
54
62
 
55
63
  ```js
@@ -45,7 +45,6 @@
45
45
  * State vars
46
46
  */
47
47
  let idCounter = Math.max(...annos.map((d) => d.id), -1);
48
- let annotations = $state(annos);
49
48
 
50
49
  /** @type {Ref<boolean>} */
51
50
  const isEditing = createRef(false);
@@ -75,31 +74,32 @@
75
74
  yScale: $yScale,
76
75
  config: $config
77
76
  });
78
- annotations.push(annotation);
79
- saveConfig_debounced(annotations);
77
+ annos.push(annotation);
78
+ saveConfig_debounced(annos);
80
79
  }
81
80
 
82
81
  /**
83
82
  * Delete an annotation from the chart
84
83
  */
85
84
  async function deleteAnnotation(id) {
86
- annotations = annotations.filter((d) => d.id !== id);
87
- saveConfig_debounced(annotations);
85
+ // Reassign annos (the bindable prop) so deletion propagates to parent
86
+ annos = annos.filter((d) => d.id !== id);
87
+ saveConfig_debounced(annos);
88
88
  }
89
89
 
90
90
  /**
91
91
  * Modify the annotation's coordinates on drag
92
92
  */
93
93
  function modifyAnnotation(id, newProps) {
94
- annotations.forEach((d, i) => {
94
+ annos.forEach((d, i) => {
95
95
  if (d.id === id) {
96
- annotations[i] = {
96
+ annos[i] = {
97
97
  ...d,
98
98
  ...newProps
99
99
  };
100
100
  }
101
101
  });
102
- saveConfig_debounced(annotations);
102
+ saveConfig_debounced(annos);
103
103
  }
104
104
 
105
105
  /**
@@ -107,7 +107,7 @@
107
107
  * Arrow structure: { side, clockwise, source: { dx, dy }, target: { [xKey], [yKey] } }
108
108
  */
109
109
  function setArrow(id, arrow) {
110
- const annotation = annotations.find((d) => d.id === id);
110
+ const annotation = annos.find((d) => d.id === id);
111
111
  if (!annotation) return;
112
112
 
113
113
  const existingIndex = annotation.arrows.findIndex((a) => a.side === arrow.side);
@@ -118,28 +118,28 @@
118
118
  annotation.arrows.push(arrow);
119
119
  }
120
120
 
121
- saveConfig_debounced(annotations);
121
+ saveConfig_debounced(annos);
122
122
  }
123
123
 
124
124
  /**
125
125
  * Modify an arrow's properties (e.g., clockwise)
126
126
  */
127
127
  function modifyArrow(id, side, attrs) {
128
- const annotation = annotations.find((d) => d.id === id);
128
+ const annotation = annos.find((d) => d.id === id);
129
129
  if (!annotation) return;
130
130
 
131
131
  const arrow = annotation.arrows.find((a) => a.side === side);
132
132
  if (!arrow) return;
133
133
 
134
134
  Object.assign(arrow, attrs);
135
- saveConfig_debounced(annotations);
135
+ saveConfig_debounced(annos);
136
136
  }
137
137
 
138
138
  /**
139
139
  * Delete an arrow from an annotation
140
140
  */
141
141
  function deleteArrow(id, side) {
142
- const annotation = annotations.find((d) => d.id === id);
142
+ const annotation = annos.find((d) => d.id === id);
143
143
  if (!annotation) return;
144
144
 
145
145
  const len = annotation.arrows.length;
@@ -149,7 +149,7 @@
149
149
  if (len === annotation.arrows.length) {
150
150
  deleteAnnotation(annotation.id);
151
151
  }
152
- saveConfig_debounced(annotations);
152
+ saveConfig_debounced(annos);
153
153
  }
154
154
 
155
155
  /**
@@ -165,7 +165,7 @@
165
165
  } else if (hover.type === 'arrow' && hover.side) {
166
166
  deleteArrow(hover.annotationId, hover.side);
167
167
  }
168
- saveConfig_debounced(annotations);
168
+ saveConfig_debounced(annos);
169
169
  }
170
170
  }
171
171
 
@@ -182,7 +182,7 @@
182
182
  {/snippet}
183
183
 
184
184
  <Svg {defs}>
185
- <Arrows {annotations} />
185
+ <Arrows annotations={annos} />
186
186
  </Svg>
187
187
 
188
188
  <Html>
@@ -196,7 +196,7 @@
196
196
  ></div>
197
197
 
198
198
  <div class="layercake-annotations">
199
- {#each annotations as d (d.id)}
199
+ {#each annos as d (d.id)}
200
200
  <AnnotationEditor {d} {containerClass} />
201
201
  {/each}
202
202
  </div>
@@ -209,5 +209,6 @@
209
209
  width: 100%;
210
210
  height: 100%;
211
211
  cursor: copy;
212
+ outline: none;
212
213
  }
213
214
  </style>
@@ -12,13 +12,13 @@
12
12
  </script>
13
13
 
14
14
  {#snippet defs()}
15
- <ArrowheadMarker />
15
+ <ArrowheadMarker />
16
16
  {/snippet}
17
17
 
18
- <Svg {defs}>
18
+ <Svg {defs} pointerEvents={false}>
19
19
  <Arrows {annotations} />
20
20
  </Svg>
21
21
 
22
- <Html>
22
+ <Html pointerEvents={false}>
23
23
  <AnnotationsData {annotations} />
24
24
  </Html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhkeller/layercake-annotations",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && pnpm package",