@wildwinter/expr-editor 0.2.0 → 0.3.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/README.md +4 -0
- package/dist/index.cjs +22 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +22 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -254,6 +254,10 @@ interface ExpressionEditorOptions {
|
|
|
254
254
|
/** Render the editor's own validation message list under the pills (default true).
|
|
255
255
|
* Hosts that display their own validation messages pass false to avoid doubling up. */
|
|
256
256
|
messages?: boolean;
|
|
257
|
+
/** Where to append the popover micro-editors (default document.body). Pass a
|
|
258
|
+
* container inside a focus-trapping dialog (Radix, etc.) so opening a pill's
|
|
259
|
+
* popover does not dismiss the surrounding dialog. */
|
|
260
|
+
popoverContainer?: HTMLElement;
|
|
257
261
|
/** Emitted on every edit (name-form; "" when cleared). */
|
|
258
262
|
onChange: (src: string) => void;
|
|
259
263
|
/** Notified when the author starts (true) / stops (false) editing inside a popover
|
|
@@ -296,6 +300,10 @@ interface EffectsEditorOptions {
|
|
|
296
300
|
allowEmit?: boolean;
|
|
297
301
|
/** Start each inline value editor in raw-text mode (host's global "show as text" toggle drives this). */
|
|
298
302
|
text?: boolean;
|
|
303
|
+
/** Where to append popover micro-editors (default document.body). Pass a container
|
|
304
|
+
* inside a focus-trapping dialog so popovers do not dismiss it. Threaded to the
|
|
305
|
+
* target/event pickers here and to every inline value editor. */
|
|
306
|
+
popoverContainer?: HTMLElement;
|
|
299
307
|
/** Emitted on every structural / value edit with the whole new list. */
|
|
300
308
|
onChange: (effects: EditorEffect[]) => void;
|
|
301
309
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -254,6 +254,10 @@ interface ExpressionEditorOptions {
|
|
|
254
254
|
/** Render the editor's own validation message list under the pills (default true).
|
|
255
255
|
* Hosts that display their own validation messages pass false to avoid doubling up. */
|
|
256
256
|
messages?: boolean;
|
|
257
|
+
/** Where to append the popover micro-editors (default document.body). Pass a
|
|
258
|
+
* container inside a focus-trapping dialog (Radix, etc.) so opening a pill's
|
|
259
|
+
* popover does not dismiss the surrounding dialog. */
|
|
260
|
+
popoverContainer?: HTMLElement;
|
|
257
261
|
/** Emitted on every edit (name-form; "" when cleared). */
|
|
258
262
|
onChange: (src: string) => void;
|
|
259
263
|
/** Notified when the author starts (true) / stops (false) editing inside a popover
|
|
@@ -296,6 +300,10 @@ interface EffectsEditorOptions {
|
|
|
296
300
|
allowEmit?: boolean;
|
|
297
301
|
/** Start each inline value editor in raw-text mode (host's global "show as text" toggle drives this). */
|
|
298
302
|
text?: boolean;
|
|
303
|
+
/** Where to append popover micro-editors (default document.body). Pass a container
|
|
304
|
+
* inside a focus-trapping dialog so popovers do not dismiss it. Threaded to the
|
|
305
|
+
* target/event pickers here and to every inline value editor. */
|
|
306
|
+
popoverContainer?: HTMLElement;
|
|
299
307
|
/** Emitted on every structural / value edit with the whole new list. */
|
|
300
308
|
onChange: (effects: EditorEffect[]) => void;
|
|
301
309
|
}
|
package/dist/index.js
CHANGED
|
@@ -310,7 +310,8 @@ function button(cls, label, onClick, title) {
|
|
|
310
310
|
b.addEventListener("click", onClick);
|
|
311
311
|
return b;
|
|
312
312
|
}
|
|
313
|
-
function openPopover(anchor, render,
|
|
313
|
+
function openPopover(anchor, render, opts = {}) {
|
|
314
|
+
const container = opts.container ?? document.body;
|
|
314
315
|
const pop = el("div", "exed-pop");
|
|
315
316
|
let closed = false;
|
|
316
317
|
const close = () => {
|
|
@@ -319,7 +320,7 @@ function openPopover(anchor, render, onClose) {
|
|
|
319
320
|
document.removeEventListener("pointerdown", onDown, true);
|
|
320
321
|
document.removeEventListener("keydown", onKey, true);
|
|
321
322
|
pop.remove();
|
|
322
|
-
onClose?.();
|
|
323
|
+
opts.onClose?.();
|
|
323
324
|
};
|
|
324
325
|
const onDown = (e) => {
|
|
325
326
|
const t = e.target;
|
|
@@ -332,15 +333,21 @@ function openPopover(anchor, render, onClose) {
|
|
|
332
333
|
}
|
|
333
334
|
};
|
|
334
335
|
pop.append(render(close));
|
|
335
|
-
|
|
336
|
+
container.append(pop);
|
|
336
337
|
const a = anchor.getBoundingClientRect();
|
|
337
338
|
const ph = pop.getBoundingClientRect();
|
|
338
339
|
let top = a.bottom + 4;
|
|
339
340
|
if (top + ph.height > window.innerHeight - 8 && a.top - ph.height - 4 > 8) top = a.top - ph.height - 4;
|
|
340
341
|
let left = a.left;
|
|
341
342
|
if (left + ph.width > window.innerWidth - 8) left = Math.max(8, window.innerWidth - 8 - ph.width);
|
|
342
|
-
|
|
343
|
-
|
|
343
|
+
if (container === document.body) {
|
|
344
|
+
pop.style.top = `${Math.round(top + window.scrollY)}px`;
|
|
345
|
+
pop.style.left = `${Math.round(left + window.scrollX)}px`;
|
|
346
|
+
} else {
|
|
347
|
+
const cr = container.getBoundingClientRect();
|
|
348
|
+
pop.style.top = `${Math.round(top - cr.top + container.scrollTop)}px`;
|
|
349
|
+
pop.style.left = `${Math.round(left - cr.left + container.scrollLeft)}px`;
|
|
350
|
+
}
|
|
344
351
|
setTimeout(() => {
|
|
345
352
|
document.addEventListener("pointerdown", onDown, true);
|
|
346
353
|
document.addEventListener("keydown", onKey, true);
|
|
@@ -1037,9 +1044,12 @@ function mountExpressionEditor(host, opts) {
|
|
|
1037
1044
|
apply: (next) => emit(toSrc(next)),
|
|
1038
1045
|
openPopover: (anchor, r) => {
|
|
1039
1046
|
closePopover();
|
|
1040
|
-
const pop = openPopover(anchor, r,
|
|
1041
|
-
|
|
1042
|
-
|
|
1047
|
+
const pop = openPopover(anchor, r, {
|
|
1048
|
+
container: opts.popoverContainer,
|
|
1049
|
+
onClose: () => {
|
|
1050
|
+
if (activePopover === pop) activePopover = null;
|
|
1051
|
+
setEditing(false);
|
|
1052
|
+
}
|
|
1043
1053
|
});
|
|
1044
1054
|
activePopover = pop;
|
|
1045
1055
|
setEditing(true);
|
|
@@ -1331,7 +1341,7 @@ function mountEffectsEditor(host, opts) {
|
|
|
1331
1341
|
close();
|
|
1332
1342
|
},
|
|
1333
1343
|
onCancel: close
|
|
1334
|
-
}));
|
|
1344
|
+
}), { container: opts.popoverContainer });
|
|
1335
1345
|
};
|
|
1336
1346
|
const targetType = (target) => opts.catalogue.find((e) => refOf(e, defaultScope) === target)?.type;
|
|
1337
1347
|
const valueDisplay = (value, onChange, type) => {
|
|
@@ -1346,6 +1356,7 @@ function mountEffectsEditor(host, opts) {
|
|
|
1346
1356
|
functions: opts.functions,
|
|
1347
1357
|
mode: "flat",
|
|
1348
1358
|
...addTerm ? { addTerm } : {},
|
|
1359
|
+
...opts.popoverContainer ? { popoverContainer: opts.popoverContainer } : {},
|
|
1349
1360
|
text: textMode,
|
|
1350
1361
|
onChange
|
|
1351
1362
|
}));
|
|
@@ -1385,7 +1396,7 @@ function mountEffectsEditor(host, opts) {
|
|
|
1385
1396
|
wrap.append(search, list);
|
|
1386
1397
|
setTimeout(() => search.focus(), 0);
|
|
1387
1398
|
return wrap;
|
|
1388
|
-
});
|
|
1399
|
+
}, { container: opts.popoverContainer });
|
|
1389
1400
|
};
|
|
1390
1401
|
const iconBtn = (glyph, title, onClick, danger = false) => button(`exed-eff-icon${danger ? " danger" : ""}`, glyph, onClick, title);
|
|
1391
1402
|
function setRow(eff, i) {
|
|
@@ -1458,7 +1469,7 @@ function mountEffectsEditor(host, opts) {
|
|
|
1458
1469
|
wrap.append(button("exed-btn primary", "Apply", apply));
|
|
1459
1470
|
setTimeout(() => input.focus(), 0);
|
|
1460
1471
|
return wrap;
|
|
1461
|
-
});
|
|
1472
|
+
}, { container: opts.popoverContainer });
|
|
1462
1473
|
};
|
|
1463
1474
|
const rowActions2 = (i) => {
|
|
1464
1475
|
const acts = el("div", "exed-effect-acts");
|