@drghaliasri/butex 5.5.0 → 5.5.2

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/index.d.mts CHANGED
@@ -1441,6 +1441,7 @@ type RuntimeButtonElements = {
1441
1441
  };
1442
1442
  type EditorRuntimeOptions = {
1443
1443
  surfaceEl: HTMLElement;
1444
+ inputEl?: HTMLTextAreaElement | null;
1444
1445
  initialSession?: EditorSession;
1445
1446
  defaultSide?: EditorSide;
1446
1447
  uiLocale?: ButexUiLocale;
@@ -1454,6 +1455,7 @@ type EditorRuntimeApi = {
1454
1455
  getSession: () => EditorSession;
1455
1456
  setSession: (next: EditorSession) => void;
1456
1457
  setUiLocale: (locale: ButexUiLocale) => void;
1458
+ focusInput: () => void;
1457
1459
  performUndo: () => void;
1458
1460
  performRedo: () => void;
1459
1461
  performCopy: () => Promise<void>;
package/dist/index.d.ts CHANGED
@@ -1441,6 +1441,7 @@ type RuntimeButtonElements = {
1441
1441
  };
1442
1442
  type EditorRuntimeOptions = {
1443
1443
  surfaceEl: HTMLElement;
1444
+ inputEl?: HTMLTextAreaElement | null;
1444
1445
  initialSession?: EditorSession;
1445
1446
  defaultSide?: EditorSide;
1446
1447
  uiLocale?: ButexUiLocale;
@@ -1454,6 +1455,7 @@ type EditorRuntimeApi = {
1454
1455
  getSession: () => EditorSession;
1455
1456
  setSession: (next: EditorSession) => void;
1456
1457
  setUiLocale: (locale: ButexUiLocale) => void;
1458
+ focusInput: () => void;
1457
1459
  performUndo: () => void;
1458
1460
  performRedo: () => void;
1459
1461
  performCopy: () => Promise<void>;
@@ -2645,7 +2645,8 @@ ${BUTEX_FONT_FACE_CSS}
2645
2645
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
2646
2646
  }
2647
2647
 
2648
- .surface:focus {
2648
+ .surface:focus,
2649
+ .surface.surface--typing-focus {
2649
2650
  border-color: var(--butex-focus-border, rgba(13, 148, 136, 0.45));
2650
2651
  box-shadow: 0 0 0 3px var(--butex-focus-shadow, rgba(13, 148, 136, 0.12));
2651
2652
  }
@@ -3384,7 +3385,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
3384
3385
  return arabicScripts(node, content, options);
3385
3386
  }
3386
3387
  if (node.kind === "sqrt" && node.radicand) {
3387
- const content = `\\arabsqrt${optionalRootIndexArabic(node, options)}{${renderChainArabic(node.radicand, options)}}`;
3388
+ const content = `\\arsqrt${optionalRootIndexArabic(node, options)}{${renderChainArabic(node.radicand, options)}}`;
3388
3389
  return arabicScripts(node, content, options);
3389
3390
  }
3390
3391
  if (node.kind === "overset" && node.baseExpr) {
@@ -5792,7 +5793,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
5792
5793
 
5793
5794
  // src/editor/runtime.ts
5794
5795
  function createEditorRuntime(options) {
5795
- const { surfaceEl } = options;
5796
+ const { surfaceEl, inputEl } = options;
5796
5797
  const buttonElements = options.buttonElements ?? {};
5797
5798
  const outsidePointerIgnoreSelectors = options.outsidePointerIgnoreSelectors ?? [];
5798
5799
  let session = options.initialSession ?? createStarterSession();
@@ -5806,6 +5807,23 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
5806
5807
  let dragSelecting = false;
5807
5808
  let dragChainId = null;
5808
5809
  let dragChanged = false;
5810
+ let composingInput = false;
5811
+ let pendingCompositionText = null;
5812
+ function resetInputElement() {
5813
+ if (!inputEl) {
5814
+ return;
5815
+ }
5816
+ inputEl.value = "";
5817
+ }
5818
+ function focusInput() {
5819
+ if (!inputEl) {
5820
+ surfaceEl.focus();
5821
+ return;
5822
+ }
5823
+ inputEl.focus({ preventScroll: true });
5824
+ const end = inputEl.value.length;
5825
+ inputEl.setSelectionRange(end, end);
5826
+ }
5809
5827
  function notifySessionChange() {
5810
5828
  options.onSessionChange?.(session);
5811
5829
  }
@@ -6070,7 +6088,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6070
6088
  event.preventDefault();
6071
6089
  event.stopPropagation();
6072
6090
  startDragSelection(chainId, index);
6073
- surfaceEl.focus();
6091
+ focusInput();
6074
6092
  });
6075
6093
  slot.addEventListener("click", (event) => {
6076
6094
  if (dragChanged) {
@@ -6080,7 +6098,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6080
6098
  return;
6081
6099
  }
6082
6100
  applyTransient((prev) => setCaret(prev, chainId, index));
6083
- surfaceEl.focus();
6101
+ focusInput();
6084
6102
  });
6085
6103
  if (session.caret.chainId === chainId && session.caret.index === index) {
6086
6104
  const caret = document.createElement("span");
@@ -6112,7 +6130,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6112
6130
  event.preventDefault();
6113
6131
  event.stopPropagation();
6114
6132
  startDragSelection(chainId, indexInChain);
6115
- surfaceEl.focus();
6133
+ focusInput();
6116
6134
  });
6117
6135
  nodeEl.addEventListener("click", (event) => {
6118
6136
  if (dragChanged) {
@@ -6123,7 +6141,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6123
6141
  }
6124
6142
  event.stopPropagation();
6125
6143
  applyTransient((prev) => selectNode(prev, node.id));
6126
- surfaceEl.focus();
6144
+ focusInput();
6127
6145
  });
6128
6146
  const body = document.createElement("span");
6129
6147
  body.className = "node-body";
@@ -6158,7 +6176,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6158
6176
  const activeTree = session[activeTreeKey(session.activeSide)];
6159
6177
  surfaceEl.appendChild(buildChain(activeTree));
6160
6178
  if (initialKeyboardFocusPending) {
6161
- requestAnimationFrame(() => surfaceEl.focus());
6179
+ requestAnimationFrame(focusInput);
6162
6180
  initialKeyboardFocusPending = false;
6163
6181
  }
6164
6182
  notifySessionChange();
@@ -6196,7 +6214,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6196
6214
  }
6197
6215
  session = restored;
6198
6216
  render();
6199
- surfaceEl.focus();
6217
+ focusInput();
6200
6218
  }
