@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 CHANGED
@@ -39,6 +39,10 @@ Notable options beyond the basics:
39
39
  host can suppress its own validation display mid-edit.
40
40
  - `messages: false` — hide the editor's internal validation list when the host
41
41
  renders its own.
42
+ - `popoverContainer` — where the popover micro-editors mount (default
43
+ `document.body`). Pass a container inside a focus-trapping dialog (Radix,
44
+ etc.) so opening a pill's popover counts as "inside" that layer and does not
45
+ dismiss the dialog; the popover is then positioned relative to that container.
42
46
  - `setText(on)` — the host's raw-text toggle (`</>`); unparseable input falls
43
47
  back to raw text automatically.
44
48
 
package/dist/index.cjs CHANGED
@@ -312,7 +312,8 @@ function button(cls, label, onClick, title) {
312
312
  b.addEventListener("click", onClick);
313
313
  return b;
314
314
  }
315
- function openPopover(anchor, render, onClose) {
315
+ function openPopover(anchor, render, opts = {}) {
316
+ const container = opts.container ?? document.body;
316
317
  const pop = el("div", "exed-pop");
317
318
  let closed = false;
318
319
  const close = () => {
@@ -321,7 +322,7 @@ function openPopover(anchor, render, onClose) {
321
322
  document.removeEventListener("pointerdown", onDown, true);
322
323
  document.removeEventListener("keydown", onKey, true);
323
324
  pop.remove();
324
- onClose?.();
325
+ opts.onClose?.();
325
326
  };
326
327
  const onDown = (e) => {
327
328
  const t = e.target;
@@ -334,15 +335,21 @@ function openPopover(anchor, render, onClose) {
334
335
  }
335
336
  };
336
337
  pop.append(render(close));
337
- document.body.append(pop);
338
+ container.append(pop);
338
339
  const a = anchor.getBoundingClientRect();
339
340
  const ph = pop.getBoundingClientRect();
340
341
  let top = a.bottom + 4;
341
342
  if (top + ph.height > window.innerHeight - 8 && a.top - ph.height - 4 > 8) top = a.top - ph.height - 4;
342
343
  let left = a.left;
343
344
  if (left + ph.width > window.innerWidth - 8) left = Math.max(8, window.innerWidth - 8 - ph.width);
344
- pop.style.top = `${Math.round(top + window.scrollY)}px`;
345
- pop.style.left = `${Math.round(left + window.scrollX)}px`;
345
+ if (container === document.body) {
346
+ pop.style.top = `${Math.round(top + window.scrollY)}px`;
347
+ pop.style.left = `${Math.round(left + window.scrollX)}px`;
348
+ } else {
349
+ const cr = container.getBoundingClientRect();
350
+ pop.style.top = `${Math.round(top - cr.top + container.scrollTop)}px`;
351
+ pop.style.left = `${Math.round(left - cr.left + container.scrollLeft)}px`;
352
+ }
346
353
  setTimeout(() => {
347
354
  document.addEventListener("pointerdown", onDown, true);
348
355
  document.addEventListener("keydown", onKey, true);
@@ -1039,9 +1046,12 @@ function mountExpressionEditor(host, opts) {
1039
1046
  apply: (next) => emit(toSrc(next)),
1040
1047
  openPopover: (anchor, r) => {
1041
1048
  closePopover();
1042
- const pop = openPopover(anchor, r, () => {
1043
- if (activePopover === pop) activePopover = null;
1044
- setEditing(false);
1049
+ const pop = openPopover(anchor, r, {
1050
+ container: opts.popoverContainer,
1051
+ onClose: () => {
1052
+ if (activePopover === pop) activePopover = null;
1053
+ setEditing(false);
1054
+ }
1045
1055
  });
1046
1056
  activePopover = pop;
1047
1057
  setEditing(true);
@@ -1333,7 +1343,7 @@ function mountEffectsEditor(host, opts) {
1333
1343
  close();
1334
1344
  },
1335
1345
  onCancel: close
1336
- }));
1346
+ }), { container: opts.popoverContainer });
1337
1347
  };
1338
1348
  const targetType = (target) => opts.catalogue.find((e) => refOf(e, defaultScope) === target)?.type;
1339
1349
  const valueDisplay = (value, onChange, type) => {
@@ -1348,6 +1358,7 @@ function mountEffectsEditor(host, opts) {
1348
1358
  functions: opts.functions,
1349
1359
  mode: "flat",
1350
1360
  ...addTerm ? { addTerm } : {},
1361
+ ...opts.popoverContainer ? { popoverContainer: opts.popoverContainer } : {},
1351
1362
  text: textMode,
1352
1363
  onChange
1353
1364
  }));
@@ -1387,7 +1398,7 @@ function mountEffectsEditor(host, opts) {
1387
1398
  wrap.append(search, list);
1388
1399
  setTimeout(() => search.focus(), 0);
1389
1400
  return wrap;
1390
- });
1401
+ }, { container: opts.popoverContainer });
1391
1402
  };
1392
1403
  const iconBtn = (glyph, title, onClick, danger = false) => button(`exed-eff-icon${danger ? " danger" : ""}`, glyph, onClick, title);
1393
1404
  function setRow(eff, i) {
@@ -1460,7 +1471,7 @@ function mountEffectsEditor(host, opts) {
1460
1471
  wrap.append(button("exed-btn primary", "Apply", apply));
1461
1472
  setTimeout(() => input.focus(), 0);
1462
1473
  return wrap;
1463
- });
1474
+ }, { container: opts.popoverContainer });
1464
1475
  };
1465
1476
  const rowActions2 = (i) => {
1466
1477
  const acts = el("div", "exed-effect-acts");