@grida/svg-editor 1.0.0-alpha.22 → 1.0.0-alpha.23
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/{dom-Dw2SPHgc.d.mts → dom-D-ZJO9aK.d.mts} +17 -1
- package/dist/{dom-BIjCxCgx.mjs → dom-DVxR7PNh.mjs} +93 -42
- package/dist/{dom-H4PvmPe3.js → dom-Disackua.js} +98 -41
- package/dist/{dom-CQkWJNrK.d.ts → dom-Dl56kUW5.d.ts} +17 -1
- package/dist/dom.d.mts +2 -2
- package/dist/dom.d.ts +2 -2
- package/dist/dom.js +2 -1
- package/dist/dom.mjs +2 -2
- package/dist/presets.d.mts +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/presets.mjs +1 -1
- package/dist/react.d.mts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/react.mjs +1 -1
- package/package.json +5 -5
|
@@ -198,6 +198,22 @@ declare function project_point_through_ctm(px: number, py: number, ctm: {
|
|
|
198
198
|
e: number;
|
|
199
199
|
f: number;
|
|
200
200
|
}, container_offset: readonly [number, number]): [number, number];
|
|
201
|
+
/**
|
|
202
|
+
* The matrix form of {@link project_point_through_ctm}: the full
|
|
203
|
+
* `local → container-px` affine for a CTM + container offset, as a
|
|
204
|
+
* `cmath.Transform`. Use when handing the transform to a downstream projector
|
|
205
|
+
* (e.g. HUD chrome) instead of projecting a single point.
|
|
206
|
+
*
|
|
207
|
+
* Pure function, no DOM types.
|
|
208
|
+
*/
|
|
209
|
+
declare function ctm_to_container_transform(ctm: {
|
|
210
|
+
a: number;
|
|
211
|
+
b: number;
|
|
212
|
+
c: number;
|
|
213
|
+
d: number;
|
|
214
|
+
e: number;
|
|
215
|
+
f: number;
|
|
216
|
+
}, container_offset: readonly [number, number]): cmath.Transform;
|
|
201
217
|
/**
|
|
202
218
|
* Inverse of the CTM's linear part applied to a delta vector. Drops
|
|
203
219
|
* translation. Used to convert a HUD-reported container-space drag delta
|
|
@@ -236,4 +252,4 @@ declare function inverse_project_rect(rect: {
|
|
|
236
252
|
f: number;
|
|
237
253
|
}, offset: readonly [number, number]): cmath.Rectangle | null;
|
|
238
254
|
//#endregion
|
|
239
|
-
export {
|
|
255
|
+
export { ctm_to_container_transform as a, project_delta_inverse_ctm as c, SnapOptions as d, attach_dom_surface as i, project_point_through_ctm as l, DomSurfaceHandle as n, install_font_load_geometry_bump as o, DomSurfaceOptions as r, inverse_project_rect as s, AttentionScope as t, DEFAULT_SNAP_OPTIONS as u };
|
|
@@ -1222,44 +1222,32 @@ function create_attention_tracker(container) {
|
|
|
1222
1222
|
}
|
|
1223
1223
|
//#endregion
|
|
1224
1224
|
//#region src/text-surface.ts
|
|
1225
|
-
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
1226
1225
|
const XML_NS = "http://www.w3.org/XML/1998/namespace";
|
|
1227
1226
|
var SvgTextSurface = class {
|
|
1228
|
-
|
|
1227
|
+
/**
|
|
1228
|
+
* @param textEl the live text element to drive.
|
|
1229
|
+
* @param sink receives the caret + selection geometry (local space) on
|
|
1230
|
+
* every change; the host projects + forwards it to the HUD. Called with
|
|
1231
|
+
* `null` on dispose so the host clears the chrome.
|
|
1232
|
+
*/
|
|
1233
|
+
constructor(textEl, sink) {
|
|
1229
1234
|
this.prevXmlSpace = void 0;
|
|
1230
1235
|
this.prevPointerEvents = void 0;
|
|
1236
|
+
this.caret = null;
|
|
1237
|
+
this.selection = null;
|
|
1231
1238
|
this.last_caret_idx = -1;
|
|
1232
1239
|
this.last_caret_visible = false;
|
|
1233
1240
|
this.last_sel_start = -1;
|
|
1234
1241
|
this.last_sel_end = -1;
|
|
1235
1242
|
this.textEl = textEl;
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
while (mountAnchor.parentElement instanceof SVGElement && (mountAnchor.localName === "tspan" || mountAnchor.localName === "textPath")) mountAnchor = mountAnchor.parentElement;
|
|
1239
|
-
const parent = mountAnchor.parentNode;
|
|
1240
|
-
if (!parent) throw new Error("text element has no parent");
|
|
1241
|
-
const computedWhitespace = ownerDoc.defaultView?.getComputedStyle(textEl).whiteSpace;
|
|
1243
|
+
this.sink = sink;
|
|
1244
|
+
const computedWhitespace = textEl.ownerDocument.defaultView?.getComputedStyle(textEl).whiteSpace;
|
|
1242
1245
|
if (!(computedWhitespace === "pre" || computedWhitespace === "pre-wrap" || computedWhitespace === "break-spaces")) {
|
|
1243
1246
|
this.prevXmlSpace = textEl.getAttributeNS(XML_NS, "space");
|
|
1244
1247
|
textEl.setAttributeNS(XML_NS, "xml:space", "preserve");
|
|
1245
1248
|
}
|
|
1246
1249
|
this.prevPointerEvents = textEl.getAttribute("pointer-events");
|
|
1247
1250
|
textEl.setAttribute("pointer-events", "bounding-box");
|
|
1248
|
-
const selection = ownerDoc.createElementNS(SVG_NS, "rect");
|
|
1249
|
-
selection.setAttribute("fill", "#2563eb");
|
|
1250
|
-
selection.setAttribute("fill-opacity", "0.25");
|
|
1251
|
-
selection.setAttribute("pointer-events", "none");
|
|
1252
|
-
selection.setAttribute("data-svg-text-edit-selection", "");
|
|
1253
|
-
selection.style.display = "none";
|
|
1254
|
-
parent.insertBefore(selection, mountAnchor);
|
|
1255
|
-
this.selectionRect = selection;
|
|
1256
|
-
const caret = ownerDoc.createElementNS(SVG_NS, "rect");
|
|
1257
|
-
caret.setAttribute("fill", "#2563eb");
|
|
1258
|
-
caret.setAttribute("pointer-events", "none");
|
|
1259
|
-
caret.setAttribute("data-svg-text-edit-caret", "");
|
|
1260
|
-
caret.style.display = "none";
|
|
1261
|
-
parent.insertBefore(caret, mountAnchor.nextSibling);
|
|
1262
|
-
this.caretRect = caret;
|
|
1263
1251
|
}
|
|
1264
1252
|
setText(text) {
|
|
1265
1253
|
if (this.textEl.textContent !== text) this.textEl.textContent = text;
|
|
@@ -1268,38 +1256,43 @@ var SvgTextSurface = class {
|
|
|
1268
1256
|
if (index === this.last_caret_idx && visible === this.last_caret_visible) return;
|
|
1269
1257
|
this.last_caret_idx = index;
|
|
1270
1258
|
this.last_caret_visible = visible;
|
|
1271
|
-
if (!visible) {
|
|
1272
|
-
this.caretRect.style.display = "none";
|
|
1273
|
-
return;
|
|
1274
|
-
}
|
|
1275
1259
|
const m = this.metrics();
|
|
1276
1260
|
const x = this.charX(index);
|
|
1277
|
-
this.
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1261
|
+
this.caret = {
|
|
1262
|
+
top: [x, m.top],
|
|
1263
|
+
bottom: [x, m.top + m.height],
|
|
1264
|
+
visible
|
|
1265
|
+
};
|
|
1266
|
+
this.emit();
|
|
1282
1267
|
}
|
|
1283
1268
|
setSelection(start, end) {
|
|
1284
1269
|
if (start === this.last_sel_start && end === this.last_sel_end) return;
|
|
1285
1270
|
this.last_sel_start = start;
|
|
1286
1271
|
this.last_sel_end = end;
|
|
1287
1272
|
if (start === end) {
|
|
1288
|
-
this.
|
|
1273
|
+
this.selection = null;
|
|
1274
|
+
this.emit();
|
|
1289
1275
|
return;
|
|
1290
1276
|
}
|
|
1291
1277
|
const m = this.metrics();
|
|
1292
1278
|
const x1 = this.charX(start);
|
|
1293
1279
|
const x2 = this.charX(end);
|
|
1294
|
-
this.
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1280
|
+
this.selection = {
|
|
1281
|
+
x: Math.min(x1, x2),
|
|
1282
|
+
y: m.top,
|
|
1283
|
+
width: Math.abs(x2 - x1),
|
|
1284
|
+
height: m.height
|
|
1285
|
+
};
|
|
1286
|
+
this.emit();
|
|
1287
|
+
}
|
|
1288
|
+
emit() {
|
|
1289
|
+
this.sink({
|
|
1290
|
+
caret: this.caret,
|
|
1291
|
+
selection: this.selection
|
|
1292
|
+
});
|
|
1299
1293
|
}
|
|
1300
1294
|
dispose(keepEditMutations = false) {
|
|
1301
|
-
this.
|
|
1302
|
-
this.selectionRect.remove();
|
|
1295
|
+
this.sink(null);
|
|
1303
1296
|
if (this.prevXmlSpace !== void 0 && !keepEditMutations) if (this.prevXmlSpace === null) this.textEl.removeAttributeNS(XML_NS, "space");
|
|
1304
1297
|
else this.textEl.setAttributeNS(XML_NS, "xml:space", this.prevXmlSpace);
|
|
1305
1298
|
if (this.prevPointerEvents !== void 0) if (this.prevPointerEvents === null) this.textEl.removeAttribute("pointer-events");
|
|
@@ -1923,6 +1916,7 @@ var DomSurface = class DomSurface {
|
|
|
1923
1916
|
this.text_edit = null;
|
|
1924
1917
|
this.text_edit_target = null;
|
|
1925
1918
|
this.text_edit_original = "";
|
|
1919
|
+
this.text_edit_geom = null;
|
|
1926
1920
|
this.pending_text_insert = null;
|
|
1927
1921
|
this.vector_edit = null;
|
|
1928
1922
|
this.point_snap_guide = void 0;
|
|
@@ -2067,6 +2061,7 @@ var DomSurface = class DomSurface {
|
|
|
2067
2061
|
this.apply_camera_transform();
|
|
2068
2062
|
this.hud.setPixelGridTransform(this.camera.transform);
|
|
2069
2063
|
this.sync_surface_selection();
|
|
2064
|
+
if (this.text_edit_geom) this.push_text_edit_chrome(this.text_edit_geom);
|
|
2070
2065
|
this.redraw();
|
|
2071
2066
|
}));
|
|
2072
2067
|
this.render();
|
|
@@ -4074,7 +4069,10 @@ var DomSurface = class DomSurface {
|
|
|
4074
4069
|
this.sync_surface_selection();
|
|
4075
4070
|
this.sync_cursor();
|
|
4076
4071
|
this.redraw();
|
|
4077
|
-
const text_surface = new SvgTextSurface(this.element_index.get(id) ?? el)
|
|
4072
|
+
const text_surface = new SvgTextSurface(this.element_index.get(id) ?? el, (geom) => {
|
|
4073
|
+
this.push_text_edit_chrome(geom);
|
|
4074
|
+
this.request_redraw();
|
|
4075
|
+
});
|
|
4078
4076
|
const is_mac = typeof navigator !== "undefined" && /Mac|iPod|iPhone|iPad/.test(navigator.userAgent);
|
|
4079
4077
|
let settled = false;
|
|
4080
4078
|
this.text_edit = createTextEditor({
|
|
@@ -4122,11 +4120,45 @@ var DomSurface = class DomSurface {
|
|
|
4122
4120
|
this.render();
|
|
4123
4121
|
this.sync_surface_selection();
|
|
4124
4122
|
this.sync_cursor();
|
|
4123
|
+
this.push_text_edit_chrome(null);
|
|
4125
4124
|
this.redraw();
|
|
4126
4125
|
this.text_edit = null;
|
|
4127
4126
|
this.text_edit_target = null;
|
|
4128
4127
|
}
|
|
4129
4128
|
/**
|
|
4129
|
+
* Project the active session's text-edit geometry (LOCAL svg user-space) and
|
|
4130
|
+
* push it to the HUD as text-edit chrome (caret + selection), or clear it on
|
|
4131
|
+
* `null`. The local→container-px transform comes from the live text
|
|
4132
|
+
* element's `getScreenCTM` (which folds in the camera's CSS transform on the
|
|
4133
|
+
* SVG root) minus the container offset — the same projection convention
|
|
4134
|
+
* `vector_of` / `container_box` use. The HUD keeps its own transform at
|
|
4135
|
+
* identity, so this per-chrome transform is the whole projection. Does NOT
|
|
4136
|
+
* redraw — callers own that.
|
|
4137
|
+
*/
|
|
4138
|
+
push_text_edit_chrome(geom) {
|
|
4139
|
+
this.text_edit_geom = geom;
|
|
4140
|
+
if (!geom) {
|
|
4141
|
+
this.hud.setTextEditChrome(null);
|
|
4142
|
+
return;
|
|
4143
|
+
}
|
|
4144
|
+
const ctm = (this.text_edit_target ? this.element_index.get(this.text_edit_target) : void 0)?.getScreenCTM?.() ?? null;
|
|
4145
|
+
if (!ctm) {
|
|
4146
|
+
this.hud.setTextEditChrome(null);
|
|
4147
|
+
return;
|
|
4148
|
+
}
|
|
4149
|
+
const input = {
|
|
4150
|
+
transform: ctm_to_container_transform(ctm, this.container_offset()),
|
|
4151
|
+
caret: geom.caret ? {
|
|
4152
|
+
top: geom.caret.top,
|
|
4153
|
+
bottom: geom.caret.bottom
|
|
4154
|
+
} : void 0,
|
|
4155
|
+
caretVisible: geom.caret?.visible ?? false,
|
|
4156
|
+
selectionRects: geom.selection ? [geom.selection] : void 0,
|
|
4157
|
+
style: { caretColor: "#000000" }
|
|
4158
|
+
};
|
|
4159
|
+
this.hud.setTextEditChrome(input);
|
|
4160
|
+
}
|
|
4161
|
+
/**
|
|
4130
4162
|
* Realize the result of a text content-edit session and exit. `result`
|
|
4131
4163
|
* is the text that should remain — the typed text on commit, the original
|
|
4132
4164
|
* on cancel. Implements the empty-equals-delete rule (design:
|
|
@@ -4945,6 +4977,25 @@ function project_point_through_ctm(px, py, ctm, container_offset) {
|
|
|
4945
4977
|
return [sx + container_offset[0], sy + container_offset[1]];
|
|
4946
4978
|
}
|
|
4947
4979
|
/**
|
|
4980
|
+
* The matrix form of {@link project_point_through_ctm}: the full
|
|
4981
|
+
* `local → container-px` affine for a CTM + container offset, as a
|
|
4982
|
+
* `cmath.Transform`. Use when handing the transform to a downstream projector
|
|
4983
|
+
* (e.g. HUD chrome) instead of projecting a single point.
|
|
4984
|
+
*
|
|
4985
|
+
* Pure function, no DOM types.
|
|
4986
|
+
*/
|
|
4987
|
+
function ctm_to_container_transform(ctm, container_offset) {
|
|
4988
|
+
return [[
|
|
4989
|
+
ctm.a,
|
|
4990
|
+
ctm.c,
|
|
4991
|
+
ctm.e + container_offset[0]
|
|
4992
|
+
], [
|
|
4993
|
+
ctm.b,
|
|
4994
|
+
ctm.d,
|
|
4995
|
+
ctm.f + container_offset[1]
|
|
4996
|
+
]];
|
|
4997
|
+
}
|
|
4998
|
+
/**
|
|
4948
4999
|
* Inverse of the CTM's linear part applied to a delta vector. Drops
|
|
4949
5000
|
* translation. Used to convert a HUD-reported container-space drag delta
|
|
4950
5001
|
* back to the path's local coord space for `PathModel.translateVertices`.
|
|
@@ -5220,4 +5271,4 @@ var SvgHitShapeDriver = class {
|
|
|
5220
5271
|
}
|
|
5221
5272
|
};
|
|
5222
5273
|
//#endregion
|
|
5223
|
-
export {
|
|
5274
|
+
export { project_delta_inverse_ctm as a, DEFAULT_SNAP_OPTIONS as c, inverse_project_rect as i, MemoizedGeometryProvider as l, ctm_to_container_transform as n, project_point_through_ctm as o, install_font_load_geometry_bump as r, Gestures as s, attach_dom_surface as t, Camera as u };
|
|
@@ -1224,44 +1224,32 @@ function create_attention_tracker(container) {
|
|
|
1224
1224
|
}
|
|
1225
1225
|
//#endregion
|
|
1226
1226
|
//#region src/text-surface.ts
|
|
1227
|
-
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
1228
1227
|
const XML_NS = "http://www.w3.org/XML/1998/namespace";
|
|
1229
1228
|
var SvgTextSurface = class {
|
|
1230
|
-
|
|
1229
|
+
/**
|
|
1230
|
+
* @param textEl the live text element to drive.
|
|
1231
|
+
* @param sink receives the caret + selection geometry (local space) on
|
|
1232
|
+
* every change; the host projects + forwards it to the HUD. Called with
|
|
1233
|
+
* `null` on dispose so the host clears the chrome.
|
|
1234
|
+
*/
|
|
1235
|
+
constructor(textEl, sink) {
|
|
1231
1236
|
this.prevXmlSpace = void 0;
|
|
1232
1237
|
this.prevPointerEvents = void 0;
|
|
1238
|
+
this.caret = null;
|
|
1239
|
+
this.selection = null;
|
|
1233
1240
|
this.last_caret_idx = -1;
|
|
1234
1241
|
this.last_caret_visible = false;
|
|
1235
1242
|
this.last_sel_start = -1;
|
|
1236
1243
|
this.last_sel_end = -1;
|
|
1237
1244
|
this.textEl = textEl;
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
while (mountAnchor.parentElement instanceof SVGElement && (mountAnchor.localName === "tspan" || mountAnchor.localName === "textPath")) mountAnchor = mountAnchor.parentElement;
|
|
1241
|
-
const parent = mountAnchor.parentNode;
|
|
1242
|
-
if (!parent) throw new Error("text element has no parent");
|
|
1243
|
-
const computedWhitespace = ownerDoc.defaultView?.getComputedStyle(textEl).whiteSpace;
|
|
1245
|
+
this.sink = sink;
|
|
1246
|
+
const computedWhitespace = textEl.ownerDocument.defaultView?.getComputedStyle(textEl).whiteSpace;
|
|
1244
1247
|
if (!(computedWhitespace === "pre" || computedWhitespace === "pre-wrap" || computedWhitespace === "break-spaces")) {
|
|
1245
1248
|
this.prevXmlSpace = textEl.getAttributeNS(XML_NS, "space");
|
|
1246
1249
|
textEl.setAttributeNS(XML_NS, "xml:space", "preserve");
|
|
1247
1250
|
}
|
|
1248
1251
|
this.prevPointerEvents = textEl.getAttribute("pointer-events");
|
|
1249
1252
|
textEl.setAttribute("pointer-events", "bounding-box");
|
|
1250
|
-
const selection = ownerDoc.createElementNS(SVG_NS, "rect");
|
|
1251
|
-
selection.setAttribute("fill", "#2563eb");
|
|
1252
|
-
selection.setAttribute("fill-opacity", "0.25");
|
|
1253
|
-
selection.setAttribute("pointer-events", "none");
|
|
1254
|
-
selection.setAttribute("data-svg-text-edit-selection", "");
|
|
1255
|
-
selection.style.display = "none";
|
|
1256
|
-
parent.insertBefore(selection, mountAnchor);
|
|
1257
|
-
this.selectionRect = selection;
|
|
1258
|
-
const caret = ownerDoc.createElementNS(SVG_NS, "rect");
|
|
1259
|
-
caret.setAttribute("fill", "#2563eb");
|
|
1260
|
-
caret.setAttribute("pointer-events", "none");
|
|
1261
|
-
caret.setAttribute("data-svg-text-edit-caret", "");
|
|
1262
|
-
caret.style.display = "none";
|
|
1263
|
-
parent.insertBefore(caret, mountAnchor.nextSibling);
|
|
1264
|
-
this.caretRect = caret;
|
|
1265
1253
|
}
|
|
1266
1254
|
setText(text) {
|
|
1267
1255
|
if (this.textEl.textContent !== text) this.textEl.textContent = text;
|
|
@@ -1270,38 +1258,43 @@ var SvgTextSurface = class {
|
|
|
1270
1258
|
if (index === this.last_caret_idx && visible === this.last_caret_visible) return;
|
|
1271
1259
|
this.last_caret_idx = index;
|
|
1272
1260
|
this.last_caret_visible = visible;
|
|
1273
|
-
if (!visible) {
|
|
1274
|
-
this.caretRect.style.display = "none";
|
|
1275
|
-
return;
|
|
1276
|
-
}
|
|
1277
1261
|
const m = this.metrics();
|
|
1278
1262
|
const x = this.charX(index);
|
|
1279
|
-
this.
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1263
|
+
this.caret = {
|
|
1264
|
+
top: [x, m.top],
|
|
1265
|
+
bottom: [x, m.top + m.height],
|
|
1266
|
+
visible
|
|
1267
|
+
};
|
|
1268
|
+
this.emit();
|
|
1284
1269
|
}
|
|
1285
1270
|
setSelection(start, end) {
|
|
1286
1271
|
if (start === this.last_sel_start && end === this.last_sel_end) return;
|
|
1287
1272
|
this.last_sel_start = start;
|
|
1288
1273
|
this.last_sel_end = end;
|
|
1289
1274
|
if (start === end) {
|
|
1290
|
-
this.
|
|
1275
|
+
this.selection = null;
|
|
1276
|
+
this.emit();
|
|
1291
1277
|
return;
|
|
1292
1278
|
}
|
|
1293
1279
|
const m = this.metrics();
|
|
1294
1280
|
const x1 = this.charX(start);
|
|
1295
1281
|
const x2 = this.charX(end);
|
|
1296
|
-
this.
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1282
|
+
this.selection = {
|
|
1283
|
+
x: Math.min(x1, x2),
|
|
1284
|
+
y: m.top,
|
|
1285
|
+
width: Math.abs(x2 - x1),
|
|
1286
|
+
height: m.height
|
|
1287
|
+
};
|
|
1288
|
+
this.emit();
|
|
1289
|
+
}
|
|
1290
|
+
emit() {
|
|
1291
|
+
this.sink({
|
|
1292
|
+
caret: this.caret,
|
|
1293
|
+
selection: this.selection
|
|
1294
|
+
});
|
|
1301
1295
|
}
|
|
1302
1296
|
dispose(keepEditMutations = false) {
|
|
1303
|
-
this.
|
|
1304
|
-
this.selectionRect.remove();
|
|
1297
|
+
this.sink(null);
|
|
1305
1298
|
if (this.prevXmlSpace !== void 0 && !keepEditMutations) if (this.prevXmlSpace === null) this.textEl.removeAttributeNS(XML_NS, "space");
|
|
1306
1299
|
else this.textEl.setAttributeNS(XML_NS, "xml:space", this.prevXmlSpace);
|
|
1307
1300
|
if (this.prevPointerEvents !== void 0) if (this.prevPointerEvents === null) this.textEl.removeAttribute("pointer-events");
|
|
@@ -1925,6 +1918,7 @@ var DomSurface = class DomSurface {
|
|
|
1925
1918
|
this.text_edit = null;
|
|
1926
1919
|
this.text_edit_target = null;
|
|
1927
1920
|
this.text_edit_original = "";
|
|
1921
|
+
this.text_edit_geom = null;
|
|
1928
1922
|
this.pending_text_insert = null;
|
|
1929
1923
|
this.vector_edit = null;
|
|
1930
1924
|
this.point_snap_guide = void 0;
|
|
@@ -2069,6 +2063,7 @@ var DomSurface = class DomSurface {
|
|
|
2069
2063
|
this.apply_camera_transform();
|
|
2070
2064
|
this.hud.setPixelGridTransform(this.camera.transform);
|
|
2071
2065
|
this.sync_surface_selection();
|
|
2066
|
+
if (this.text_edit_geom) this.push_text_edit_chrome(this.text_edit_geom);
|
|
2072
2067
|
this.redraw();
|
|
2073
2068
|
}));
|
|
2074
2069
|
this.render();
|
|
@@ -4076,7 +4071,10 @@ var DomSurface = class DomSurface {
|
|
|
4076
4071
|
this.sync_surface_selection();
|
|
4077
4072
|
this.sync_cursor();
|
|
4078
4073
|
this.redraw();
|
|
4079
|
-
const text_surface = new SvgTextSurface(this.element_index.get(id) ?? el)
|
|
4074
|
+
const text_surface = new SvgTextSurface(this.element_index.get(id) ?? el, (geom) => {
|
|
4075
|
+
this.push_text_edit_chrome(geom);
|
|
4076
|
+
this.request_redraw();
|
|
4077
|
+
});
|
|
4080
4078
|
const is_mac = typeof navigator !== "undefined" && /Mac|iPod|iPhone|iPad/.test(navigator.userAgent);
|
|
4081
4079
|
let settled = false;
|
|
4082
4080
|
this.text_edit = (0, _grida_text_editor_dom.createTextEditor)({
|
|
@@ -4124,11 +4122,45 @@ var DomSurface = class DomSurface {
|
|
|
4124
4122
|
this.render();
|
|
4125
4123
|
this.sync_surface_selection();
|
|
4126
4124
|
this.sync_cursor();
|
|
4125
|
+
this.push_text_edit_chrome(null);
|
|
4127
4126
|
this.redraw();
|
|
4128
4127
|
this.text_edit = null;
|
|
4129
4128
|
this.text_edit_target = null;
|
|
4130
4129
|
}
|
|
4131
4130
|
/**
|
|
4131
|
+
* Project the active session's text-edit geometry (LOCAL svg user-space) and
|
|
4132
|
+
* push it to the HUD as text-edit chrome (caret + selection), or clear it on
|
|
4133
|
+
* `null`. The local→container-px transform comes from the live text
|
|
4134
|
+
* element's `getScreenCTM` (which folds in the camera's CSS transform on the
|
|
4135
|
+
* SVG root) minus the container offset — the same projection convention
|
|
4136
|
+
* `vector_of` / `container_box` use. The HUD keeps its own transform at
|
|
4137
|
+
* identity, so this per-chrome transform is the whole projection. Does NOT
|
|
4138
|
+
* redraw — callers own that.
|
|
4139
|
+
*/
|
|
4140
|
+
push_text_edit_chrome(geom) {
|
|
4141
|
+
this.text_edit_geom = geom;
|
|
4142
|
+
if (!geom) {
|
|
4143
|
+
this.hud.setTextEditChrome(null);
|
|
4144
|
+
return;
|
|
4145
|
+
}
|
|
4146
|
+
const ctm = (this.text_edit_target ? this.element_index.get(this.text_edit_target) : void 0)?.getScreenCTM?.() ?? null;
|
|
4147
|
+
if (!ctm) {
|
|
4148
|
+
this.hud.setTextEditChrome(null);
|
|
4149
|
+
return;
|
|
4150
|
+
}
|
|
4151
|
+
const input = {
|
|
4152
|
+
transform: ctm_to_container_transform(ctm, this.container_offset()),
|
|
4153
|
+
caret: geom.caret ? {
|
|
4154
|
+
top: geom.caret.top,
|
|
4155
|
+
bottom: geom.caret.bottom
|
|
4156
|
+
} : void 0,
|
|
4157
|
+
caretVisible: geom.caret?.visible ?? false,
|
|
4158
|
+
selectionRects: geom.selection ? [geom.selection] : void 0,
|
|
4159
|
+
style: { caretColor: "#000000" }
|
|
4160
|
+
};
|
|
4161
|
+
this.hud.setTextEditChrome(input);
|
|
4162
|
+
}
|
|
4163
|
+
/**
|
|
4132
4164
|
* Realize the result of a text content-edit session and exit. `result`
|
|
4133
4165
|
* is the text that should remain — the typed text on commit, the original
|
|
4134
4166
|
* on cancel. Implements the empty-equals-delete rule (design:
|
|
@@ -4947,6 +4979,25 @@ function project_point_through_ctm(px, py, ctm, container_offset) {
|
|
|
4947
4979
|
return [sx + container_offset[0], sy + container_offset[1]];
|
|
4948
4980
|
}
|
|
4949
4981
|
/**
|
|
4982
|
+
* The matrix form of {@link project_point_through_ctm}: the full
|
|
4983
|
+
* `local → container-px` affine for a CTM + container offset, as a
|
|
4984
|
+
* `cmath.Transform`. Use when handing the transform to a downstream projector
|
|
4985
|
+
* (e.g. HUD chrome) instead of projecting a single point.
|
|
4986
|
+
*
|
|
4987
|
+
* Pure function, no DOM types.
|
|
4988
|
+
*/
|
|
4989
|
+
function ctm_to_container_transform(ctm, container_offset) {
|
|
4990
|
+
return [[
|
|
4991
|
+
ctm.a,
|
|
4992
|
+
ctm.c,
|
|
4993
|
+
ctm.e + container_offset[0]
|
|
4994
|
+
], [
|
|
4995
|
+
ctm.b,
|
|
4996
|
+
ctm.d,
|
|
4997
|
+
ctm.f + container_offset[1]
|
|
4998
|
+
]];
|
|
4999
|
+
}
|
|
5000
|
+
/**
|
|
4950
5001
|
* Inverse of the CTM's linear part applied to a delta vector. Drops
|
|
4951
5002
|
* translation. Used to convert a HUD-reported container-space drag delta
|
|
4952
5003
|
* back to the path's local coord space for `PathModel.translateVertices`.
|
|
@@ -5252,6 +5303,12 @@ Object.defineProperty(exports, "attach_dom_surface", {
|
|
|
5252
5303
|
return attach_dom_surface;
|
|
5253
5304
|
}
|
|
5254
5305
|
});
|
|
5306
|
+
Object.defineProperty(exports, "ctm_to_container_transform", {
|
|
5307
|
+
enumerable: true,
|
|
5308
|
+
get: function() {
|
|
5309
|
+
return ctm_to_container_transform;
|
|
5310
|
+
}
|
|
5311
|
+
});
|
|
5255
5312
|
Object.defineProperty(exports, "install_font_load_geometry_bump", {
|
|
5256
5313
|
enumerable: true,
|
|
5257
5314
|
get: function() {
|
|
@@ -196,6 +196,22 @@ declare function project_point_through_ctm(px: number, py: number, ctm: {
|
|
|
196
196
|
e: number;
|
|
197
197
|
f: number;
|
|
198
198
|
}, container_offset: readonly [number, number]): [number, number];
|
|
199
|
+
/**
|
|
200
|
+
* The matrix form of {@link project_point_through_ctm}: the full
|
|
201
|
+
* `local → container-px` affine for a CTM + container offset, as a
|
|
202
|
+
* `cmath.Transform`. Use when handing the transform to a downstream projector
|
|
203
|
+
* (e.g. HUD chrome) instead of projecting a single point.
|
|
204
|
+
*
|
|
205
|
+
* Pure function, no DOM types.
|
|
206
|
+
*/
|
|
207
|
+
declare function ctm_to_container_transform(ctm: {
|
|
208
|
+
a: number;
|
|
209
|
+
b: number;
|
|
210
|
+
c: number;
|
|
211
|
+
d: number;
|
|
212
|
+
e: number;
|
|
213
|
+
f: number;
|
|
214
|
+
}, container_offset: readonly [number, number]): cmath.Transform;
|
|
199
215
|
/**
|
|
200
216
|
* Inverse of the CTM's linear part applied to a delta vector. Drops
|
|
201
217
|
* translation. Used to convert a HUD-reported container-space drag delta
|
|
@@ -234,4 +250,4 @@ declare function inverse_project_rect(rect: {
|
|
|
234
250
|
f: number;
|
|
235
251
|
}, offset: readonly [number, number]): cmath.Rectangle | null;
|
|
236
252
|
//#endregion
|
|
237
|
-
export {
|
|
253
|
+
export { ctm_to_container_transform as a, project_delta_inverse_ctm as c, SnapOptions as d, attach_dom_surface as i, project_point_through_ctm as l, DomSurfaceHandle as n, install_font_load_geometry_bump as o, DomSurfaceOptions as r, inverse_project_rect as s, AttentionScope as t, DEFAULT_SNAP_OPTIONS as u };
|
package/dist/dom.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { C as BoundsResolver, E as CameraOptions, T as CameraConstraints, d as GestureContext, f as GestureId, g as MemoizedGeometryProvider, h as GeometrySignals, i as DomComputedResolver, m as GeometryProvider, p as Gestures, r as DomComputedPaint, u as GestureBinding, w as Camera } from "./editor-CcW4BVth.mjs";
|
|
2
|
-
import { a as
|
|
3
|
-
export { AttentionScope, type BoundsResolver, Camera, type CameraConstraints, type CameraOptions, DEFAULT_SNAP_OPTIONS, type DomComputedPaint, type DomComputedResolver, DomSurfaceHandle, DomSurfaceOptions, type GeometryProvider, type GeometrySignals, type GestureBinding, type GestureContext, type GestureId, Gestures, MemoizedGeometryProvider, type SnapOptions, attach_dom_surface, install_font_load_geometry_bump, inverse_project_rect, project_delta_inverse_ctm, project_point_through_ctm };
|
|
2
|
+
import { a as ctm_to_container_transform, c as project_delta_inverse_ctm, d as SnapOptions, i as attach_dom_surface, l as project_point_through_ctm, n as DomSurfaceHandle, o as install_font_load_geometry_bump, r as DomSurfaceOptions, s as inverse_project_rect, t as AttentionScope, u as DEFAULT_SNAP_OPTIONS } from "./dom-D-ZJO9aK.mjs";
|
|
3
|
+
export { AttentionScope, type BoundsResolver, Camera, type CameraConstraints, type CameraOptions, DEFAULT_SNAP_OPTIONS, type DomComputedPaint, type DomComputedResolver, DomSurfaceHandle, DomSurfaceOptions, type GeometryProvider, type GeometrySignals, type GestureBinding, type GestureContext, type GestureId, Gestures, MemoizedGeometryProvider, type SnapOptions, attach_dom_surface, ctm_to_container_transform, install_font_load_geometry_bump, inverse_project_rect, project_delta_inverse_ctm, project_point_through_ctm };
|
package/dist/dom.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { C as BoundsResolver, E as CameraOptions, T as CameraConstraints, d as GestureContext, f as GestureId, g as MemoizedGeometryProvider, h as GeometrySignals, i as DomComputedResolver, m as GeometryProvider, p as Gestures, r as DomComputedPaint, u as GestureBinding, w as Camera } from "./editor-CxqRhhzP.js";
|
|
2
|
-
import { a as
|
|
3
|
-
export { AttentionScope, type BoundsResolver, Camera, type CameraConstraints, type CameraOptions, DEFAULT_SNAP_OPTIONS, type DomComputedPaint, type DomComputedResolver, DomSurfaceHandle, DomSurfaceOptions, type GeometryProvider, type GeometrySignals, type GestureBinding, type GestureContext, type GestureId, Gestures, MemoizedGeometryProvider, type SnapOptions, attach_dom_surface, install_font_load_geometry_bump, inverse_project_rect, project_delta_inverse_ctm, project_point_through_ctm };
|
|
2
|
+
import { a as ctm_to_container_transform, c as project_delta_inverse_ctm, d as SnapOptions, i as attach_dom_surface, l as project_point_through_ctm, n as DomSurfaceHandle, o as install_font_load_geometry_bump, r as DomSurfaceOptions, s as inverse_project_rect, t as AttentionScope, u as DEFAULT_SNAP_OPTIONS } from "./dom-Dl56kUW5.js";
|
|
3
|
+
export { AttentionScope, type BoundsResolver, Camera, type CameraConstraints, type CameraOptions, DEFAULT_SNAP_OPTIONS, type DomComputedPaint, type DomComputedResolver, DomSurfaceHandle, DomSurfaceOptions, type GeometryProvider, type GeometrySignals, type GestureBinding, type GestureContext, type GestureId, Gestures, MemoizedGeometryProvider, type SnapOptions, attach_dom_surface, ctm_to_container_transform, install_font_load_geometry_bump, inverse_project_rect, project_delta_inverse_ctm, project_point_through_ctm };
|
package/dist/dom.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_dom = require("./dom-
|
|
2
|
+
const require_dom = require("./dom-Disackua.js");
|
|
3
3
|
exports.Camera = require_dom.Camera;
|
|
4
4
|
exports.DEFAULT_SNAP_OPTIONS = require_dom.DEFAULT_SNAP_OPTIONS;
|
|
5
5
|
exports.Gestures = require_dom.Gestures;
|
|
6
6
|
exports.MemoizedGeometryProvider = require_dom.MemoizedGeometryProvider;
|
|
7
7
|
exports.attach_dom_surface = require_dom.attach_dom_surface;
|
|
8
|
+
exports.ctm_to_container_transform = require_dom.ctm_to_container_transform;
|
|
8
9
|
exports.install_font_load_geometry_bump = require_dom.install_font_load_geometry_bump;
|
|
9
10
|
exports.inverse_project_rect = require_dom.inverse_project_rect;
|
|
10
11
|
exports.project_delta_inverse_ctm = require_dom.project_delta_inverse_ctm;
|
package/dist/dom.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { Camera, DEFAULT_SNAP_OPTIONS, Gestures, MemoizedGeometryProvider, attach_dom_surface, install_font_load_geometry_bump, inverse_project_rect, project_delta_inverse_ctm, project_point_through_ctm };
|
|
1
|
+
import { a as project_delta_inverse_ctm, c as DEFAULT_SNAP_OPTIONS, i as inverse_project_rect, l as MemoizedGeometryProvider, n as ctm_to_container_transform, o as project_point_through_ctm, r as install_font_load_geometry_bump, s as Gestures, t as attach_dom_surface, u as Camera } from "./dom-DVxR7PNh.mjs";
|
|
2
|
+
export { Camera, DEFAULT_SNAP_OPTIONS, Gestures, MemoizedGeometryProvider, attach_dom_surface, ctm_to_container_transform, install_font_load_geometry_bump, inverse_project_rect, project_delta_inverse_ctm, project_point_through_ctm };
|
package/dist/presets.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as SvgEditor } from "./editor-CcW4BVth.mjs";
|
|
2
|
-
import { n as DomSurfaceHandle, r as DomSurfaceOptions } from "./dom-
|
|
2
|
+
import { n as DomSurfaceHandle, r as DomSurfaceOptions } from "./dom-D-ZJO9aK.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/presets/keynote.d.ts
|
|
5
5
|
declare namespace keynote_d_exports {
|
package/dist/presets.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as SvgEditor } from "./editor-CxqRhhzP.js";
|
|
2
|
-
import { n as DomSurfaceHandle, r as DomSurfaceOptions } from "./dom-
|
|
2
|
+
import { n as DomSurfaceHandle, r as DomSurfaceOptions } from "./dom-Dl56kUW5.js";
|
|
3
3
|
|
|
4
4
|
//#region \0rolldown/runtime.js
|
|
5
5
|
declare namespace keynote_d_exports {
|
package/dist/presets.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_model = require("./model-HEKGO-56.js");
|
|
3
|
-
const require_dom = require("./dom-
|
|
3
|
+
const require_dom = require("./dom-Disackua.js");
|
|
4
4
|
//#region src/presets/keynote.ts
|
|
5
5
|
var keynote_exports = /* @__PURE__ */ require_model.__exportAll({ attach: () => attach });
|
|
6
6
|
/**
|
package/dist/presets.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-D7D4PA-g.mjs";
|
|
2
|
-
import { t as attach_dom_surface } from "./dom-
|
|
2
|
+
import { t as attach_dom_surface } from "./dom-DVxR7PNh.mjs";
|
|
3
3
|
//#region src/presets/keynote.ts
|
|
4
4
|
var keynote_exports = /* @__PURE__ */ __exportAll({ attach: () => attach });
|
|
5
5
|
/**
|
package/dist/react.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A as EditorState, H as Mode, J as PickEvent, K as PaintPreviewSession, Q as Providers, U as NodeId, Y as PreviewSession, c as SvgEditor, j as EditorStyle, rt as Tool, t as Commands } from "./editor-CcW4BVth.mjs";
|
|
2
|
-
import { n as DomSurfaceHandle } from "./dom-
|
|
2
|
+
import { n as DomSurfaceHandle } from "./dom-D-ZJO9aK.mjs";
|
|
3
3
|
import cmath from "@grida/cmath";
|
|
4
4
|
import { ReactNode } from "react";
|
|
5
5
|
|
package/dist/react.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A as EditorState, H as Mode, J as PickEvent, K as PaintPreviewSession, Q as Providers, U as NodeId, Y as PreviewSession, c as SvgEditor, j as EditorStyle, rt as Tool, t as Commands } from "./editor-CxqRhhzP.js";
|
|
2
|
-
import { n as DomSurfaceHandle } from "./dom-
|
|
2
|
+
import { n as DomSurfaceHandle } from "./dom-Dl56kUW5.js";
|
|
3
3
|
import cmath from "@grida/cmath";
|
|
4
4
|
import { ReactNode } from "react";
|
|
5
5
|
|
package/dist/react.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const require_editor = require("./editor-DFvojUwn.js");
|
|
4
|
-
const require_dom = require("./dom-
|
|
4
|
+
const require_dom = require("./dom-Disackua.js");
|
|
5
5
|
let react = require("react");
|
|
6
6
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
7
7
|
//#region src/react.tsx
|
package/dist/react.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { t as createSvgEditor } from "./editor-DCDQl18y.mjs";
|
|
3
|
-
import { t as attach_dom_surface } from "./dom-
|
|
3
|
+
import { t as attach_dom_surface } from "./dom-DVxR7PNh.mjs";
|
|
4
4
|
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useSyncExternalStore } from "react";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
//#region src/react.tsx
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grida/svg-editor",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.23",
|
|
4
4
|
"description": "Headless SVG editor (experimental).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bezier",
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"@grida/cmath": "0.2.3",
|
|
62
62
|
"@grida/color": "0.1.0",
|
|
63
63
|
"@grida/history": "0.1.2",
|
|
64
|
-
"@grida/
|
|
65
|
-
"@grida/hud": "0.2.4",
|
|
66
|
-
"@grida/svg": "0.2.0",
|
|
64
|
+
"@grida/vn": "0.1.0",
|
|
67
65
|
"@grida/text-editor": "0.1.2",
|
|
68
|
-
"@grida/
|
|
66
|
+
"@grida/hud": "0.3.0",
|
|
67
|
+
"@grida/keybinding": "0.2.1",
|
|
68
|
+
"@grida/svg": "0.2.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/react": "^19",
|