6201
6219
  function performRedo() {
6202
6220
  const restored = restoreRedo(undoRedo, session);
@@ -6205,9 +6223,12 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6205
6223
  }
6206
6224
  session = restored;
6207
6225
  render();
6208
- surfaceEl.focus();
6226
+ focusInput();
6209
6227
  }
6210
6228
  function onKeyDown(event) {
6229
+ if (event.isComposing || event.key === "Process" || event.keyCode === 229) {
6230
+ return;
6231
+ }
6211
6232
  const shortcutMod = event.ctrlKey || event.metaKey;
6212
6233
  const keyLower = typeof event.key === "string" ? event.key.toLowerCase() : "";
6213
6234
  if (shortcutMod && !event.altKey && keyLower === "z") {
@@ -6306,6 +6327,70 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6306
6327
  applyStructural((prev) => insertChar(prev, char));
6307
6328
  }
6308
6329
  }
6330
+ function onBeforeInput(event) {
6331
+ if (composingInput || event.isComposing) {
6332
+ return;
6333
+ }
6334
+ if (event.inputType === "deleteContentBackward") {
6335
+ event.preventDefault();
6336
+ applyStructural((prev) => deleteBackward(prev));
6337
+ resetInputElement();
6338
+ return;
6339
+ }
6340
+ if (event.inputType === "deleteContentForward") {
6341
+ event.preventDefault();
6342
+ applyStructural((prev) => deleteForward(prev));
6343
+ resetInputElement();
6344
+ }
6345
+ }
6346
+ function onInput(event) {
6347
+ if (!inputEl || composingInput) {
6348
+ return;
6349
+ }
6350
+ const inputEvent = event;
6351
+ const text = inputEvent.data ?? inputEl.value;
6352
+ resetInputElement();
6353
+ if (pendingCompositionText !== null && (inputEvent.inputType === "insertFromComposition" || text === pendingCompositionText)) {
6354
+ pendingCompositionText = null;
6355
+ return;
6356
+ }
6357
+ pendingCompositionText = null;
6358
+ if (inputEvent.inputType === "deleteContentBackward") {
6359
+ applyStructural((prev) => deleteBackward(prev));
6360
+ return;
6361
+ }
6362
+ if (inputEvent.inputType === "deleteContentForward") {
6363
+ applyStructural((prev) => deleteForward(prev));
6364
+ return;
6365
+ }
6366
+ if (text) {
6367
+ applyStructural((prev) => pasteText(prev, text));
6368
+ }
6369
+ }
6370
+ function onCompositionStart() {
6371
+ composingInput = true;
6372
+ }
6373
+ function onCompositionEnd(event) {
6374
+ if (!inputEl) {
6375
+ return;
6376
+ }
6377
+ composingInput = false;
6378
+ const text = event.data || inputEl.value;
6379
+ resetInputElement();
6380
+ if (text) {
6381
+ applyStructural((prev) => pasteText(prev, text));
6382
+ }
6383
+ pendingCompositionText = text || null;
6384
+ window.setTimeout(() => {
6385
+ pendingCompositionText = null;
6386
+ }, 0);
6387
+ }
6388
+ function onInputFocus() {
6389
+ surfaceEl.classList.add("surface--typing-focus");
6390
+ }
6391
+ function onInputBlur() {
6392
+ surfaceEl.classList.remove("surface--typing-focus");
6393
+ }
6309
6394
  function isShortcutOnlyEvent(event) {
6310
6395
  if (!(event.ctrlKey || event.metaKey) || event.altKey) {
6311
6396
  return false;
@@ -6355,7 +6440,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6355
6440
  }
6356
6441
  event.preventDefault();
6357
6442
  startDragSelection(resolved.chainId, resolved.slotIndex);
6358
- surfaceEl.focus();
6443
+ focusInput();
6359
6444
  }
6360
6445
  function onSurfaceClick(event) {
6361
6446
  if (dragChanged) {
@@ -6372,7 +6457,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6372
6457
  } else {
6373
6458
  clearSelectionAndNodeHighlights();
6374
6459
  }
6375
- surfaceEl.focus();
6460
+ focusInput();
6376
6461
  }
6377
6462
  function onDocumentPointerDown(event) {
6378
6463
  const target = event.target;
@@ -6388,6 +6473,13 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6388
6473
  clearSelectionAndNodeHighlights();
6389
6474
  }
6390
6475
  surfaceEl.addEventListener("keydown", onKeyDown);
6476
+ inputEl?.addEventListener("keydown", onKeyDown);
6477
+ inputEl?.addEventListener("beforeinput", onBeforeInput);
6478
+ inputEl?.addEventListener("input", onInput);
6479
+ inputEl?.addEventListener("compositionstart", onCompositionStart);
6480
+ inputEl?.addEventListener("compositionend", onCompositionEnd);
6481
+ inputEl?.addEventListener("focus", onInputFocus);
6482
+ inputEl?.addEventListener("blur", onInputBlur);
6391
6483
  document.addEventListener("keydown", onDocumentKeyDown);
6392
6484
  document.addEventListener("mouseup", endDragSelection);
6393
6485
  document.addEventListener("mouseleave", endDragSelection);
@@ -6399,6 +6491,13 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6399
6491
  render,
6400
6492
  destroy: () => {
6401
6493
  surfaceEl.removeEventListener("keydown", onKeyDown);
6494
+ inputEl?.removeEventListener("keydown", onKeyDown);
6495
+ inputEl?.removeEventListener("beforeinput", onBeforeInput);
6496
+ inputEl?.removeEventListener("input", onInput);
6497
+ inputEl?.removeEventListener("compositionstart", onCompositionStart);
6498
+ inputEl?.removeEventListener("compositionend", onCompositionEnd);
6499
+ inputEl?.removeEventListener("focus", onInputFocus);
6500
+ inputEl?.removeEventListener("blur", onInputBlur);
6402
6501
  document.removeEventListener("keydown", onDocumentKeyDown);
6403
6502
  document.removeEventListener("mouseup", endDragSelection);
6404
6503
  document.removeEventListener("mouseleave", endDragSelection);
@@ -6419,6 +6518,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6419
6518
  uiLocale = locale;
6420
6519
  render();
6421
6520
  },
6521
+ focusInput,
6422
6522
  performUndo,
6423
6523
  performRedo,
6424
6524
  performCopy,
@@ -6426,27 +6526,27 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6426
6526
  performPaste,
6427
6527
  toggleSide: () => {
6428
6528
  applyTransient((prev) => switchSide(prev));
6429
- surfaceEl.focus();
6529
+ focusInput();
6430
6530
  },
6431
6531
  toggleSplitLeafTyping: () => {
6432
6532
  applyStructural((prev) => setSplitLeafTyping(prev, !prev.splitLeafTyping));
6433
- surfaceEl.focus();
6533
+ focusInput();
6434
6534
  },
6435
6535
  toggleArabicReverseNumberTyping: () => {
6436
6536
  applyStructural((prev) => setArabicReverseNumberTyping(prev, !prev.arabicReverseNumberTyping));
6437
- surfaceEl.focus();
6537
+ focusInput();
6438
6538
  },
6439
6539
  toggleTakweenCharacterFont: () => {
6440
6540
  applyTransient((prev) => toggleTakweenCharacterFont(prev));
6441
- surfaceEl.focus();
6541
+ focusInput();
6442
6542
  },
6443
6543
  setCurrentCharacterFont: (fontId) => {
6444
6544
  applyTransient((prev) => setCurrentCharacterFont(prev, fontId));
6445
- surfaceEl.focus();
6545
+ focusInput();
6446
6546
  },
6447
6547
  setCurrentDigitForm: (digitForm) => {
6448
6548
  applyStructural((prev) => setCurrentDigitForm(prev, digitForm));
6449
- surfaceEl.focus();
6549
+ focusInput();
6450
6550
  },
6451
6551
  insertDelimiterByKind: (kind) => {
6452
6552
  if (kind === "paren") {
@@ -6456,79 +6556,79 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6456
6556
  } else {
6457
6557
  applyStructural((prev) => insertDelimiterPair(prev, "\\left\\{", "\\right\\}"));
6458
6558
  }
6459
- surfaceEl.focus();
6559
+ focusInput();
6460
6560
  },
6461
6561
  insertFraction: () => {
6462
6562
  applyStructural((prev) => insertFraction(prev));
6463
- surfaceEl.focus();
6563
+ focusInput();
6464
6564
  },
6465
6565
  insertFirstDerivative: () => {
6466
6566
  applyStructural((prev) => insertFirstDerivative(prev));
6467
- surfaceEl.focus();
6567
+ focusInput();
6468
6568
  },
6469
6569
  insertSecondDerivative: () => {
6470
6570
  applyStructural((prev) => insertSecondDerivative(prev));
6471
- surfaceEl.focus();
6571
+ focusInput();
6472
6572
  },
6473
6573
  insertMatrixEnv: (style, rows, columns) => {
6474
6574
  applyStructural((prev) => insertMatrixEnv(prev, style, rows, columns));
6475
- surfaceEl.focus();
6575
+ focusInput();
6476
6576
  },
6477
6577
  insertArrayEnv: (rows, columns) => {
6478
6578
  applyStructural((prev) => insertArrayEnv(prev, rows, columns));
6479
- surfaceEl.focus();
6579
+ focusInput();
6480
6580
  },
6481
6581
  insertAlignedEnv: (rows, columns) => {
6482
6582
  applyStructural((prev) => insertAlignedEnv(prev, rows, columns));
6483
- surfaceEl.focus();
6583
+ focusInput();
6484
6584
  },
6485
6585
  insertSqrt: () => {
6486
6586
  applyStructural((prev) => insertSqrt(prev));
6487
- surfaceEl.focus();
6587
+ focusInput();
6488
6588
  },
6489
6589
  insertOverset: () => {
6490
6590
  applyStructural((prev) => insertOverset(prev));
6491
- surfaceEl.focus();
6591
+ focusInput();
6492
6592
  },
6493
6593
  insertUnderset: () => {
6494
6594
  applyStructural((prev) => insertUnderset(prev));
6495
- surfaceEl.focus();
6595
+ focusInput();
6496
6596
  },
6497
6597
  insertLimitsSeriesTemplate: (commandId) => {
6498
6598
  applyStructural((prev) => insertLimitsSeriesTemplate(prev, commandId));
6499
- surfaceEl.focus();
6599
+ focusInput();
6500
6600
  },
6501
6601
  insertAccentPair: () => {
6502
6602
  applyStructural((prev) => insertAccentPair(prev));
6503
- surfaceEl.focus();
6603
+ focusInput();
6504
6604
  },
6505
6605
  insertAccent: (accentId) => {
6506
6606
  applyStructural((prev) => insertAccent(prev, accentId));
6507
- surfaceEl.focus();
6607
+ focusInput();
6508
6608
  },
6509
6609
  insertAtomicCommand: (commandId) => {
6510
6610
  applyStructural((prev) => insertAtomicCommand(prev, commandId));
6511
- surfaceEl.focus();
6611
+ focusInput();
6512
6612
  },
6513
6613
  insertAtomicOperatorCommand: (commandId) => {
6514
6614
  applyStructural((prev) => insertAtomicOperatorCommand(prev, commandId));
6515
- surfaceEl.focus();
6615
+ focusInput();
6516
6616
  },
6517
6617
  addSup: () => {
6518
6618
  applyStructural((prev) => addSup(prev));
6519
- surfaceEl.focus();
6619
+ focusInput();
6520
6620
  },
6521
6621
  addSub: () => {
6522
6622
  applyStructural((prev) => addSub(prev));
6523
- surfaceEl.focus();
6623
+ focusInput();
6524
6624
  },
6525
6625
  removeSup: () => {
6526
6626
  applyStructural((prev) => removeSup(prev));
6527
- surfaceEl.focus();
6627
+ focusInput();
6528
6628
  },
6529
6629
  removeSub: () => {
6530
6630
  applyStructural((prev) => removeSub(prev));
6531
- surfaceEl.focus();
6631
+ focusInput();
6532
6632
  },
6533
6633
  setMatrixEnvStyle: (style) => {
6534
6634
  applyStructural((prev) => setMatrixEnvStyle(prev, style));
@@ -6550,7 +6650,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6550
6650
  },
6551
6651
  deleteStructure: () => {
6552
6652
  applyStructural((prev) => deleteStructure(prev));
6553
- surfaceEl.focus();
6653
+ focusInput();
6554
6654
  }
6555
6655
  };
6556
6656
  render();