@sofereditor/react 0.7.0 → 0.10.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/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  // src/Editor.tsx
2
2
  import {
3
- useCallback as useCallback7,
4
- useEffect as useEffect9,
3
+ useCallback as useCallback8,
4
+ useEffect as useEffect10,
5
5
  useLayoutEffect as useLayoutEffect5,
6
6
  useMemo as useMemo4,
7
- useRef as useRef11,
8
- useState as useState10
7
+ useRef as useRef12,
8
+ useState as useState11
9
9
  } from "react";
10
10
  import {
11
11
  collapsedSelection as collapsedSelection2,
@@ -17,6 +17,7 @@ import {
17
17
  insertSlice,
18
18
  insertText,
19
19
  isEmbedAdjacentToCaret,
20
+ isFormulaEmbed as isFormulaEmbed2,
20
21
  serializeSelection,
21
22
  sliceToText,
22
23
  SOFER_MIME as SOFER_MIME2
@@ -93,6 +94,11 @@ function isWrapAnchorImg(n) {
93
94
  function isPhantomEmbed(n) {
94
95
  return n.nodeType === Node.ELEMENT_NODE && n.dataset.embedPhantom === "true";
95
96
  }
97
+ function isCellLineBoundary(n) {
98
+ if (n.nodeType !== Node.ELEMENT_NODE) return false;
99
+ const line = n.dataset.cellLine;
100
+ return line != null && Number(line) > 0;
101
+ }
96
102
  function indexInParent(n) {
97
103
  const parent = n.parentNode;
98
104
  if (!parent) return 0;
@@ -120,6 +126,7 @@ function textOffsetWithin(container, node, offsetInNode) {
120
126
  let done = false;
121
127
  function visit(n) {
122
128
  if (done) return;
129
+ if (isCellLineBoundary(n)) offset += 1;
123
130
  if (n === target) {
124
131
  if (n.nodeType === Node.TEXT_NODE) {
125
132
  offset += targetOff;
@@ -220,6 +227,7 @@ function locatePoint(root, pos) {
220
227
  let remaining = Math.max(0, pos.offset - containerStart);
221
228
  let result = null;
222
229
  let lastImg = null;
230
+ let lastBoundary = null;
223
231
  let lastText = null;
224
232
  function visit(n) {
225
233
  if (result) return;
@@ -231,6 +239,7 @@ function locatePoint(root, pos) {
231
239
  }
232
240
  remaining -= len;
233
241
  lastImg = null;
242
+ lastBoundary = null;
234
243
  lastText = n;
235
244
  return;
236
245
  }
@@ -238,6 +247,25 @@ function locatePoint(root, pos) {
238
247
  const el = n;
239
248
  if (isRejectedSubtree(el, container)) return;
240
249
  if (isImgEmbed(el) && isWrapAnchorImg(el)) return;
250
+ if (isCellLineBoundary(el)) {
251
+ if (remaining === 0) {
252
+ if (lastImg) {
253
+ const parent = lastImg.parentNode;
254
+ if (parent) {
255
+ result = { node: parent, offset: indexInParent(lastImg) + 1 };
256
+ return;
257
+ }
258
+ }
259
+ const prevLine = lastBoundary ?? el.previousElementSibling;
260
+ if (prevLine) {
261
+ result = { node: prevLine, offset: 0 };
262
+ return;
263
+ }
264
+ }
265
+ remaining -= 1;
266
+ lastBoundary = el;
267
+ lastImg = null;
268
+ }
241
269
  if (isImgEmbed(el) || isPhantomEmbed(el)) {
242
270
  if (remaining === 0) {
243
271
  const parent = el.parentNode;
@@ -248,6 +276,7 @@ function locatePoint(root, pos) {
248
276
  }
249
277
  remaining -= 1;
250
278
  lastImg = el;
279
+ lastBoundary = null;
251
280
  return;
252
281
  }
253
282
  for (const child of Array.from(el.childNodes)) {
@@ -257,7 +286,10 @@ function locatePoint(root, pos) {
257
286
  }
258
287
  visit(container);
259
288
  if (result) return result;
260
- if (lastImg && remaining === 0) {
289
+ if (lastBoundary) {
290
+ return { node: lastBoundary, offset: 0 };
291
+ }
292
+ if (lastImg) {
261
293
  const parent = lastImg.parentNode;
262
294
  if (parent) return { node: parent, offset: indexInParent(lastImg) + 1 };
263
295
  }
@@ -1802,15 +1834,376 @@ function ImageCaptionDialog() {
1802
1834
  );
1803
1835
  }
1804
1836
 
1805
- // src/EditorContext.tsx
1837
+ // src/FormulaDialog.tsx
1838
+ import { useCallback as useCallback2, useEffect as useEffect5, useRef as useRef4, useState as useState5 } from "react";
1839
+
1840
+ // src/formulaSnippet.ts
1841
+ var PALETA = [
1842
+ {
1843
+ nome: "Estruturas",
1844
+ colunas: 4,
1845
+ itens: [
1846
+ { label: "Fra\xE7\xE3o", snippet: "\\frac{}{}" },
1847
+ { label: "Expoente", snippet: "^{}" },
1848
+ { label: "\xCDndice", snippet: "_{}" },
1849
+ { label: "Raiz", snippet: "\\sqrt{}" },
1850
+ { label: "Raiz n-\xE9sima", snippet: "\\sqrt[{}]{}" },
1851
+ { label: "Somat\xF3rio", snippet: "\\sum_{}^{}" },
1852
+ { label: "Produt\xF3rio", snippet: "\\prod_{}^{}" },
1853
+ { label: "Integral", snippet: "\\int_{}^{}" },
1854
+ { label: "Limite", snippet: "\\lim_{{} \\to {}}" },
1855
+ { label: "Derivada", snippet: "\\frac{d}{d{}}" },
1856
+ {
1857
+ label: "Matriz 2\xD72",
1858
+ snippet: "\\begin{pmatrix} {} & {} \\\\ {} & {} \\end{pmatrix}"
1859
+ },
1860
+ { label: "Sistema", snippet: "\\begin{cases} {} \\\\ \\end{cases}" },
1861
+ { label: "Par\xEAnteses", snippet: "\\left({}\\right)" },
1862
+ { label: "Binomial", snippet: "\\binom{}{}" },
1863
+ { label: "M\xF3dulo", snippet: "\\left|{}\\right|" }
1864
+ ]
1865
+ },
1866
+ {
1867
+ nome: "S\xEDmbolos",
1868
+ colunas: 6,
1869
+ itens: [
1870
+ { label: "\xB1", snippet: "\\pm", titulo: "mais ou menos" },
1871
+ { label: "\xD7", snippet: "\\times", titulo: "multiplica\xE7\xE3o" },
1872
+ { label: "\xF7", snippet: "\\div", titulo: "divis\xE3o" },
1873
+ { label: "\xB7", snippet: "\\cdot", titulo: "multiplica\xE7\xE3o (ponto)" },
1874
+ { label: "\u221E", snippet: "\\infty", titulo: "infinito" },
1875
+ { label: "\xB0", snippet: "^\\circ", titulo: "grau" },
1876
+ { label: "%", snippet: "\\%", titulo: "por cento" },
1877
+ { label: ",", snippet: "{,}", titulo: "v\xEDrgula decimal" }
1878
+ ]
1879
+ },
1880
+ {
1881
+ nome: "Rela\xE7\xF5es",
1882
+ colunas: 6,
1883
+ itens: [
1884
+ { label: "\u2260", snippet: "\\neq", titulo: "diferente de" },
1885
+ { label: "\u2248", snippet: "\\approx", titulo: "aproximadamente" },
1886
+ { label: "\u2261", snippet: "\\equiv", titulo: "id\xEAntico a" },
1887
+ { label: "\u2264", snippet: "\\leq", titulo: "menor ou igual a" },
1888
+ { label: "\u2265", snippet: "\\geq", titulo: "maior ou igual a" },
1889
+ { label: "\u221D", snippet: "\\propto", titulo: "proporcional a" },
1890
+ { label: "\u22A5", snippet: "\\perp", titulo: "perpendicular a" },
1891
+ { label: "\u2225", snippet: "\\parallel", titulo: "paralelo a" },
1892
+ { label: "\u2245", snippet: "\\cong", titulo: "congruente a" },
1893
+ { label: "\u223C", snippet: "\\sim", titulo: "semelhante a" }
1894
+ ]
1895
+ },
1896
+ {
1897
+ nome: "Gregas",
1898
+ colunas: 6,
1899
+ itens: [
1900
+ { label: "\u03B1", snippet: "\\alpha", titulo: "alfa" },
1901
+ { label: "\u03B2", snippet: "\\beta", titulo: "beta" },
1902
+ { label: "\u03B3", snippet: "\\gamma", titulo: "gama" },
1903
+ { label: "\u03B4", snippet: "\\delta", titulo: "delta" },
1904
+ { label: "\u03B5", snippet: "\\varepsilon", titulo: "\xE9psilon" },
1905
+ { label: "\u03B8", snippet: "\\theta", titulo: "teta" },
1906
+ { label: "\u03BB", snippet: "\\lambda", titulo: "lambda" },
1907
+ { label: "\u03BC", snippet: "\\mu", titulo: "mi" },
1908
+ { label: "\u03C0", snippet: "\\pi", titulo: "pi" },
1909
+ { label: "\u03C1", snippet: "\\rho", titulo: "r\xF4" },
1910
+ { label: "\u03C3", snippet: "\\sigma", titulo: "sigma" },
1911
+ { label: "\u03C6", snippet: "\\varphi", titulo: "fi" },
1912
+ { label: "\u03C9", snippet: "\\omega", titulo: "\xF4mega" },
1913
+ { label: "\u0394", snippet: "\\Delta", titulo: "delta mai\xFAsculo" },
1914
+ {
1915
+ label: "\u03A3",
1916
+ snippet: "\\Sigma",
1917
+ titulo: "sigma mai\xFAsculo \u2014 letra grega; para somat\xF3rio use Estruturas"
1918
+ },
1919
+ {
1920
+ label: "\u03A0",
1921
+ snippet: "\\Pi",
1922
+ titulo: "pi mai\xFAsculo \u2014 letra grega; para produt\xF3rio use Estruturas"
1923
+ },
1924
+ { label: "\u03A9", snippet: "\\Omega", titulo: "\xF4mega mai\xFAsculo" },
1925
+ { label: "\u03A6", snippet: "\\Phi", titulo: "fi mai\xFAsculo" }
1926
+ ]
1927
+ },
1928
+ {
1929
+ nome: "Conjuntos",
1930
+ colunas: 6,
1931
+ itens: [
1932
+ { label: "\u2208", snippet: "\\in", titulo: "pertence a" },
1933
+ { label: "\u2209", snippet: "\\notin", titulo: "n\xE3o pertence a" },
1934
+ { label: "\u2282", snippet: "\\subset", titulo: "contido em" },
1935
+ { label: "\u2286", snippet: "\\subseteq", titulo: "contido ou igual a" },
1936
+ { label: "\u222A", snippet: "\\cup", titulo: "uni\xE3o" },
1937
+ { label: "\u2229", snippet: "\\cap", titulo: "interse\xE7\xE3o" },
1938
+ { label: "\u2205", snippet: "\\varnothing", titulo: "conjunto vazio" },
1939
+ { label: "\u2115", snippet: "\\mathbb{N}", titulo: "conjunto dos naturais" },
1940
+ { label: "\u2124", snippet: "\\mathbb{Z}", titulo: "conjunto dos inteiros" },
1941
+ { label: "\u211A", snippet: "\\mathbb{Q}", titulo: "conjunto dos racionais" },
1942
+ { label: "\u211D", snippet: "\\mathbb{R}", titulo: "conjunto dos reais" },
1943
+ { label: "\u2102", snippet: "\\mathbb{C}", titulo: "conjunto dos complexos" },
1944
+ { label: "\u2200", snippet: "\\forall", titulo: "para todo" },
1945
+ { label: "\u2203", snippet: "\\exists", titulo: "existe" },
1946
+ { label: "{ }", snippet: "\\{{}\\}", titulo: "chaves de conjunto" }
1947
+ ]
1948
+ },
1949
+ {
1950
+ nome: "Fun\xE7\xF5es",
1951
+ colunas: 6,
1952
+ itens: [
1953
+ { label: "sen", snippet: "\\operatorname{sen}", titulo: "seno" },
1954
+ { label: "cos", snippet: "\\cos", titulo: "cosseno" },
1955
+ { label: "tg", snippet: "\\operatorname{tg}", titulo: "tangente" },
1956
+ { label: "cotg", snippet: "\\operatorname{cotg}", titulo: "cotangente" },
1957
+ { label: "log", snippet: "\\log_{}", titulo: "logaritmo" },
1958
+ { label: "ln", snippet: "\\ln", titulo: "logaritmo natural" },
1959
+ { label: "exp", snippet: "\\exp", titulo: "exponencial" }
1960
+ ]
1961
+ },
1962
+ {
1963
+ nome: "Setas",
1964
+ colunas: 6,
1965
+ itens: [
1966
+ { label: "\u2192", snippet: "\\to", titulo: "tende a / vai para" },
1967
+ { label: "\u2190", snippet: "\\leftarrow", titulo: "vem de / sentido inverso" },
1968
+ { label: "\u21D2", snippet: "\\Rightarrow", titulo: "implica em" },
1969
+ { label: "\u21D4", snippet: "\\Leftrightarrow", titulo: "se e somente se" },
1970
+ { label: "\u21CC", snippet: "\\rightleftharpoons", titulo: "equil\xEDbrio qu\xEDmico" },
1971
+ { label: "vetor AB", snippet: "\\overrightarrow{}", titulo: "vetor entre dois pontos (AB)" },
1972
+ { label: "vetor", snippet: "\\vec{}", titulo: "vetor (f\xEDsica)" },
1973
+ { label: "\u2220", snippet: "\\angle", titulo: "\xE2ngulo" },
1974
+ { label: "\u25B3", snippet: "\\triangle", titulo: "tri\xE2ngulo" }
1975
+ ]
1976
+ }
1977
+ ];
1978
+ function paraMathlive(snippet) {
1979
+ return snippet.replaceAll("{}", "{#?}");
1980
+ }
1981
+ function paraMarkup(snippet) {
1982
+ return snippet.replaceAll("{}", "{\u25A1}");
1983
+ }
1984
+ function conteudoDoBotao(markup, snippet, label) {
1985
+ if (!markup) return { children: label };
1986
+ return { dangerouslySetInnerHTML: { __html: markup(paraMarkup(snippet)) } };
1987
+ }
1988
+
1989
+ // src/formulaGuarda.ts
1990
+ var PLACEHOLDER = "\\placeholder{}";
1991
+ var GRUPO_VAZIO = /\{\s*\}/;
1992
+ var CELULA_VAZIA = /(?:\\begin\{[a-zA-Z]+\*?\}|&|\\\\)\s*(?:&|\\\\|\\end\{)/;
1993
+ function podeInserir(latex, preview) {
1994
+ if (motivoBloqueio(latex, preview) !== null) return false;
1995
+ return latex.trim() !== "" && preview?.ok === true;
1996
+ }
1997
+ function motivoBloqueio(latex, preview) {
1998
+ if (latex.includes(PLACEHOLDER) || GRUPO_VAZIO.test(latex) || CELULA_VAZIA.test(latex)) {
1999
+ return "Preencha os campos em branco da f\xF3rmula.";
2000
+ }
2001
+ if (preview && !preview.ok) return preview.error ?? null;
2002
+ return null;
2003
+ }
2004
+
2005
+ // src/FormulaDialog.tsx
1806
2006
  import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2007
+ var CIRCUNFLEXO_DE_TECLA_MORTA = /* @__PURE__ */ new Set(["\u02C6", "\u0302"]);
2008
+ function FormulaDialog({
2009
+ fontsDirectory
2010
+ }) {
2011
+ const { formulaRequest, resolveFormulaRequest } = useEditorContext();
2012
+ const dialogRef = useRef4(null);
2013
+ const hostRef = useRef4(null);
2014
+ const fieldRef = useRef4(null);
2015
+ const [latex, setLatex] = useState5("");
2016
+ const [display, setDisplay] = useState5(false);
2017
+ const [abaAtiva, setAbaAtiva] = useState5(0);
2018
+ useEffect5(() => {
2019
+ const dialog = dialogRef.current;
2020
+ if (!dialog) return;
2021
+ if (formulaRequest) {
2022
+ setLatex(formulaRequest.initialLatex);
2023
+ setDisplay(formulaRequest.initialDisplay);
2024
+ setAbaAtiva(0);
2025
+ if (!dialog.open) dialog.showModal();
2026
+ } else if (dialog.open) {
2027
+ dialog.close();
2028
+ }
2029
+ }, [formulaRequest]);
2030
+ const rendererRef = useRef4(null);
2031
+ const mathfieldCtorRef = useRef4(null);
2032
+ const markupRef = useRef4(null);
2033
+ const [preview, setPreview] = useState5(null);
2034
+ const [carregando, setCarregando] = useState5(false);
2035
+ const [erroCarregando, setErroCarregando] = useState5(null);
2036
+ useEffect5(() => {
2037
+ if (!formulaRequest || rendererRef.current) return;
2038
+ setCarregando(true);
2039
+ setErroCarregando(null);
2040
+ void Promise.all([import("@sofereditor/math"), import("mathlive")]).then(([math, mathlive]) => {
2041
+ rendererRef.current = math.renderLatexToSvg;
2042
+ mathfieldCtorRef.current = mathlive.MathfieldElement;
2043
+ markupRef.current = mathlive.convertLatexToMarkup;
2044
+ mathlive.MathfieldElement.soundsDirectory = null;
2045
+ if (fontsDirectory) {
2046
+ mathlive.MathfieldElement.fontsDirectory = fontsDirectory;
2047
+ }
2048
+ setCarregando(false);
2049
+ }).catch(() => {
2050
+ setCarregando(false);
2051
+ setErroCarregando(
2052
+ "N\xE3o foi poss\xEDvel carregar o editor de f\xF3rmulas. Recarregue a p\xE1gina e tente de novo."
2053
+ );
2054
+ });
2055
+ }, [formulaRequest]);
2056
+ useEffect5(() => {
2057
+ const render = rendererRef.current;
2058
+ if (!render || !latex.trim()) {
2059
+ setPreview(null);
2060
+ return;
2061
+ }
2062
+ setPreview(render(latex, display));
2063
+ }, [latex, display, carregando]);
2064
+ const onCircunflexoMorto = useCallback2((e) => {
2065
+ const ev = e;
2066
+ if (!ev.data || !CIRCUNFLEXO_DE_TECLA_MORTA.has(ev.data)) return;
2067
+ ev.preventDefault();
2068
+ ev.stopPropagation();
2069
+ fieldRef.current?.insert("^{#?}", { focus: true });
2070
+ }, []);
2071
+ useEffect5(() => {
2072
+ const Ctor = mathfieldCtorRef.current;
2073
+ const host = hostRef.current;
2074
+ if (!Ctor || !host || !formulaRequest) return;
2075
+ const mf = new Ctor();
2076
+ mf.className = "ed-formula-field";
2077
+ const onInput = () => setLatex(mf.getValue("latex"));
2078
+ mf.addEventListener("input", onInput);
2079
+ mf.addEventListener("beforeinput", onCircunflexoMorto, true);
2080
+ host.appendChild(mf);
2081
+ mf.mathVirtualKeyboardPolicy = "manual";
2082
+ mf.inlineShortcuts = {
2083
+ ...mf.inlineShortcuts,
2084
+ sen: "\\operatorname{sen}",
2085
+ tg: "\\operatorname{tg}",
2086
+ cotg: "\\operatorname{cotg}",
2087
+ // Vírgula decimal. Em modo matemático a vírgula crua é átomo de
2088
+ // pontuação e ganha espaço DEPOIS de si: digitar "3,14" sai impresso
2089
+ // como "3, 14" (medido: 4.4ex contra 4.023ex do agrupado). A paleta
2090
+ // tem um botão `{,}`, mas ninguém clica num botão para uma tecla que
2091
+ // está no teclado — e decimal aparece em toda prova de matemática,
2092
+ // física e química.
2093
+ //
2094
+ // O `after: "digit"` é o que separa os dois usos da vírgula, e foi
2095
+ // verificado no navegador: "3,14" vira `3{,}14` e "f(x,y)" continua
2096
+ // `f\left(x,y\right)`, com a vírgula de lista intacta — que é o
2097
+ // comportamento certo, ali ela É pontuação.
2098
+ ",": { after: "digit", value: "{,}" }
2099
+ };
2100
+ mf.setValue(formulaRequest.initialLatex);
2101
+ setLatex(mf.getValue("latex"));
2102
+ fieldRef.current = mf;
2103
+ queueMicrotask(() => mf.focus());
2104
+ return () => {
2105
+ mf.removeEventListener("input", onInput);
2106
+ mf.removeEventListener("beforeinput", onCircunflexoMorto, true);
2107
+ mf.remove();
2108
+ fieldRef.current = null;
2109
+ };
2110
+ }, [formulaRequest, carregando]);
2111
+ if (!formulaRequest) return null;
2112
+ const markup = markupRef.current;
2113
+ const motivo = motivoBloqueio(latex, preview);
2114
+ const podeSubmeter = podeInserir(latex, preview);
2115
+ const onSubmit = (e) => {
2116
+ e.preventDefault();
2117
+ if (!podeSubmeter) return;
2118
+ resolveFormulaRequest({ latex, display });
2119
+ };
2120
+ const onCancel = () => resolveFormulaRequest(null);
2121
+ const onPaleta = (snippet) => {
2122
+ const mf = fieldRef.current;
2123
+ if (!mf) return;
2124
+ mf.insert(paraMathlive(snippet), { focus: true });
2125
+ setLatex(mf.getValue("latex"));
2126
+ };
2127
+ return /* @__PURE__ */ jsx6(
2128
+ "dialog",
2129
+ {
2130
+ ref: dialogRef,
2131
+ className: "ed-formula-dialog ed-link-dialog",
2132
+ style: DIALOG_CENTER_STYLE,
2133
+ onClose: onCancel,
2134
+ onCancel: (e) => {
2135
+ e.preventDefault();
2136
+ onCancel();
2137
+ },
2138
+ children: /* @__PURE__ */ jsxs6("form", { onSubmit, className: "ed-formula-form", children: [
2139
+ /* @__PURE__ */ jsx6("div", { className: "ed-formula-abas", role: "tablist", children: PALETA.map((cat, i) => /* @__PURE__ */ jsx6(
2140
+ "button",
2141
+ {
2142
+ type: "button",
2143
+ role: "tab",
2144
+ "aria-selected": i === abaAtiva,
2145
+ className: "ed-formula-aba",
2146
+ onClick: () => setAbaAtiva(i),
2147
+ children: cat.nome
2148
+ },
2149
+ cat.nome
2150
+ )) }),
2151
+ /* @__PURE__ */ jsx6(
2152
+ "div",
2153
+ {
2154
+ className: "ed-formula-paleta",
2155
+ role: "tabpanel",
2156
+ style: { gridTemplateColumns: `repeat(${PALETA[abaAtiva].colunas}, 1fr)` },
2157
+ children: PALETA[abaAtiva].itens.map((p) => /* @__PURE__ */ jsx6(
2158
+ "button",
2159
+ {
2160
+ type: "button",
2161
+ className: "ed-formula-paleta-btn",
2162
+ title: p.titulo ?? p.label,
2163
+ "aria-label": p.titulo ?? p.label,
2164
+ onClick: () => onPaleta(p.snippet),
2165
+ ...conteudoDoBotao(markup, p.snippet, p.label)
2166
+ },
2167
+ p.label
2168
+ ))
2169
+ }
2170
+ ),
2171
+ /* @__PURE__ */ jsx6("div", { ref: hostRef, className: "ed-formula-host" }),
2172
+ /* @__PURE__ */ jsxs6("label", { className: "ed-formula-display", children: [
2173
+ /* @__PURE__ */ jsx6(
2174
+ "input",
2175
+ {
2176
+ type: "checkbox",
2177
+ checked: display,
2178
+ onChange: (e) => setDisplay(e.target.checked)
2179
+ }
2180
+ ),
2181
+ "F\xF3rmula em bloco (centralizada, limites acima e abaixo)"
2182
+ ] }),
2183
+ /* @__PURE__ */ jsx6("div", { className: "ed-formula-preview", "aria-live": "polite", children: carregando ? /* @__PURE__ */ jsx6("span", { className: "ed-formula-vazio", children: "Carregando o editor\u2026" }) : erroCarregando ? /* @__PURE__ */ jsx6("span", { className: "ed-formula-erro", role: "alert", children: erroCarregando }) : motivo ? /* @__PURE__ */ jsx6("span", { className: "ed-formula-erro", role: "alert", children: motivo }) : null }),
2184
+ /* @__PURE__ */ jsxs6("div", { className: "ed-formula-acoes", children: [
2185
+ /* @__PURE__ */ jsx6("button", { type: "button", onClick: onCancel, children: "Cancelar" }),
2186
+ /* @__PURE__ */ jsx6("button", { type: "submit", disabled: !podeSubmeter, children: "Inserir" })
2187
+ ] })
2188
+ ] })
2189
+ }
2190
+ );
2191
+ }
2192
+
2193
+ // src/EditorContext.tsx
2194
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1807
2195
  var EditorContext = createContext(null);
1808
- function EditorProvider({ editor, children }) {
1809
- return /* @__PURE__ */ jsxs6(EditorContext.Provider, { value: editor, children: [
2196
+ function EditorProvider({
2197
+ editor,
2198
+ children,
2199
+ mathliveFontsDirectory
2200
+ }) {
2201
+ return /* @__PURE__ */ jsxs7(EditorContext.Provider, { value: editor, children: [
1810
2202
  children,
1811
- /* @__PURE__ */ jsx6(LinkDialog, {}),
1812
- /* @__PURE__ */ jsx6(PageConfigDialog, {}),
1813
- /* @__PURE__ */ jsx6(ImageCaptionDialog, {})
2203
+ /* @__PURE__ */ jsx7(LinkDialog, {}),
2204
+ /* @__PURE__ */ jsx7(PageConfigDialog, {}),
2205
+ /* @__PURE__ */ jsx7(ImageCaptionDialog, {}),
2206
+ /* @__PURE__ */ jsx7(FormulaDialog, { fontsDirectory: mathliveFontsDirectory })
1814
2207
  ] });
1815
2208
  }
1816
2209
  function useEditorContext() {
@@ -1823,13 +2216,13 @@ function useEditorContext() {
1823
2216
 
1824
2217
  // src/ImageResizeOverlay.tsx
1825
2218
  import {
1826
- useCallback as useCallback2,
1827
- useEffect as useEffect5,
2219
+ useCallback as useCallback3,
2220
+ useEffect as useEffect6,
1828
2221
  useLayoutEffect as useLayoutEffect2,
1829
- useRef as useRef4,
1830
- useState as useState5
2222
+ useRef as useRef5,
2223
+ useState as useState6
1831
2224
  } from "react";
1832
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
2225
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1833
2226
  function ImageResizeOverlay({
1834
2227
  rootRef,
1835
2228
  blockIndex,
@@ -1840,10 +2233,10 @@ function ImageResizeOverlay({
1840
2233
  onCommitMove,
1841
2234
  onReanchor
1842
2235
  }) {
1843
- const [rect, setRect] = useState5(null);
1844
- const [isMoving, setIsMoving] = useState5(false);
1845
- const imgRef = useRef4(null);
1846
- const locateImage = useCallback2(() => {
2236
+ const [rect, setRect] = useState6(null);
2237
+ const [isMoving, setIsMoving] = useState6(false);
2238
+ const imgRef = useRef5(null);
2239
+ const locateImage = useCallback3(() => {
1847
2240
  const root = rootRef.current;
1848
2241
  if (!root) return null;
1849
2242
  let container = null;
@@ -1861,7 +2254,7 @@ function ImageResizeOverlay({
1861
2254
  `img[data-embed="image"][data-embed-offset="${localOffset}"]`
1862
2255
  );
1863
2256
  }, [rootRef, blockIndex, offset, cellIndex]);
1864
- const measure = useCallback2(() => {
2257
+ const measure = useCallback3(() => {
1865
2258
  const img = locateImage();
1866
2259
  if (!img) {
1867
2260
  setRect((prev) => prev === null ? prev : null);
@@ -1912,7 +2305,7 @@ function ImageResizeOverlay({
1912
2305
  embed.offsetX,
1913
2306
  embed.offsetY
1914
2307
  ]);
1915
- useEffect5(() => {
2308
+ useEffect6(() => {
1916
2309
  const root = rootRef.current;
1917
2310
  if (!root) return;
1918
2311
  const onScroll = () => measure();
@@ -1923,7 +2316,7 @@ function ImageResizeOverlay({
1923
2316
  root.removeEventListener("scroll", onScroll);
1924
2317
  };
1925
2318
  }, [measure, rootRef]);
1926
- useEffect5(() => {
2319
+ useEffect6(() => {
1927
2320
  if (typeof ResizeObserver === "undefined") return;
1928
2321
  const img = locateImage();
1929
2322
  const root = rootRef.current;
@@ -1936,7 +2329,7 @@ function ImageResizeOverlay({
1936
2329
  if (!rect) return null;
1937
2330
  const layout = embed.layout ?? "inline";
1938
2331
  const movable = layout !== "inline" && onCommitMove !== void 0;
1939
- return /* @__PURE__ */ jsxs7(
2332
+ return /* @__PURE__ */ jsxs8(
1940
2333
  "div",
1941
2334
  {
1942
2335
  className: "ed-image-overlay",
@@ -1947,7 +2340,7 @@ function ImageResizeOverlay({
1947
2340
  // follows the cursor, so the image stays visible while it crosses the
1948
2341
  // page boundary (the real, clipped figure is hidden during the drag).
1949
2342
  // Inline styles only — the package does not ship CSS.
1950
- /* @__PURE__ */ jsx7(
2343
+ /* @__PURE__ */ jsx8(
1951
2344
  "img",
1952
2345
  {
1953
2346
  src: embed.src,
@@ -1965,7 +2358,7 @@ function ImageResizeOverlay({
1965
2358
  }
1966
2359
  }
1967
2360
  ),
1968
- movable && /* @__PURE__ */ jsx7(
2361
+ movable && /* @__PURE__ */ jsx8(
1969
2362
  MoveHandle,
1970
2363
  {
1971
2364
  layout,
@@ -1983,7 +2376,7 @@ function ImageResizeOverlay({
1983
2376
  onMoveEnd: () => setIsMoving(false)
1984
2377
  }
1985
2378
  ),
1986
- /* @__PURE__ */ jsx7(
2379
+ /* @__PURE__ */ jsx8(
1987
2380
  Handle,
1988
2381
  {
1989
2382
  corner: "nw",
@@ -1994,7 +2387,7 @@ function ImageResizeOverlay({
1994
2387
  onLiveChange: measure
1995
2388
  }
1996
2389
  ),
1997
- /* @__PURE__ */ jsx7(
2390
+ /* @__PURE__ */ jsx8(
1998
2391
  Handle,
1999
2392
  {
2000
2393
  corner: "ne",
@@ -2005,7 +2398,7 @@ function ImageResizeOverlay({
2005
2398
  onLiveChange: measure
2006
2399
  }
2007
2400
  ),
2008
- /* @__PURE__ */ jsx7(
2401
+ /* @__PURE__ */ jsx8(
2009
2402
  Handle,
2010
2403
  {
2011
2404
  corner: "sw",
@@ -2016,7 +2409,7 @@ function ImageResizeOverlay({
2016
2409
  onLiveChange: measure
2017
2410
  }
2018
2411
  ),
2019
- /* @__PURE__ */ jsx7(
2412
+ /* @__PURE__ */ jsx8(
2020
2413
  Handle,
2021
2414
  {
2022
2415
  corner: "se",
@@ -2046,7 +2439,7 @@ function MoveHandle({
2046
2439
  onMoveStart,
2047
2440
  onMoveEnd
2048
2441
  }) {
2049
- const dragRef = useRef4(null);
2442
+ const dragRef = useRef5(null);
2050
2443
  const onPointerDown = (e) => {
2051
2444
  if (e.button !== 0) return;
2052
2445
  if (!imgRef.current) return;
@@ -2196,7 +2589,7 @@ function MoveHandle({
2196
2589
  newOffsetY
2197
2590
  );
2198
2591
  };
2199
- return /* @__PURE__ */ jsx7(
2592
+ return /* @__PURE__ */ jsx8(
2200
2593
  "div",
2201
2594
  {
2202
2595
  className: "ed-image-move",
@@ -2216,7 +2609,7 @@ function Handle({
2216
2609
  onCommit,
2217
2610
  onLiveChange
2218
2611
  }) {
2219
- const dragRef = useRef4(null);
2612
+ const dragRef = useRef5(null);
2220
2613
  const onPointerDown = (e) => {
2221
2614
  if (e.button !== 0) return;
2222
2615
  if (!imgRef.current) return;
@@ -2259,7 +2652,7 @@ function Handle({
2259
2652
  }
2260
2653
  onCommit(Math.round(d.liveW), Math.round(d.liveH));
2261
2654
  };
2262
- return /* @__PURE__ */ jsx7(
2655
+ return /* @__PURE__ */ jsx8(
2263
2656
  "div",
2264
2657
  {
2265
2658
  className: `ed-image-handle ${corner}`,
@@ -2273,15 +2666,15 @@ function Handle({
2273
2666
 
2274
2667
  // src/RemoteCursorsOverlay.tsx
2275
2668
  import {
2276
- useCallback as useCallback3,
2277
- useEffect as useEffect6,
2278
- useRef as useRef5,
2279
- useState as useState6
2669
+ useCallback as useCallback4,
2670
+ useEffect as useEffect7,
2671
+ useRef as useRef6,
2672
+ useState as useState7
2280
2673
  } from "react";
2281
2674
  import {
2282
2675
  decodeSelection
2283
2676
  } from "@sofereditor/core";
2284
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
2677
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
2285
2678
  var DEFAULT_COLOR = "#3b82f6";
2286
2679
  function RemoteCursorsOverlay({
2287
2680
  rootRef,
@@ -2289,9 +2682,9 @@ function RemoteCursorsOverlay({
2289
2682
  awareness,
2290
2683
  revision
2291
2684
  }) {
2292
- const [views, setViews] = useState6([]);
2293
- const rafRef = useRef5(null);
2294
- const measure = useCallback3(() => {
2685
+ const [views, setViews] = useState7([]);
2686
+ const rafRef = useRef6(null);
2687
+ const measure = useCallback4(() => {
2295
2688
  const root = rootRef.current;
2296
2689
  if (!root) {
2297
2690
  setViews((prev) => prev.length === 0 ? prev : []);
@@ -2356,7 +2749,7 @@ function RemoteCursorsOverlay({
2356
2749
  });
2357
2750
  setViews(out);
2358
2751
  }, [rootRef, doc, awareness]);
2359
- const scheduleMeasure = useCallback3(() => {
2752
+ const scheduleMeasure = useCallback4(() => {
2360
2753
  if (rafRef.current != null) return;
2361
2754
  const raf = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (cb) => setTimeout(() => cb(0), 16);
2362
2755
  rafRef.current = raf(() => {
@@ -2364,16 +2757,16 @@ function RemoteCursorsOverlay({
2364
2757
  measure();
2365
2758
  });
2366
2759
  }, [measure]);
2367
- useEffect6(() => {
2760
+ useEffect7(() => {
2368
2761
  const onChange = () => scheduleMeasure();
2369
2762
  awareness.on("change", onChange);
2370
2763
  scheduleMeasure();
2371
2764
  return () => awareness.off("change", onChange);
2372
2765
  }, [awareness, scheduleMeasure]);
2373
- useEffect6(() => {
2766
+ useEffect7(() => {
2374
2767
  scheduleMeasure();
2375
2768
  }, [revision, scheduleMeasure]);
2376
- useEffect6(() => {
2769
+ useEffect7(() => {
2377
2770
  const root = rootRef.current;
2378
2771
  if (!root) return;
2379
2772
  const onScroll = () => scheduleMeasure();
@@ -2395,8 +2788,8 @@ function RemoteCursorsOverlay({
2395
2788
  pointerEvents: "none",
2396
2789
  zIndex: 6
2397
2790
  };
2398
- return /* @__PURE__ */ jsx8("div", { className: "ed-remote-cursors", "aria-hidden": true, style: layer, children: views.map((v) => /* @__PURE__ */ jsxs8("div", { children: [
2399
- v.selection.map((r, i) => /* @__PURE__ */ jsx8(
2791
+ return /* @__PURE__ */ jsx9("div", { className: "ed-remote-cursors", "aria-hidden": true, style: layer, children: views.map((v) => /* @__PURE__ */ jsxs9("div", { children: [
2792
+ v.selection.map((r, i) => /* @__PURE__ */ jsx9(
2400
2793
  "div",
2401
2794
  {
2402
2795
  style: {
@@ -2412,7 +2805,7 @@ function RemoteCursorsOverlay({
2412
2805
  },
2413
2806
  i
2414
2807
  )),
2415
- v.caret && /* @__PURE__ */ jsx8(
2808
+ v.caret && /* @__PURE__ */ jsx9(
2416
2809
  "div",
2417
2810
  {
2418
2811
  style: {
@@ -2423,7 +2816,7 @@ function RemoteCursorsOverlay({
2423
2816
  width: 2,
2424
2817
  background: v.color
2425
2818
  },
2426
- children: /* @__PURE__ */ jsx8(
2819
+ children: /* @__PURE__ */ jsx9(
2427
2820
  "span",
2428
2821
  {
2429
2822
  style: {
@@ -2449,10 +2842,13 @@ function RemoteCursorsOverlay({
2449
2842
  }
2450
2843
 
2451
2844
  // src/NodeView.tsx
2452
- import { useMemo as useMemo2, useRef as useRef7 } from "react";
2845
+ import { useMemo as useMemo2, useRef as useRef8 } from "react";
2453
2846
  import {
2454
2847
  answerLineStyle,
2455
2848
  cellBorderStyle,
2849
+ deltaLength as deltaLength2,
2850
+ normalizarLarguras as normalizarLarguras2,
2851
+ splitDeltaByLines,
2456
2852
  tableRectSelection
2457
2853
  } from "@sofereditor/core";
2458
2854
 
@@ -2463,12 +2859,12 @@ import {
2463
2859
  isImageEmbed as isImageEmbed3,
2464
2860
  splitUnderscoreRuns
2465
2861
  } from "@sofereditor/core";
2466
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
2467
- function renderInline(delta, keyPrefix) {
2862
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
2863
+ function renderInline(delta, keyPrefix, baseOffset = 0) {
2468
2864
  if (delta.length === 0 || delta.length === 1 && typeof delta[0].insert === "string" && delta[0].insert === "") {
2469
- return /* @__PURE__ */ jsx9("br", { "data-empty": "true" });
2865
+ return /* @__PURE__ */ jsx10("br", { "data-empty": "true" });
2470
2866
  }
2471
- let offset = 0;
2867
+ let offset = baseOffset;
2472
2868
  const wrapAnchors = [];
2473
2869
  const body = [];
2474
2870
  for (const op of delta) {
@@ -2476,7 +2872,7 @@ function renderInline(delta, keyPrefix) {
2476
2872
  const text = op.insert;
2477
2873
  if (text.length === 0) continue;
2478
2874
  const key = `${keyPrefix}-${offset}`;
2479
- body.push(/* @__PURE__ */ jsx9(Fragment3, { children: wrap(text, op.attributes) }, key));
2875
+ body.push(/* @__PURE__ */ jsx10(Fragment3, { children: wrap(text, op.attributes) }, key));
2480
2876
  offset += text.length;
2481
2877
  } else if (isImageEmbed3(op.insert)) {
2482
2878
  const key = `${keyPrefix}-${offset}`;
@@ -2484,10 +2880,10 @@ function renderInline(delta, keyPrefix) {
2484
2880
  const commentMarkId = op.attributes?.comment?.markId;
2485
2881
  if (layout === "wrap-left" || layout === "wrap-right") {
2486
2882
  wrapAnchors.push(
2487
- /* @__PURE__ */ jsx9(ImageEmbedView, { embed: op.insert, offset, wrapAnchor: true }, `${key}-anchor`)
2883
+ /* @__PURE__ */ jsx10(ImageEmbedView, { embed: op.insert, offset, wrapAnchor: true }, `${key}-anchor`)
2488
2884
  );
2489
2885
  body.push(
2490
- /* @__PURE__ */ jsx9(
2886
+ /* @__PURE__ */ jsx10(
2491
2887
  "span",
2492
2888
  {
2493
2889
  "data-embed-phantom": "true",
@@ -2499,10 +2895,10 @@ function renderInline(delta, keyPrefix) {
2499
2895
  )
2500
2896
  );
2501
2897
  } else {
2502
- const imgNode = /* @__PURE__ */ jsx9(ImageEmbedView, { embed: op.insert, offset }, key);
2898
+ const imgNode = /* @__PURE__ */ jsx10(ImageEmbedView, { embed: op.insert, offset }, key);
2503
2899
  if (commentMarkId) {
2504
2900
  body.push(
2505
- /* @__PURE__ */ jsx9("span", { "data-comment-id": commentMarkId, className: "ed-comment", children: imgNode }, `${key}-cmt`)
2901
+ /* @__PURE__ */ jsx10("span", { "data-comment-id": commentMarkId, className: "ed-comment", children: imgNode }, `${key}-cmt`)
2506
2902
  );
2507
2903
  } else {
2508
2904
  body.push(imgNode);
@@ -2513,7 +2909,7 @@ function renderInline(delta, keyPrefix) {
2513
2909
  offset += 1;
2514
2910
  }
2515
2911
  }
2516
- if (wrapAnchors.length === 0 && body.length === 0) return /* @__PURE__ */ jsx9("br", { "data-empty": "true" });
2912
+ if (wrapAnchors.length === 0 && body.length === 0) return /* @__PURE__ */ jsx10("br", { "data-empty": "true" });
2517
2913
  return [...wrapAnchors, ...body];
2518
2914
  }
2519
2915
  var PHANTOM_STYLE = {
@@ -2588,7 +2984,9 @@ function ImageEmbedViewImpl({
2588
2984
  marginRight: align === "right" ? 0 : "auto"
2589
2985
  } : {
2590
2986
  display: "inline-block",
2591
- verticalAlign: "text-bottom",
2987
+ // Fórmula inline traz o deslocamento de base que o MathJax mediu;
2988
+ // sem ele a fórmula flutua no topo da linha em vez de sentar nela.
2989
+ verticalAlign: embed.formula?.vAlign ?? "text-bottom",
2592
2990
  width: embed.width
2593
2991
  };
2594
2992
  break;
@@ -2598,7 +2996,7 @@ function ImageEmbedViewImpl({
2598
2996
  height: embed.height,
2599
2997
  display: "block"
2600
2998
  };
2601
- const img = /* @__PURE__ */ jsx9(
2999
+ const img = /* @__PURE__ */ jsx10(
2602
3000
  "img",
2603
3001
  {
2604
3002
  src: embed.src,
@@ -2618,7 +3016,7 @@ function ImageEmbedViewImpl({
2618
3016
  }
2619
3017
  );
2620
3018
  const captionAlign = embed.captionAlign ?? "center";
2621
- return /* @__PURE__ */ jsxs9(
3019
+ return /* @__PURE__ */ jsxs10(
2622
3020
  "figure",
2623
3021
  {
2624
3022
  className: "ed-figure",
@@ -2628,7 +3026,7 @@ function ImageEmbedViewImpl({
2628
3026
  style: outerStyle,
2629
3027
  children: [
2630
3028
  img,
2631
- hasCaption && /* @__PURE__ */ jsx9(
3029
+ hasCaption && /* @__PURE__ */ jsx10(
2632
3030
  "figcaption",
2633
3031
  {
2634
3032
  className: "ed-figcaption",
@@ -2645,26 +3043,26 @@ function decorateBlanks(text) {
2645
3043
  const segs = splitUnderscoreRuns(text);
2646
3044
  if (segs.length === 1 && !segs[0].blank) return text;
2647
3045
  return segs.map(
2648
- (s, i) => s.blank ? /* @__PURE__ */ jsx9("span", { "data-blank": "true", style: BLANK_STYLE, children: s.text }, i) : /* @__PURE__ */ jsx9(Fragment3, { children: s.text }, i)
3046
+ (s, i) => s.blank ? /* @__PURE__ */ jsx10("span", { "data-blank": "true", style: BLANK_STYLE, children: s.text }, i) : /* @__PURE__ */ jsx10(Fragment3, { children: s.text }, i)
2649
3047
  );
2650
3048
  }
2651
3049
  function wrap(text, attrs) {
2652
3050
  let node = decorateBlanks(text);
2653
3051
  if (!attrs) return node;
2654
- if (attrs.bold) node = /* @__PURE__ */ jsx9("strong", { children: node });
2655
- if (attrs.italic) node = /* @__PURE__ */ jsx9("em", { children: node });
2656
- if (attrs.underline) node = /* @__PURE__ */ jsx9("u", { children: node });
2657
- if (attrs.strike) node = /* @__PURE__ */ jsx9("s", { children: node });
3052
+ if (attrs.bold) node = /* @__PURE__ */ jsx10("strong", { children: node });
3053
+ if (attrs.italic) node = /* @__PURE__ */ jsx10("em", { children: node });
3054
+ if (attrs.underline) node = /* @__PURE__ */ jsx10("u", { children: node });
3055
+ if (attrs.strike) node = /* @__PURE__ */ jsx10("s", { children: node });
2658
3056
  const styleParts = {};
2659
3057
  if (attrs.color) styleParts.color = attrs.color;
2660
3058
  if (attrs.highlight) styleParts.backgroundColor = attrs.highlight;
2661
3059
  if (attrs.fontFamily) styleParts.fontFamily = attrs.fontFamily;
2662
3060
  if (attrs.fontSize) styleParts.fontSize = attrs.fontSize;
2663
3061
  if (Object.keys(styleParts).length > 0) {
2664
- node = /* @__PURE__ */ jsx9("span", { style: styleParts, children: node });
3062
+ node = /* @__PURE__ */ jsx10("span", { style: styleParts, children: node });
2665
3063
  }
2666
3064
  if (attrs.link?.href) {
2667
- node = /* @__PURE__ */ jsx9(
3065
+ node = /* @__PURE__ */ jsx10(
2668
3066
  "a",
2669
3067
  {
2670
3068
  href: attrs.link.href,
@@ -2683,7 +3081,7 @@ function wrap(text, attrs) {
2683
3081
  );
2684
3082
  }
2685
3083
  if (attrs.comment?.markId) {
2686
- node = /* @__PURE__ */ jsx9("span", { "data-comment-id": attrs.comment.markId, className: "ed-comment", children: node });
3084
+ node = /* @__PURE__ */ jsx10("span", { "data-comment-id": attrs.comment.markId, className: "ed-comment", children: node });
2687
3085
  }
2688
3086
  return node;
2689
3087
  }
@@ -2728,21 +3126,30 @@ function sliceDelta(delta, start, end) {
2728
3126
 
2729
3127
  // src/TableResizeOverlay.tsx
2730
3128
  import {
2731
- useCallback as useCallback4,
2732
- useEffect as useEffect7,
3129
+ useCallback as useCallback5,
3130
+ useEffect as useEffect8,
2733
3131
  useLayoutEffect as useLayoutEffect3,
2734
- useRef as useRef6,
2735
- useState as useState7
3132
+ useRef as useRef7,
3133
+ useState as useState8
2736
3134
  } from "react";
2737
- import { Fragment as Fragment4, jsx as jsx10 } from "react/jsx-runtime";
2738
- function TableResizeOverlay({ tableRef, blockIndex, cols }) {
3135
+ import { MIN_LINHA_PX, normalizarLarguras } from "@sofereditor/core";
3136
+ import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
3137
+ function deltaPctDoArrasto(dxPx, larguraTabelaPx) {
3138
+ if (!(larguraTabelaPx > 0)) return 0;
3139
+ return dxPx / larguraTabelaPx * 100;
3140
+ }
3141
+ function distribuirAltura(base, deltaPx) {
3142
+ if (base.length === 0) return base;
3143
+ const fatia = deltaPx / base.length;
3144
+ return base.map((h) => Math.max(MIN_LINHA_PX, Math.round(h + fatia)));
3145
+ }
3146
+ function TableResizeOverlay({ tableRef, blockIndex, cols, rows }) {
2739
3147
  const editor = useEditorContext();
2740
- const [positions, setPositions] = useState7(null);
2741
- const [layout, setLayout] = useState7(null);
2742
- const draggingRef = useRef6(null);
2743
- const measure = useCallback4(() => {
3148
+ const [layout, setLayout] = useState8(null);
3149
+ const arrastoRef = useRef7(null);
3150
+ const measureNow = useCallback5(() => {
2744
3151
  const table = tableRef.current;
2745
- if (!table) return;
3152
+ if (!table) return null;
2746
3153
  const tableRect = table.getBoundingClientRect();
2747
3154
  const cgCols = table.querySelectorAll("colgroup > col");
2748
3155
  let rights = [];
@@ -2765,55 +3172,160 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
2765
3172
  });
2766
3173
  }
2767
3174
  if (rights.length !== cols) {
2768
- setLayout(null);
2769
- return;
3175
+ return null;
2770
3176
  }
2771
- setLayout({ rights, height: tableRect.height });
2772
- }, [cols, tableRef]);
3177
+ const trs = table.querySelectorAll("tbody > tr");
3178
+ const bottoms = [];
3179
+ let accY = 0;
3180
+ trs.forEach((tr) => {
3181
+ accY += tr.getBoundingClientRect().height;
3182
+ bottoms.push(accY);
3183
+ });
3184
+ return {
3185
+ rights,
3186
+ bottoms: trs.length === rows ? bottoms : [],
3187
+ width: tableRect.width,
3188
+ height: tableRect.height
3189
+ };
3190
+ }, [cols, rows, tableRef]);
3191
+ const measure = useCallback5(() => {
3192
+ setLayout(measureNow());
3193
+ }, [measureNow]);
2773
3194
  useLayoutEffect3(() => {
2774
3195
  measure();
2775
3196
  }, [measure]);
2776
- useEffect7(() => {
3197
+ useEffect8(() => {
2777
3198
  const table = tableRef.current;
2778
3199
  if (!table) return;
2779
3200
  const ro = new ResizeObserver(() => measure());
2780
3201
  ro.observe(table);
2781
3202
  return () => ro.disconnect();
2782
3203
  }, [measure, tableRef]);
2783
- const onPointerDown = useCallback4(
2784
- (col) => (e) => {
3204
+ const onPointerUp = useCallback5(
3205
+ (e) => {
3206
+ arrastoRef.current = null;
3207
+ measure();
3208
+ try {
3209
+ e.currentTarget.releasePointerCapture(e.pointerId);
3210
+ } catch {
3211
+ }
3212
+ },
3213
+ [measure]
3214
+ );
3215
+ const onPointerMove = useCallback5(
3216
+ (e) => {
3217
+ const d = arrastoRef.current;
3218
+ if (!d) return;
3219
+ switch (d.tipo) {
3220
+ case "coluna": {
3221
+ const dPct = deltaPctDoArrasto(e.clientX - d.startX, d.tableWidthPx);
3222
+ editor.setColumnBoundary(blockIndex, d.boundary, dPct, d.baseWidths);
3223
+ break;
3224
+ }
3225
+ case "larguraTotal": {
3226
+ const dPct = deltaPctDoArrasto(e.clientX - d.startX, d.utilPx);
3227
+ editor.setTableWidth(blockIndex, d.baseWidthPct + dPct);
3228
+ break;
3229
+ }
3230
+ case "linha": {
3231
+ editor.setRowHeight(blockIndex, d.row, d.baseHeightPx + (e.clientY - d.startY));
3232
+ break;
3233
+ }
3234
+ case "alturaTotal": {
3235
+ editor.setRowHeights(blockIndex, distribuirAltura(d.baseHeights, e.clientY - d.startY));
3236
+ break;
3237
+ }
3238
+ case "canto": {
3239
+ const dPct = deltaPctDoArrasto(e.clientX - d.startX, d.utilPx);
3240
+ editor.setTableWidth(blockIndex, d.baseWidthPct + dPct);
3241
+ editor.setRowHeights(blockIndex, distribuirAltura(d.baseHeights, e.clientY - d.startY));
3242
+ break;
3243
+ }
3244
+ }
3245
+ },
3246
+ [blockIndex, editor]
3247
+ );
3248
+ const containerWidthPxOf = useCallback5((table, tableWidthPx) => {
3249
+ return table.parentElement?.getBoundingClientRect().width || tableWidthPx;
3250
+ }, []);
3251
+ const onColumnPointerDown = useCallback5(
3252
+ (boundary) => (e) => {
2785
3253
  e.preventDefault();
2786
3254
  e.stopPropagation();
2787
3255
  const table = tableRef.current;
2788
3256
  if (!table) return;
2789
- const cgCols = table.querySelectorAll("colgroup > col");
2790
- const startWidth = cgCols[col]?.getBoundingClientRect().width ?? 100;
2791
- draggingRef.current = { col, startX: e.clientX, startWidth };
2792
- setPositions({ x: e.clientX, height: layout?.height ?? 0 });
3257
+ const tableWidthPx = table.getBoundingClientRect().width || 1;
3258
+ const attrs = editor.doc.getBlockAttrs(blockIndex);
3259
+ const baseWidths = normalizarLarguras(attrs.colWidths, cols);
3260
+ arrastoRef.current = { tipo: "coluna", boundary, startX: e.clientX, baseWidths, tableWidthPx };
2793
3261
  e.currentTarget.setPointerCapture(e.pointerId);
2794
3262
  },
2795
- [layout, tableRef]
3263
+ [tableRef, editor, blockIndex, cols]
2796
3264
  );
2797
- const onPointerMove = useCallback4(
3265
+ const onTableWidthPointerDown = useCallback5(
2798
3266
  (e) => {
2799
- const d = draggingRef.current;
2800
- if (!d) return;
2801
- const dx = e.clientX - d.startX;
2802
- const next = Math.max(40, d.startWidth + dx);
2803
- editor.setColumnWidth(blockIndex, d.col, next);
3267
+ e.preventDefault();
3268
+ e.stopPropagation();
3269
+ const table = tableRef.current;
3270
+ if (!table) return;
3271
+ const tableWidthPx = table.getBoundingClientRect().width || 1;
3272
+ const utilPx = containerWidthPxOf(table, tableWidthPx);
3273
+ const attrs = editor.doc.getBlockAttrs(blockIndex);
3274
+ const baseWidthPct = typeof attrs.tableWidth === "number" ? attrs.tableWidth : 100;
3275
+ arrastoRef.current = { tipo: "larguraTotal", startX: e.clientX, baseWidthPct, utilPx };
3276
+ e.currentTarget.setPointerCapture(e.pointerId);
2804
3277
  },
2805
- [blockIndex, editor]
3278
+ [tableRef, editor, blockIndex, containerWidthPxOf]
3279
+ );
3280
+ const heightsFromBottoms = (bottoms) => bottoms.map((b, i) => b - (i === 0 ? 0 : bottoms[i - 1]));
3281
+ const onRowPointerDown = useCallback5(
3282
+ (row) => (e) => {
3283
+ e.preventDefault();
3284
+ e.stopPropagation();
3285
+ const m = measureNow();
3286
+ if (!m || m.bottoms.length === 0) return;
3287
+ const baseHeightPx = m.bottoms[row] - (row === 0 ? 0 : m.bottoms[row - 1]);
3288
+ arrastoRef.current = { tipo: "linha", row, startY: e.clientY, baseHeightPx };
3289
+ e.currentTarget.setPointerCapture(e.pointerId);
3290
+ },
3291
+ [measureNow]
3292
+ );
3293
+ const onTableHeightPointerDown = useCallback5(
3294
+ (e) => {
3295
+ e.preventDefault();
3296
+ e.stopPropagation();
3297
+ const m = measureNow();
3298
+ if (!m || m.bottoms.length === 0) return;
3299
+ arrastoRef.current = { tipo: "alturaTotal", startY: e.clientY, baseHeights: heightsFromBottoms(m.bottoms) };
3300
+ e.currentTarget.setPointerCapture(e.pointerId);
3301
+ },
3302
+ [measureNow]
3303
+ );
3304
+ const onCornerPointerDown = useCallback5(
3305
+ (e) => {
3306
+ e.preventDefault();
3307
+ e.stopPropagation();
3308
+ const table = tableRef.current;
3309
+ const m = measureNow();
3310
+ if (!table || !m) return;
3311
+ const tableWidthPx = table.getBoundingClientRect().width || 1;
3312
+ const utilPx = containerWidthPxOf(table, tableWidthPx);
3313
+ const attrs = editor.doc.getBlockAttrs(blockIndex);
3314
+ const baseWidthPct = typeof attrs.tableWidth === "number" ? attrs.tableWidth : 100;
3315
+ arrastoRef.current = {
3316
+ tipo: "canto",
3317
+ startX: e.clientX,
3318
+ startY: e.clientY,
3319
+ baseWidthPct,
3320
+ utilPx,
3321
+ baseHeights: heightsFromBottoms(m.bottoms)
3322
+ };
3323
+ e.currentTarget.setPointerCapture(e.pointerId);
3324
+ },
3325
+ [tableRef, editor, blockIndex, measureNow, containerWidthPxOf]
2806
3326
  );
2807
- const onPointerUp = useCallback4((e) => {
2808
- draggingRef.current = null;
2809
- setPositions(null);
2810
- try {
2811
- e.currentTarget.releasePointerCapture(e.pointerId);
2812
- } catch {
2813
- }
2814
- }, []);
2815
3327
  if (!layout) return null;
2816
- const handleStyle = (x) => ({
3328
+ const colHandleStyle = (x) => ({
2817
3329
  position: "absolute",
2818
3330
  top: 0,
2819
3331
  left: `${x - 3}px`,
@@ -2822,28 +3334,104 @@ function TableResizeOverlay({ tableRef, blockIndex, cols }) {
2822
3334
  cursor: "col-resize",
2823
3335
  zIndex: 5
2824
3336
  });
2825
- void positions;
2826
- return /* @__PURE__ */ jsx10(Fragment4, { children: layout.rights.map((x, c) => /* @__PURE__ */ jsx10(
2827
- "div",
2828
- {
2829
- contentEditable: false,
2830
- className: "ed-col-resize-handle",
2831
- style: handleStyle(x),
2832
- onPointerDown: onPointerDown(c),
2833
- onPointerMove,
2834
- onPointerUp,
2835
- "aria-label": `Redimensionar coluna ${c + 1}`,
2836
- role: "separator"
2837
- },
2838
- c
2839
- )) });
3337
+ const rowHandleStyle = (y) => ({
3338
+ position: "absolute",
3339
+ left: 0,
3340
+ top: `${y - 3}px`,
3341
+ width: `${layout.width}px`,
3342
+ height: "6px",
3343
+ cursor: "row-resize",
3344
+ zIndex: 5
3345
+ });
3346
+ const cornerHandleStyle = {
3347
+ position: "absolute",
3348
+ left: `${layout.width - 5}px`,
3349
+ top: `${layout.height - 5}px`,
3350
+ width: "10px",
3351
+ height: "10px",
3352
+ cursor: "nwse-resize",
3353
+ zIndex: 6
3354
+ };
3355
+ return /* @__PURE__ */ jsxs11(Fragment4, { children: [
3356
+ layout.rights.map(
3357
+ (x, c) => c < cols - 1 ? /* @__PURE__ */ jsx11(
3358
+ "div",
3359
+ {
3360
+ contentEditable: false,
3361
+ className: "ed-col-resize-handle",
3362
+ style: colHandleStyle(x),
3363
+ onPointerDown: onColumnPointerDown(c),
3364
+ onPointerMove,
3365
+ onPointerUp,
3366
+ "aria-label": `Redimensionar coluna ${c + 1}`,
3367
+ role: "separator"
3368
+ },
3369
+ `col-${c}`
3370
+ ) : /* @__PURE__ */ jsx11(
3371
+ "div",
3372
+ {
3373
+ contentEditable: false,
3374
+ className: "ed-col-resize-handle",
3375
+ style: colHandleStyle(x),
3376
+ onPointerDown: onTableWidthPointerDown,
3377
+ onPointerMove,
3378
+ onPointerUp,
3379
+ "aria-label": "Largura da tabela",
3380
+ role: "separator"
3381
+ },
3382
+ "col-total"
3383
+ )
3384
+ ),
3385
+ layout.bottoms.map(
3386
+ (y, r) => r < rows - 1 ? /* @__PURE__ */ jsx11(
3387
+ "div",
3388
+ {
3389
+ contentEditable: false,
3390
+ className: "ed-row-resize-handle",
3391
+ style: rowHandleStyle(y),
3392
+ onPointerDown: onRowPointerDown(r),
3393
+ onPointerMove,
3394
+ onPointerUp,
3395
+ "aria-label": `Redimensionar linha ${r + 1}`,
3396
+ role: "separator"
3397
+ },
3398
+ `row-${r}`
3399
+ ) : /* @__PURE__ */ jsx11(
3400
+ "div",
3401
+ {
3402
+ contentEditable: false,
3403
+ className: "ed-row-resize-handle",
3404
+ style: rowHandleStyle(y),
3405
+ onPointerDown: onTableHeightPointerDown,
3406
+ onPointerMove,
3407
+ onPointerUp,
3408
+ "aria-label": "Altura da tabela",
3409
+ role: "separator"
3410
+ },
3411
+ "row-total"
3412
+ )
3413
+ ),
3414
+ /* @__PURE__ */ jsx11(
3415
+ "div",
3416
+ {
3417
+ contentEditable: false,
3418
+ className: "ed-table-corner-handle",
3419
+ style: cornerHandleStyle,
3420
+ onPointerDown: onCornerPointerDown,
3421
+ onPointerMove,
3422
+ onPointerUp,
3423
+ "aria-label": "Redimensionar tabela",
3424
+ role: "separator"
3425
+ }
3426
+ )
3427
+ ] });
2840
3428
  }
2841
3429
 
2842
3430
  // src/NodeView.tsx
2843
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
3431
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
2844
3432
  function NodeView({ block, index, children, fragment, tableFragment }) {
2845
3433
  if (block.type === "table") {
2846
- return /* @__PURE__ */ jsx11(TableView, { block, index, tableFragment });
3434
+ return /* @__PURE__ */ jsx12(TableView, { block, index, tableFragment });
2847
3435
  }
2848
3436
  const inline = fragment ? renderInline(sliceDelta(block.delta, fragment.start, fragment.end), index) : renderInline(block.delta, index);
2849
3437
  const common = commonBlockProps(block.attrs, index, block.type, fragment);
@@ -2851,7 +3439,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
2851
3439
  case "heading": {
2852
3440
  const level = clampLevel2(block.attrs.level);
2853
3441
  const Tag = `h${level}`;
2854
- return /* @__PURE__ */ jsx11(
3442
+ return /* @__PURE__ */ jsx12(
2855
3443
  Tag,
2856
3444
  {
2857
3445
  ...common,
@@ -2861,7 +3449,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
2861
3449
  );
2862
3450
  }
2863
3451
  case "blockquote":
2864
- return /* @__PURE__ */ jsx11(
3452
+ return /* @__PURE__ */ jsx12(
2865
3453
  "blockquote",
2866
3454
  {
2867
3455
  ...common,
@@ -2870,18 +3458,18 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
2870
3458
  }
2871
3459
  );
2872
3460
  case "codeBlock":
2873
- return /* @__PURE__ */ jsx11(
3461
+ return /* @__PURE__ */ jsx12(
2874
3462
  "pre",
2875
3463
  {
2876
3464
  ...common,
2877
3465
  "data-language": block.attrs.language ?? void 0,
2878
3466
  className: `ed-block ed-codeblock${alignClass(block.attrs.align)}`,
2879
- children: /* @__PURE__ */ jsx11("code", { children: inline })
3467
+ children: /* @__PURE__ */ jsx12("code", { children: inline })
2880
3468
  }
2881
3469
  );
2882
3470
  case "listItem": {
2883
3471
  const level = clampListLevel(block.attrs.listLevel);
2884
- return /* @__PURE__ */ jsxs10(
3472
+ return /* @__PURE__ */ jsxs12(
2885
3473
  "li",
2886
3474
  {
2887
3475
  ...common,
@@ -2897,7 +3485,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
2897
3485
  }
2898
3486
  case "paragraph":
2899
3487
  default:
2900
- return /* @__PURE__ */ jsx11(
3488
+ return /* @__PURE__ */ jsx12(
2901
3489
  "div",
2902
3490
  {
2903
3491
  ...common,
@@ -2944,12 +3532,35 @@ function clampListLevel(l) {
2944
3532
  if (typeof l !== "number" || !Number.isFinite(l)) return 0;
2945
3533
  return Math.max(0, Math.min(5, Math.trunc(l)));
2946
3534
  }
3535
+ function renderCellContent(attrs, delta, keyPrefix) {
3536
+ const kind = attrs?.listKind;
3537
+ if (!kind) return renderInline(delta, keyPrefix);
3538
+ const linhas = splitDeltaByLines(delta);
3539
+ const Tag = kind === "ordered" ? "ol" : "ul";
3540
+ let baseOffset = 0;
3541
+ return /* @__PURE__ */ jsx12(
3542
+ Tag,
3543
+ {
3544
+ className: `ed-list ed-list-${kind}`,
3545
+ "data-list-kind": kind,
3546
+ start: kind === "ordered" && typeof attrs?.listStart === "number" ? attrs.listStart : void 0,
3547
+ style: attrs?.listStyle ? { listStyleType: attrs.listStyle } : void 0,
3548
+ children: linhas.map((linha, i) => {
3549
+ const li = /* @__PURE__ */ jsx12("li", { className: "ed-listitem", "data-cell-line": i, children: renderInline(linha, `${keyPrefix}-l${i}`, baseOffset) }, i);
3550
+ baseOffset += deltaLength2(linha) + 1;
3551
+ return li;
3552
+ })
3553
+ }
3554
+ );
3555
+ }
2947
3556
  function TableView({ block, index, tableFragment }) {
2948
3557
  const rows = clampPositive(block.attrs.rows);
2949
3558
  const cols = clampPositive(block.attrs.cols);
2950
3559
  const cells = block.cells ?? [];
2951
- const widths = readColWidths(block.attrs.colWidths, cols);
2952
- const tableRef = useRef7(null);
3560
+ const widths = normalizarLarguras2(block.attrs.colWidths, cols);
3561
+ const tableWidth = block.attrs.tableWidth;
3562
+ const rowHeights = block.attrs.rowHeights;
3563
+ const tableRef = useRef8(null);
2953
3564
  const rowStart = tableFragment?.rowStart ?? 0;
2954
3565
  const rowEnd = tableFragment?.rowEnd ?? rows;
2955
3566
  const isFirstFragment = !tableFragment || tableFragment.index === 0;
@@ -2959,69 +3570,69 @@ function TableView({ block, index, tableFragment }) {
2959
3570
  if (editor.selection.focus.blockIndex !== index) return null;
2960
3571
  return tableRectSelection(editor.doc, editor.selection);
2961
3572
  }, [editor.doc, editor.selection, index]);
2962
- return /* @__PURE__ */ jsxs10("div", { className: "ed-table-wrap", children: [
2963
- /* @__PURE__ */ jsxs10(
3573
+ return /* @__PURE__ */ jsxs12("div", { className: "ed-table-wrap", children: [
3574
+ /* @__PURE__ */ jsxs12(
2964
3575
  "table",
2965
3576
  {
2966
3577
  ref: tableRef,
2967
3578
  "data-block-index": index,
2968
3579
  "data-block-type": "table",
2969
3580
  className: "ed-block ed-table",
3581
+ style: typeof tableWidth === "number" ? { width: `${tableWidth}%` } : void 0,
2970
3582
  children: [
2971
- widths && /* @__PURE__ */ jsx11("colgroup", { children: widths.map((w, c) => /* @__PURE__ */ jsx11("col", { style: w != null ? { width: `${w}px` } : void 0 }, c)) }),
2972
- /* @__PURE__ */ jsx11("tbody", { children: Array.from({ length: rowEnd - rowStart }, (_, i) => {
3583
+ /* @__PURE__ */ jsx12("colgroup", { children: widths.map((w, c) => /* @__PURE__ */ jsx12("col", { style: { width: `${w}%` } }, c)) }),
3584
+ /* @__PURE__ */ jsx12("tbody", { children: Array.from({ length: rowEnd - rowStart }, (_, i) => {
2973
3585
  const r = rowStart + i;
2974
- return /* @__PURE__ */ jsx11("tr", { "data-cell-row": r, children: Array.from({ length: cols }, (_2, c) => {
2975
- const flat = r * cols + c;
2976
- const cell = cells[flat];
2977
- if (cell?.attrs.covered === true) return null;
2978
- const rowspan = spanAttr(cell?.attrs.rowspan);
2979
- const colspan = spanAttr(cell?.attrs.colspan);
2980
- const delta = cell?.delta ?? [];
2981
- const inRect = rect !== null && r >= rect.top && r <= rect.bottom && c >= rect.left && c <= rect.right;
2982
- return /* @__PURE__ */ jsx11(
2983
- "td",
2984
- {
2985
- "data-cell-index": flat,
2986
- "data-cell-row": r,
2987
- "data-cell-col": c,
2988
- "data-cell-rowspan": rowspan,
2989
- "data-cell-colspan": colspan,
2990
- rowSpan: rowspan > 1 ? rowspan : void 0,
2991
- colSpan: colspan > 1 ? colspan : void 0,
2992
- style: cellStyle(
2993
- cell?.attrs,
2994
- // rowStart/rowEnd são os limites do FRAGMENTO: numa tabela
2995
- // quebrada entre páginas, cada página fecha a própria caixa.
2996
- cellBorderStyle(
2997
- block.attrs.borderPreset,
2998
- { row: r, col: c, rowspan, colspan, cols, rowStart, rowEnd },
2999
- "screen",
3000
- block.attrs.borderColor
3001
- )
3002
- ),
3003
- className: inRect ? "ed-cell ed-cell--selected" : "ed-cell",
3004
- children: renderInline(delta, `t${index}-c${flat}`)
3005
- },
3006
- c
3007
- );
3008
- }) }, r);
3586
+ return /* @__PURE__ */ jsx12(
3587
+ "tr",
3588
+ {
3589
+ "data-cell-row": r,
3590
+ style: typeof rowHeights?.[r] === "number" ? { height: `${rowHeights[r]}px` } : void 0,
3591
+ children: Array.from({ length: cols }, (_2, c) => {
3592
+ const flat = r * cols + c;
3593
+ const cell = cells[flat];
3594
+ if (cell?.attrs.covered === true) return null;
3595
+ const rowspan = spanAttr(cell?.attrs.rowspan);
3596
+ const colspan = spanAttr(cell?.attrs.colspan);
3597
+ const delta = cell?.delta ?? [];
3598
+ const inRect = rect !== null && r >= rect.top && r <= rect.bottom && c >= rect.left && c <= rect.right;
3599
+ return /* @__PURE__ */ jsx12(
3600
+ "td",
3601
+ {
3602
+ "data-cell-index": flat,
3603
+ "data-cell-row": r,
3604
+ "data-cell-col": c,
3605
+ "data-cell-rowspan": rowspan,
3606
+ "data-cell-colspan": colspan,
3607
+ rowSpan: rowspan > 1 ? rowspan : void 0,
3608
+ colSpan: colspan > 1 ? colspan : void 0,
3609
+ style: cellStyle(
3610
+ cell?.attrs,
3611
+ // rowStart/rowEnd são os limites do FRAGMENTO: numa tabela
3612
+ // quebrada entre páginas, cada página fecha a própria caixa.
3613
+ cellBorderStyle(
3614
+ block.attrs.borderPreset,
3615
+ { row: r, col: c, rowspan, colspan, cols, rowStart, rowEnd },
3616
+ "screen",
3617
+ block.attrs.borderColor
3618
+ )
3619
+ ),
3620
+ className: inRect ? "ed-cell ed-cell--selected" : "ed-cell",
3621
+ children: renderCellContent(cell?.attrs, delta, `t${index}-c${flat}`)
3622
+ },
3623
+ c
3624
+ );
3625
+ })
3626
+ },
3627
+ r
3628
+ );
3009
3629
  }) })
3010
3630
  ]
3011
3631
  }
3012
3632
  ),
3013
- isFirstFragment && /* @__PURE__ */ jsx11(TableResizeOverlay, { tableRef, blockIndex: index, cols })
3633
+ isFirstFragment && /* @__PURE__ */ jsx12(TableResizeOverlay, { tableRef, blockIndex: index, cols, rows })
3014
3634
  ] });
3015
3635
  }
3016
- function readColWidths(raw, cols) {
3017
- if (!Array.isArray(raw)) return null;
3018
- const out = [];
3019
- for (let i = 0; i < cols; i++) {
3020
- const v = raw[i];
3021
- out.push(typeof v === "number" && Number.isFinite(v) && v > 0 ? v : null);
3022
- }
3023
- return out;
3024
- }
3025
3636
  function spanAttr(v) {
3026
3637
  if (typeof v !== "number" || !Number.isFinite(v) || v < 1) return 1;
3027
3638
  return Math.trunc(v);
@@ -3032,7 +3643,7 @@ function clampPositive(n) {
3032
3643
  }
3033
3644
 
3034
3645
  // src/usePagination.ts
3035
- import { useLayoutEffect as useLayoutEffect4, useRef as useRef8, useState as useState8 } from "react";
3646
+ import { useLayoutEffect as useLayoutEffect4, useRef as useRef9, useState as useState9 } from "react";
3036
3647
  var A4_PAGE = {
3037
3648
  width: 794,
3038
3649
  height: 1123,
@@ -3058,9 +3669,9 @@ function defaultPageLayout(topLevelCount) {
3058
3669
  };
3059
3670
  }
3060
3671
  function usePageLayout(rootRef, geometry, topLevelCount, deps) {
3061
- const [phase, setPhase] = useState8("measure");
3062
- const [layout, setLayout] = useState8(() => defaultPageLayout(topLevelCount));
3063
- const lastDepsRef = useRef8(null);
3672
+ const [phase, setPhase] = useState9("measure");
3673
+ const [layout, setLayout] = useState9(() => defaultPageLayout(topLevelCount));
3674
+ const lastDepsRef = useRef9(null);
3064
3675
  useLayoutEffect4(() => {
3065
3676
  const currentDeps = [...deps, topLevelCount, geometry];
3066
3677
  if (lastDepsRef.current !== null && shallowArrayEqual(lastDepsRef.current, currentDeps)) {
@@ -3545,17 +4156,17 @@ function layoutsDeepEqual(a, b) {
3545
4156
  }
3546
4157
 
3547
4158
  // src/useEditor.ts
3548
- import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo3, useRef as useRef10, useState as useState9 } from "react";
4159
+ import { useCallback as useCallback7, useEffect as useEffect9, useMemo as useMemo3, useRef as useRef11, useState as useState10 } from "react";
3549
4160
 
3550
4161
  // src/usePageSettings.ts
3551
- import { useCallback as useCallback5, useRef as useRef9, useSyncExternalStore } from "react";
4162
+ import { useCallback as useCallback6, useRef as useRef10, useSyncExternalStore } from "react";
3552
4163
  function usePageSettings(doc) {
3553
- const cacheRef = useRef9(null);
3554
- const subscribe = useCallback5(
4164
+ const cacheRef = useRef10(null);
4165
+ const subscribe = useCallback6(
3555
4166
  (notify) => doc.observePageSettings(notify),
3556
4167
  [doc]
3557
4168
  );
3558
- const getSnapshot = useCallback5(() => {
4169
+ const getSnapshot = useCallback6(() => {
3559
4170
  const next = doc.getPageSettings();
3560
4171
  const prev = cacheRef.current;
3561
4172
  if (prev && shallowEqual(prev, next)) return prev;
@@ -3583,8 +4194,10 @@ import {
3583
4194
  mergeSelection as cmdMergeSelection,
3584
4195
  moveEmbedAnchor as cmdMoveEmbedAnchor,
3585
4196
  setBlockAttrAtIndex as cmdSetBlockAttrAtIndex,
3586
- setColumnWidth as cmdSetColumnWidth,
4197
+ setColumnBoundary as cmdSetColumnBoundary,
3587
4198
  setImageAttrs as cmdSetImageAttrs,
4199
+ setRowHeight as cmdSetRowHeight,
4200
+ setRowHeights as cmdSetRowHeights,
3588
4201
  splitCell as cmdSplitCell,
3589
4202
  tableRectSelection as tableRectSelection2,
3590
4203
  getMarksInRange,
@@ -3593,6 +4206,7 @@ import {
3593
4206
  insertTable as cmdInsertTable,
3594
4207
  insertTableColumn as cmdInsertColumn,
3595
4208
  insertTableRow as cmdInsertRow,
4209
+ isFormulaEmbed,
3596
4210
  isImageEmbed as isImageEmbed4,
3597
4211
  isMarkUniformInRange,
3598
4212
  moveToNextCell as cmdMoveNextCell,
@@ -3603,6 +4217,7 @@ import {
3603
4217
  setCellAttr as cmdSetCellAttr,
3604
4218
  setBlockType as cmdSetBlockType,
3605
4219
  setMark as cmdSetMark,
4220
+ setTableWidth as cmdSetTableWidth,
3606
4221
  splitListItem as cmdSplitListItem,
3607
4222
  tableLocationOf,
3608
4223
  toggleList as cmdToggleList,
@@ -3611,19 +4226,19 @@ import {
3611
4226
  function useEditor(opts = {}) {
3612
4227
  const doc = useMemo3(() => opts.document ?? new EditorDocument(), [opts.document]);
3613
4228
  const history = useMemo3(() => new EditorHistory(doc), [doc]);
3614
- const [snapshot, setSnapshot] = useState9(() => doc.toJSON());
3615
- const [selection, setSelectionState] = useState9(
4229
+ const [snapshot, setSnapshot] = useState10(() => doc.toJSON());
4230
+ const [selection, setSelectionState] = useState10(
3616
4231
  () => collapsedSelection({ blockIndex: 0, offset: 0 })
3617
4232
  );
3618
- const selectionRef = useRef10(selection);
4233
+ const selectionRef = useRef11(selection);
3619
4234
  selectionRef.current = selection;
3620
- const pendingMarksRef = useRef10({});
3621
- const [pendingMarks, setPendingMarksState] = useState9({});
3622
- const setPendingMarks = useCallback6((next) => {
4235
+ const pendingMarksRef = useRef11({});
4236
+ const [pendingMarks, setPendingMarksState] = useState10({});
4237
+ const setPendingMarks = useCallback7((next) => {
3623
4238
  pendingMarksRef.current = next;
3624
4239
  setPendingMarksState(next);
3625
4240
  }, []);
3626
- useEffect8(() => {
4241
+ useEffect9(() => {
3627
4242
  let scheduled = false;
3628
4243
  let cancelled = false;
3629
4244
  let frame = 0;
@@ -3650,8 +4265,8 @@ function useEditor(opts = {}) {
3650
4265
  doc.ydoc.off("afterTransaction", schedule);
3651
4266
  };
3652
4267
  }, [doc]);
3653
- const getSelection = useCallback6(() => selectionRef.current, []);
3654
- const setSelection = useCallback6(
4268
+ const getSelection = useCallback7(() => selectionRef.current, []);
4269
+ const setSelection = useCallback7(
3655
4270
  (sel) => {
3656
4271
  const prev = selectionRef.current;
3657
4272
  selectionRef.current = sel;
@@ -3666,16 +4281,16 @@ function useEditor(opts = {}) {
3666
4281
  },
3667
4282
  []
3668
4283
  );
3669
- const ctxRef = useRef10({ doc, getSelection, setSelection });
4284
+ const ctxRef = useRef11({ doc, getSelection, setSelection });
3670
4285
  ctxRef.current = { doc, getSelection, setSelection };
3671
- const consumePendingMarks = useCallback6(() => {
4286
+ const consumePendingMarks = useCallback7(() => {
3672
4287
  const current = pendingMarksRef.current;
3673
4288
  if (Object.keys(current).length === 0) return void 0;
3674
4289
  pendingMarksRef.current = {};
3675
4290
  setPendingMarksState({});
3676
4291
  return current;
3677
4292
  }, []);
3678
- const isMarkActive = useCallback6(
4293
+ const isMarkActive = useCallback7(
3679
4294
  (name, value) => {
3680
4295
  const sel = selectionRef.current;
3681
4296
  const { start, end } = orderedRange(sel);
@@ -3706,7 +4321,7 @@ function useEditor(opts = {}) {
3706
4321
  },
3707
4322
  [doc]
3708
4323
  );
3709
- const getActiveMarks = useCallback6(() => {
4324
+ const getActiveMarks = useCallback7(() => {
3710
4325
  const sel = selectionRef.current;
3711
4326
  const { start, end } = orderedRange(sel);
3712
4327
  if (start.blockIndex !== end.blockIndex) {
@@ -3720,7 +4335,7 @@ function useEditor(opts = {}) {
3720
4335
  }
3721
4336
  return getMarksInRange(yText, start.offset, end.offset);
3722
4337
  }, [doc]);
3723
- const toggleMark = useCallback6(
4338
+ const toggleMark = useCallback7(
3724
4339
  (name, value) => {
3725
4340
  const sel = selectionRef.current;
3726
4341
  const { start, end } = orderedRange(sel);
@@ -3740,7 +4355,7 @@ function useEditor(opts = {}) {
3740
4355
  },
3741
4356
  [isMarkActive, setPendingMarks]
3742
4357
  );
3743
- const setMark = useCallback6(
4358
+ const setMark = useCallback7(
3744
4359
  (name, value) => {
3745
4360
  const sel = selectionRef.current;
3746
4361
  const { start, end } = orderedRange(sel);
@@ -3753,7 +4368,7 @@ function useEditor(opts = {}) {
3753
4368
  },
3754
4369
  [setPendingMarks]
3755
4370
  );
3756
- const removeMark = useCallback6(
4371
+ const removeMark = useCallback7(
3757
4372
  (name) => {
3758
4373
  const sel = selectionRef.current;
3759
4374
  const { start, end } = orderedRange(sel);
@@ -3766,7 +4381,7 @@ function useEditor(opts = {}) {
3766
4381
  },
3767
4382
  [setPendingMarks]
3768
4383
  );
3769
- const getBlockType = useCallback6(() => {
4384
+ const getBlockType = useCallback7(() => {
3770
4385
  const sel = selectionRef.current;
3771
4386
  const { start, end } = orderedRange(sel);
3772
4387
  const first = doc.getBlockType(start.blockIndex);
@@ -3776,7 +4391,7 @@ function useEditor(opts = {}) {
3776
4391
  }
3777
4392
  return first;
3778
4393
  }, [doc]);
3779
- const getBlockAttr = useCallback6(
4394
+ const getBlockAttr = useCallback7(
3780
4395
  (key) => {
3781
4396
  const sel = selectionRef.current;
3782
4397
  const { start, end } = orderedRange(sel);
@@ -3789,59 +4404,63 @@ function useEditor(opts = {}) {
3789
4404
  },
3790
4405
  [doc]
3791
4406
  );
3792
- const setBlockType = useCallback6((type, attrs) => {
4407
+ const setBlockType = useCallback7((type, attrs) => {
3793
4408
  cmdSetBlockType(ctxRef.current, type, attrs);
3794
4409
  }, []);
3795
- const setBlockAttr = useCallback6(
4410
+ const setBlockAttr = useCallback7(
3796
4411
  (key, value) => {
3797
4412
  cmdSetBlockAttr(ctxRef.current, key, value);
3798
4413
  },
3799
4414
  []
3800
4415
  );
3801
- const setAlign = useCallback6((value) => {
4416
+ const setAlign = useCallback7((value) => {
3802
4417
  const sel = selectionRef.current;
3803
4418
  const inCell = sel.focus.cellIndex != null;
3804
4419
  if (inCell) cmdSetCellAttr(ctxRef.current, "align", value);
3805
4420
  else cmdSetBlockAttr(ctxRef.current, "align", value);
3806
4421
  }, []);
3807
- const getAlign = useCallback6(() => {
4422
+ const getAlign = useCallback7(() => {
3808
4423
  const sel = selectionRef.current;
3809
4424
  if (sel.focus.cellIndex != null && doc.isTable(sel.focus.blockIndex)) {
3810
4425
  return doc.getCellAttrs(sel.focus.blockIndex, sel.focus.cellIndex).align;
3811
4426
  }
3812
4427
  return getBlockAttr("align");
3813
4428
  }, [doc, getBlockAttr]);
3814
- const setCellBackground = useCallback6((color) => {
4429
+ const setCellBackground = useCallback7((color) => {
3815
4430
  cmdSetCellAttr(ctxRef.current, "bgColor", color);
3816
4431
  }, []);
3817
- const getCellBackground = useCallback6(() => {
4432
+ const getCellBackground = useCallback7(() => {
3818
4433
  const sel = selectionRef.current;
3819
4434
  if (sel.focus.cellIndex == null || !doc.isTable(sel.focus.blockIndex)) return void 0;
3820
4435
  return doc.getCellAttrs(sel.focus.blockIndex, sel.focus.cellIndex).bgColor;
3821
4436
  }, [doc]);
3822
- const setTableBorderPreset = useCallback6((preset) => {
4437
+ const setTableBorderPreset = useCallback7((preset) => {
3823
4438
  const sel = selectionRef.current;
3824
4439
  if (!doc.isTable(sel.focus.blockIndex)) return;
3825
4440
  cmdSetBlockAttrAtIndex(ctxRef.current, sel.focus.blockIndex, "borderPreset", preset);
3826
4441
  }, [doc]);
3827
- const getTableBorderPreset = useCallback6(() => {
4442
+ const getTableBorderPreset = useCallback7(() => {
3828
4443
  const sel = selectionRef.current;
3829
4444
  if (!doc.isTable(sel.focus.blockIndex)) return "all";
3830
4445
  return doc.getBlockAttrs(sel.focus.blockIndex).borderPreset ?? "all";
3831
4446
  }, [doc]);
3832
- const setTableBorderColor = useCallback6((color) => {
4447
+ const setTableBorderColor = useCallback7((color) => {
3833
4448
  const sel = selectionRef.current;
3834
4449
  if (!doc.isTable(sel.focus.blockIndex)) return;
3835
4450
  cmdSetBlockAttrAtIndex(ctxRef.current, sel.focus.blockIndex, "borderColor", color);
3836
4451
  }, [doc]);
3837
- const getTableBorderColor = useCallback6(() => {
4452
+ const getTableBorderColor = useCallback7(() => {
3838
4453
  const sel = selectionRef.current;
3839
4454
  if (!doc.isTable(sel.focus.blockIndex)) return void 0;
3840
4455
  return doc.getBlockAttrs(sel.focus.blockIndex).borderColor;
3841
4456
  }, [doc]);
3842
- const isListActive = useCallback6(
4457
+ const isListActive = useCallback7(
3843
4458
  (kind) => {
3844
4459
  const sel = selectionRef.current;
4460
+ if (sel.focus.cellIndex != null && doc.isTable(sel.focus.blockIndex)) {
4461
+ const real = doc.realCellIndex(sel.focus.blockIndex, sel.focus.cellIndex);
4462
+ return real != null && doc.getCellAttrs(sel.focus.blockIndex, real).listKind === kind;
4463
+ }
3845
4464
  const { start, end } = orderedRange(sel);
3846
4465
  for (let i = start.blockIndex; i <= end.blockIndex; i++) {
3847
4466
  if (doc.getBlockType(i) !== "listItem") return false;
@@ -3851,119 +4470,128 @@ function useEditor(opts = {}) {
3851
4470
  },
3852
4471
  [doc]
3853
4472
  );
3854
- const toggleList = useCallback6((kind) => {
4473
+ const toggleList = useCallback7((kind) => {
3855
4474
  cmdToggleList(ctxRef.current, kind);
3856
4475
  }, []);
3857
- const indentList = useCallback6(() => {
4476
+ const indentList = useCallback7(() => {
3858
4477
  cmdIndentList(ctxRef.current);
3859
4478
  }, []);
3860
- const dedentList = useCallback6(() => {
4479
+ const dedentList = useCallback7(() => {
3861
4480
  cmdDedentList(ctxRef.current);
3862
4481
  }, []);
3863
- const splitListItem = useCallback6(() => {
4482
+ const splitListItem = useCallback7(() => {
3864
4483
  return cmdSplitListItem(ctxRef.current);
3865
4484
  }, []);
3866
- const isInTable = useCallback6(() => {
4485
+ const isInTable = useCallback7(() => {
3867
4486
  return selectionRef.current.focus.cellIndex != null;
3868
4487
  }, []);
3869
- const getTableLocation = useCallback6(() => {
4488
+ const getTableLocation = useCallback7(() => {
3870
4489
  return tableLocationOf(doc, selectionRef.current.focus);
3871
4490
  }, [doc]);
3872
- const insertTable = useCallback6((rows, cols) => {
4491
+ const insertTable = useCallback7((rows, cols) => {
3873
4492
  cmdInsertTable(ctxRef.current, rows, cols);
3874
4493
  }, []);
3875
- const insertAnswerLines = useCallback6((count, spacing) => {
4494
+ const insertAnswerLines = useCallback7((count, spacing) => {
3876
4495
  cmdInsertAnswerLines(ctxRef.current, count, spacing);
3877
4496
  }, []);
3878
- const deleteTable = useCallback6((blockIndex) => {
4497
+ const deleteTable = useCallback7((blockIndex) => {
3879
4498
  const idx = blockIndex ?? selectionRef.current.focus.blockIndex;
3880
4499
  cmdDeleteTable(ctxRef.current, idx);
3881
4500
  }, []);
3882
- const insertRowAbove = useCallback6(() => {
4501
+ const insertRowAbove = useCallback7(() => {
3883
4502
  const loc = tableLocationOf(doc, selectionRef.current.focus);
3884
4503
  if (!loc) return;
3885
4504
  cmdInsertRow(ctxRef.current, loc.blockIndex, loc.row, "before");
3886
4505
  }, [doc]);
3887
- const insertRowBelow = useCallback6(() => {
4506
+ const insertRowBelow = useCallback7(() => {
3888
4507
  const loc = tableLocationOf(doc, selectionRef.current.focus);
3889
4508
  if (!loc) return;
3890
4509
  cmdInsertRow(ctxRef.current, loc.blockIndex, loc.row, "after");
3891
4510
  }, [doc]);
3892
- const deleteCurrentRow = useCallback6(() => {
4511
+ const deleteCurrentRow = useCallback7(() => {
3893
4512
  const loc = tableLocationOf(doc, selectionRef.current.focus);
3894
4513
  if (!loc) return;
3895
4514
  cmdDeleteRow(ctxRef.current, loc.blockIndex, loc.row);
3896
4515
  }, [doc]);
3897
- const insertColumnLeft = useCallback6(() => {
4516
+ const insertColumnLeft = useCallback7(() => {
3898
4517
  const loc = tableLocationOf(doc, selectionRef.current.focus);
3899
4518
  if (!loc) return;
3900
4519
  cmdInsertColumn(ctxRef.current, loc.blockIndex, loc.col, "before");
3901
4520
  }, [doc]);
3902
- const insertColumnRight = useCallback6(() => {
4521
+ const insertColumnRight = useCallback7(() => {
3903
4522
  const loc = tableLocationOf(doc, selectionRef.current.focus);
3904
4523
  if (!loc) return;
3905
4524
  cmdInsertColumn(ctxRef.current, loc.blockIndex, loc.col, "after");
3906
4525
  }, [doc]);
3907
- const deleteCurrentColumn = useCallback6(() => {
4526
+ const deleteCurrentColumn = useCallback7(() => {
3908
4527
  const loc = tableLocationOf(doc, selectionRef.current.focus);
3909
4528
  if (!loc) return;
3910
4529
  cmdDeleteColumn(ctxRef.current, loc.blockIndex, loc.col);
3911
4530
  }, [doc]);
3912
- const moveToNextCell = useCallback6(() => {
4531
+ const moveToNextCell = useCallback7(() => {
3913
4532
  cmdMoveNextCell(ctxRef.current);
3914
4533
  }, []);
3915
- const moveToPrevCell = useCallback6(() => {
4534
+ const moveToPrevCell = useCallback7(() => {
3916
4535
  cmdMovePrevCell(ctxRef.current);
3917
4536
  }, []);
3918
- const mergeRight = useCallback6(() => {
4537
+ const mergeRight = useCallback7(() => {
3919
4538
  const loc = tableLocationOf(doc, selectionRef.current.focus);
3920
4539
  if (!loc) return false;
3921
4540
  return cmdMergeRight(ctxRef.current, loc.blockIndex, loc.row, loc.col);
3922
4541
  }, [doc]);
3923
- const mergeDown = useCallback6(() => {
4542
+ const mergeDown = useCallback7(() => {
3924
4543
  const loc = tableLocationOf(doc, selectionRef.current.focus);
3925
4544
  if (!loc) return false;
3926
4545
  return cmdMergeDown(ctxRef.current, loc.blockIndex, loc.row, loc.col);
3927
4546
  }, [doc]);
3928
- const splitCell = useCallback6(() => {
4547
+ const splitCell = useCallback7(() => {
3929
4548
  const loc = tableLocationOf(doc, selectionRef.current.focus);
3930
4549
  if (!loc) return false;
3931
4550
  return cmdSplitCell(ctxRef.current, loc.blockIndex, loc.row, loc.col);
3932
4551
  }, [doc]);
3933
- const setColumnWidth = useCallback6(
3934
- (blockIndex, col, widthPx) => {
3935
- cmdSetColumnWidth(ctxRef.current, blockIndex, col, widthPx);
4552
+ const setColumnBoundary = useCallback7(
4553
+ (blockIndex, boundary, deltaPct, base) => {
4554
+ cmdSetColumnBoundary(ctxRef.current, blockIndex, boundary, deltaPct, base);
3936
4555
  },
3937
4556
  []
3938
4557
  );
3939
- const getTableRect = useCallback6(
4558
+ const setTableWidth = useCallback7((blockIndex, pct) => {
4559
+ cmdSetTableWidth(ctxRef.current, blockIndex, pct);
4560
+ }, []);
4561
+ const setRowHeight = useCallback7((blockIndex, row, px) => {
4562
+ cmdSetRowHeight(ctxRef.current, blockIndex, row, px);
4563
+ }, []);
4564
+ const setRowHeights = useCallback7((blockIndex, heights) => {
4565
+ cmdSetRowHeights(ctxRef.current, blockIndex, heights);
4566
+ }, []);
4567
+ const getTableRect = useCallback7(
3940
4568
  () => tableRectSelection2(doc, selectionRef.current),
3941
4569
  [doc]
3942
4570
  );
3943
- const hasTableRectSelection = useCallback6(() => {
4571
+ const hasTableRectSelection = useCallback7(() => {
3944
4572
  return tableRectSelection2(doc, selectionRef.current) !== null;
3945
4573
  }, [doc]);
3946
- const mergeSelection = useCallback6(() => {
4574
+ const mergeSelection = useCallback7(() => {
3947
4575
  return cmdMergeSelection(ctxRef.current);
3948
4576
  }, []);
3949
- const insertImage = useCallback6((embed) => {
4577
+ const insertImage = useCallback7((embed) => {
3950
4578
  cmdInsertImage(ctxRef.current, embed);
3951
4579
  }, []);
3952
- const setImageAttrs = useCallback6(
4580
+ const setImageAttrs = useCallback7(
3953
4581
  (blockIndex, offset, partial, cellIndex, newOffset) => {
3954
4582
  cmdSetImageAttrs(ctxRef.current, blockIndex, offset, partial, cellIndex, newOffset);
3955
4583
  },
3956
4584
  []
3957
4585
  );
3958
- const moveEmbedAnchor = useCallback6(
4586
+ const moveEmbedAnchor = useCallback7(
3959
4587
  (from, to, newOffsetX, newOffsetY) => {
3960
4588
  cmdMoveEmbedAnchor(ctxRef.current, from, to, newOffsetX, newOffsetY);
3961
4589
  },
3962
4590
  []
3963
4591
  );
3964
- const uploadImageRef = useRef10(opts.uploadImage);
4592
+ const uploadImageRef = useRef11(opts.uploadImage);
3965
4593
  uploadImageRef.current = opts.uploadImage;
3966
- const insertImageFromFile = useCallback6(async (file) => {
4594
+ const insertImageFromFile = useCallback7(async (file) => {
3967
4595
  if (!file.type.startsWith("image/")) return;
3968
4596
  const dataUrl = await readAsDataURL(file);
3969
4597
  const dims = await readImageDimensions(dataUrl);
@@ -3977,7 +4605,7 @@ function useEditor(opts = {}) {
3977
4605
  const src = upload ? await upload(file) : dataUrl;
3978
4606
  cmdInsertImage(ctxRef.current, { type: "image", src, width: w, height: h });
3979
4607
  }, []);
3980
- const getSelectedEmbed = useCallback6(() => {
4608
+ const getSelectedEmbed = useCallback7(() => {
3981
4609
  const sel = selectionRef.current;
3982
4610
  if (sel.anchor.blockIndex !== sel.focus.blockIndex) return null;
3983
4611
  if ((sel.anchor.cellIndex ?? -1) !== (sel.focus.cellIndex ?? -1)) return null;
@@ -4006,16 +4634,16 @@ function useEditor(opts = {}) {
4006
4634
  }
4007
4635
  return null;
4008
4636
  }, [doc]);
4009
- const [linkRequest, setLinkRequest] = useState9(null);
4010
- const linkRequestRef = useRef10(null);
4011
- const requestLink = useCallback6((initialHref = "") => {
4637
+ const [linkRequest, setLinkRequest] = useState10(null);
4638
+ const linkRequestRef = useRef11(null);
4639
+ const requestLink = useCallback7((initialHref = "") => {
4012
4640
  return new Promise((resolve) => {
4013
4641
  const req = { initialHref, resolve, selection: selectionRef.current };
4014
4642
  linkRequestRef.current = req;
4015
4643
  setLinkRequest(req);
4016
4644
  });
4017
4645
  }, []);
4018
- const resolveLinkRequest = useCallback6(
4646
+ const resolveLinkRequest = useCallback7(
4019
4647
  (href) => {
4020
4648
  const req = linkRequestRef.current;
4021
4649
  linkRequestRef.current = null;
@@ -4028,26 +4656,26 @@ function useEditor(opts = {}) {
4028
4656
  [setSelection]
4029
4657
  );
4030
4658
  const pageSettings = usePageSettings(doc);
4031
- const setPageSettings = useCallback6(
4659
+ const setPageSettings = useCallback7(
4032
4660
  (partial) => {
4033
4661
  doc.setPageSettings(partial);
4034
4662
  },
4035
4663
  [doc]
4036
4664
  );
4037
- const [pageConfigRequest, setPageConfigRequest] = useState9(null);
4038
- const requestPageConfig = useCallback6(() => {
4665
+ const [pageConfigRequest, setPageConfigRequest] = useState10(null);
4666
+ const requestPageConfig = useCallback7(() => {
4039
4667
  return new Promise((resolve) => {
4040
4668
  setPageConfigRequest({ initial: doc.getPageSettings(), resolve });
4041
4669
  });
4042
4670
  }, [doc]);
4043
- const resolvePageConfigRequest = useCallback6((applied) => {
4671
+ const resolvePageConfigRequest = useCallback7((applied) => {
4044
4672
  setPageConfigRequest((prev) => {
4045
4673
  if (prev) prev.resolve(applied);
4046
4674
  return null;
4047
4675
  });
4048
4676
  }, []);
4049
- const [imageCaptionRequest, setImageCaptionRequest] = useState9(null);
4050
- const requestImageCaption = useCallback6(
4677
+ const [imageCaptionRequest, setImageCaptionRequest] = useState10(null);
4678
+ const requestImageCaption = useCallback7(
4051
4679
  (initialCaption = "", initialAlign = "center") => {
4052
4680
  return new Promise((resolve) => {
4053
4681
  setImageCaptionRequest({ initialCaption, initialAlign, resolve });
@@ -4055,12 +4683,82 @@ function useEditor(opts = {}) {
4055
4683
  },
4056
4684
  []
4057
4685
  );
4058
- const resolveImageCaptionRequest = useCallback6((result) => {
4686
+ const resolveImageCaptionRequest = useCallback7((result) => {
4059
4687
  setImageCaptionRequest((prev) => {
4060
4688
  if (prev) prev.resolve(result);
4061
4689
  return null;
4062
4690
  });
4063
4691
  }, []);
4692
+ const [formulaRequest, setFormulaRequest] = useState10(null);
4693
+ const requestFormula = useCallback7(
4694
+ (initialLatex = "", initialDisplay = false) => {
4695
+ return new Promise((resolve) => {
4696
+ setFormulaRequest({ initialLatex, initialDisplay, resolve });
4697
+ });
4698
+ },
4699
+ []
4700
+ );
4701
+ const resolveFormulaRequest = useCallback7((result) => {
4702
+ setFormulaRequest((prev) => {
4703
+ if (prev) prev.resolve(result);
4704
+ return null;
4705
+ });
4706
+ }, []);
4707
+ const insertFormula = useCallback7(
4708
+ async (latex, display) => {
4709
+ const selectionAtCall = ctxRef.current.getSelection();
4710
+ const embedAtCall = getSelectedEmbed();
4711
+ let mathModule;
4712
+ try {
4713
+ mathModule = await import("@sofereditor/math");
4714
+ } catch {
4715
+ return;
4716
+ }
4717
+ const { renderLatexToSvg, measureExInPx, svgToDataUrl, svgToPngDataUrl } = mathModule;
4718
+ const r = renderLatexToSvg(latex, display);
4719
+ if (!r.ok) return;
4720
+ const root = document.querySelector(".ed-root");
4721
+ const exPx = root ? measureExInPx(root) : 8;
4722
+ let w = Math.round(r.widthEx * exPx);
4723
+ let h = Math.round(r.heightEx * exPx);
4724
+ let vAlignScale = 1;
4725
+ if (w > MAX_INSERT_WIDTH) {
4726
+ vAlignScale = MAX_INSERT_WIDTH / w;
4727
+ h = Math.round(h * MAX_INSERT_WIDTH / w);
4728
+ w = MAX_INSERT_WIDTH;
4729
+ }
4730
+ const src = svgToDataUrl(r.svg);
4731
+ let svgFallback;
4732
+ try {
4733
+ svgFallback = await svgToPngDataUrl(r.svg, w, h);
4734
+ } catch {
4735
+ svgFallback = void 0;
4736
+ }
4737
+ ctxRef.current.setSelection(selectionAtCall);
4738
+ const inheritedLayout = {};
4739
+ if (isFormulaEmbed(embedAtCall?.embed)) {
4740
+ const prev = embedAtCall.embed;
4741
+ if (prev.layout !== void 0) inheritedLayout.layout = prev.layout;
4742
+ if (prev.offsetX !== void 0) inheritedLayout.offsetX = prev.offsetX;
4743
+ if (prev.offsetY !== void 0) inheritedLayout.offsetY = prev.offsetY;
4744
+ }
4745
+ cmdInsertImage(ctxRef.current, {
4746
+ type: "image",
4747
+ src,
4748
+ width: w,
4749
+ height: h,
4750
+ ...inheritedLayout,
4751
+ ...display ? { align: "center" } : {},
4752
+ formula: {
4753
+ latex,
4754
+ display,
4755
+ ...display ? {} : { vAlign: `${r.vAlignEx * vAlignScale}ex` }
4756
+ },
4757
+ ...svgFallback ? { svgFallback } : {}
4758
+ });
4759
+ },
4760
+ [getSelectedEmbed]
4761
+ );
4064
4762
  return {
4065
4763
  doc,
4066
4764
  history,
@@ -4111,7 +4809,10 @@ function useEditor(opts = {}) {
4111
4809
  mergeRight,
4112
4810
  mergeDown,
4113
4811
  splitCell,
4114
- setColumnWidth,
4812
+ setColumnBoundary,
4813
+ setTableWidth,
4814
+ setRowHeight,
4815
+ setRowHeights,
4115
4816
  getTableRect,
4116
4817
  hasTableRectSelection,
4117
4818
  mergeSelection,
@@ -4128,6 +4829,10 @@ function useEditor(opts = {}) {
4128
4829
  imageCaptionRequest,
4129
4830
  requestImageCaption,
4130
4831
  resolveImageCaptionRequest,
4832
+ formulaRequest,
4833
+ requestFormula,
4834
+ resolveFormulaRequest,
4835
+ insertFormula,
4131
4836
  uploadImage: opts.uploadImage
4132
4837
  };
4133
4838
  }
@@ -4160,7 +4865,7 @@ function sameValue(a, b) {
4160
4865
  }
4161
4866
 
4162
4867
  // src/Editor.tsx
4163
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
4868
+ import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
4164
4869
  var defaultFooter = ({ pageNumber, pageCount }) => `${pageNumber} / ${pageCount}`;
4165
4870
  function Editor({
4166
4871
  editor: providedEditor,
@@ -4173,15 +4878,15 @@ function Editor({
4173
4878
  const internal = useEditor();
4174
4879
  const editor = providedEditor ?? internal;
4175
4880
  const { doc, history, snapshot, getSelection, setSelection } = editor;
4176
- const rootRef = useRef11(null);
4177
- const isComposingRef = useRef11(false);
4178
- const pasteInFlightRef = useRef11(false);
4179
- const [hoveredBehind, setHoveredBehind] = useState10(null);
4180
- const hoveredBehindRef = useRef11(null);
4181
- const [hoveredLink, setHoveredLink] = useState10(null);
4182
- const hoveredLinkElRef = useRef11(null);
4183
- const suppressSelectionSyncRef = useRef11(false);
4184
- useEffect9(() => {
4881
+ const rootRef = useRef12(null);
4882
+ const isComposingRef = useRef12(false);
4883
+ const pasteInFlightRef = useRef12(false);
4884
+ const [hoveredBehind, setHoveredBehind] = useState11(null);
4885
+ const hoveredBehindRef = useRef12(null);
4886
+ const [hoveredLink, setHoveredLink] = useState11(null);
4887
+ const hoveredLinkElRef = useRef12(null);
4888
+ const suppressSelectionSyncRef = useRef12(false);
4889
+ useEffect10(() => {
4185
4890
  if (!awareness) return;
4186
4891
  const root = rootRef.current;
4187
4892
  if (!root) return;
@@ -4211,11 +4916,11 @@ function Editor({
4211
4916
  awareness.setLocalStateField("cursor", null);
4212
4917
  };
4213
4918
  }, [awareness, doc]);
4214
- const ctxRef = useRef11({ doc, getSelection, setSelection });
4919
+ const ctxRef = useRef12({ doc, getSelection, setSelection });
4215
4920
  ctxRef.current = { doc, getSelection, setSelection };
4216
- const historyRef = useRef11(history);
4921
+ const historyRef = useRef12(history);
4217
4922
  historyRef.current = history;
4218
- const editorRef = useRef11(editor);
4923
+ const editorRef = useRef12(editor);
4219
4924
  editorRef.current = editor;
4220
4925
  useLayoutEffect5(() => {
4221
4926
  const root = rootRef.current;
@@ -4232,7 +4937,7 @@ function Editor({
4232
4937
  suppressSelectionSyncRef.current = true;
4233
4938
  applyDomSelection(root, editor.selection);
4234
4939
  });
4235
- useEffect9(() => {
4940
+ useEffect10(() => {
4236
4941
  const root = rootRef.current;
4237
4942
  if (!root) return;
4238
4943
  const handler = () => {
@@ -4253,7 +4958,7 @@ function Editor({
4253
4958
  document.addEventListener("selectionchange", handler);
4254
4959
  return () => document.removeEventListener("selectionchange", handler);
4255
4960
  }, [setSelection]);
4256
- useEffect9(() => {
4961
+ useEffect10(() => {
4257
4962
  const root = rootRef.current;
4258
4963
  if (!root) return;
4259
4964
  let drag = null;
@@ -4324,7 +5029,7 @@ function Editor({
4324
5029
  document.removeEventListener("pointerup", onPointerUp);
4325
5030
  };
4326
5031
  }, []);
4327
- useEffect9(() => {
5032
+ useEffect10(() => {
4328
5033
  const root = rootRef.current;
4329
5034
  if (!root) return;
4330
5035
  const onDragOver = (e) => {
@@ -4362,7 +5067,7 @@ function Editor({
4362
5067
  root.removeEventListener("drop", onDrop);
4363
5068
  };
4364
5069
  }, []);
4365
- useEffect9(() => {
5070
+ useEffect10(() => {
4366
5071
  const root = rootRef.current;
4367
5072
  if (!root) return;
4368
5073
  const onPointerDown = (e) => {
@@ -4390,7 +5095,27 @@ function Editor({
4390
5095
  root.addEventListener("pointerdown", onPointerDown);
4391
5096
  return () => root.removeEventListener("pointerdown", onPointerDown);
4392
5097
  }, []);
4393
- useEffect9(() => {
5098
+ useEffect10(() => {
5099
+ const root = rootRef.current;
5100
+ if (!root) return;
5101
+ const onDoubleClick = (e) => {
5102
+ const target = e.target;
5103
+ if (!(target instanceof Element)) return;
5104
+ if (!target.closest('img[data-embed="image"]')) return;
5105
+ const ed = editorRef.current;
5106
+ const sel = ed.getSelectedEmbed();
5107
+ if (!sel || !isFormulaEmbed2(sel.embed)) return;
5108
+ e.preventDefault();
5109
+ const { latex, display } = sel.embed.formula;
5110
+ void ed.requestFormula(latex, display).then((r) => {
5111
+ if (!r) return;
5112
+ void ed.insertFormula(r.latex, r.display);
5113
+ });
5114
+ };
5115
+ root.addEventListener("dblclick", onDoubleClick);
5116
+ return () => root.removeEventListener("dblclick", onDoubleClick);
5117
+ }, []);
5118
+ useEffect10(() => {
4394
5119
  const root = rootRef.current;
4395
5120
  if (!root) return;
4396
5121
  const same = (a, b) => a === b || !!a && !!b && a.blockIndex === b.blockIndex && a.offset === b.offset && (a.cellIndex ?? -1) === (b.cellIndex ?? -1);
@@ -4443,7 +5168,7 @@ function Editor({
4443
5168
  if (raf) cancelAnimationFrame(raf);
4444
5169
  };
4445
5170
  }, []);
4446
- useEffect9(() => {
5171
+ useEffect10(() => {
4447
5172
  const root = rootRef.current;
4448
5173
  if (!root) return;
4449
5174
  const clear = () => {
@@ -4478,7 +5203,7 @@ function Editor({
4478
5203
  window.removeEventListener("scroll", clear, true);
4479
5204
  };
4480
5205
  }, []);
4481
- useEffect9(() => {
5206
+ useEffect10(() => {
4482
5207
  const root = rootRef.current;
4483
5208
  if (!root) return;
4484
5209
  const handler = (e) => {
@@ -4591,7 +5316,7 @@ function Editor({
4591
5316
  root.addEventListener("beforeinput", handler);
4592
5317
  return () => root.removeEventListener("beforeinput", handler);
4593
5318
  }, []);
4594
- useEffect9(() => {
5319
+ useEffect10(() => {
4595
5320
  const root = rootRef.current;
4596
5321
  if (!root) return;
4597
5322
  const writeSlice = (e) => {
@@ -4684,7 +5409,7 @@ function Editor({
4684
5409
  root.removeEventListener("paste", onPaste);
4685
5410
  };
4686
5411
  }, []);
4687
- const onKeyDown = useCallback7((e) => {
5412
+ const onKeyDown = useCallback8((e) => {
4688
5413
  const ed = editorRef.current;
4689
5414
  const mod = e.metaKey || e.ctrlKey;
4690
5415
  if (e.key === "Tab") {
@@ -4769,10 +5494,10 @@ function Editor({
4769
5494
  });
4770
5495
  }
4771
5496
  }, []);
4772
- const onCompositionStart = useCallback7(() => {
5497
+ const onCompositionStart = useCallback8(() => {
4773
5498
  isComposingRef.current = true;
4774
5499
  }, []);
4775
- const onCompositionEnd = useCallback7((e) => {
5500
+ const onCompositionEnd = useCallback8((e) => {
4776
5501
  isComposingRef.current = false;
4777
5502
  if (e.data && e.data.length > 0) {
4778
5503
  insertText(ctxRef.current, e.data);
@@ -4820,7 +5545,7 @@ function Editor({
4820
5545
  geom.marginRight
4821
5546
  ]
4822
5547
  );
4823
- const body = /* @__PURE__ */ jsxs11(
5548
+ const body = /* @__PURE__ */ jsxs13(
4824
5549
  "div",
4825
5550
  {
4826
5551
  ref: rootRef,
@@ -4846,7 +5571,7 @@ function Editor({
4846
5571
  const pageInlineStyle = pi === 0 && geom.firstPageExtraTop ? {
4847
5572
  "--ed-page-margin-top": `${geom.marginTop + geom.firstPageExtraTop}px`
4848
5573
  } : void 0;
4849
- return /* @__PURE__ */ jsxs11(
5574
+ return /* @__PURE__ */ jsxs13(
4850
5575
  "div",
4851
5576
  {
4852
5577
  className: "ed-page",
@@ -4854,15 +5579,15 @@ function Editor({
4854
5579
  "data-page-total": ctx.pageCount,
4855
5580
  style: pageInlineStyle,
4856
5581
  children: [
4857
- renderPageHeader && /* @__PURE__ */ jsx12("div", { className: "ed-page-header", contentEditable: false, children: renderPageHeader(ctx) }),
4858
- /* @__PURE__ */ jsx12("div", { className: "ed-page-content", children: page.slots.map((slot) => renderSlot(slot, topLevels)) }),
4859
- renderPageFooter && /* @__PURE__ */ jsx12("div", { className: "ed-page-footer", contentEditable: false, children: renderPageFooter(ctx) })
5582
+ renderPageHeader && /* @__PURE__ */ jsx13("div", { className: "ed-page-header", contentEditable: false, children: renderPageHeader(ctx) }),
5583
+ /* @__PURE__ */ jsx13("div", { className: "ed-page-content", children: page.slots.map((slot) => renderSlot(slot, topLevels)) }),
5584
+ renderPageFooter && /* @__PURE__ */ jsx13("div", { className: "ed-page-footer", contentEditable: false, children: renderPageFooter(ctx) })
4860
5585
  ]
4861
5586
  },
4862
5587
  `page-${pi}`
4863
5588
  );
4864
5589
  }) : topLevels.map((t) => renderTopLevel(t)),
4865
- selectedEmbed && /* @__PURE__ */ jsx12(
5590
+ selectedEmbed && /* @__PURE__ */ jsx13(
4866
5591
  ImageResizeOverlay,
4867
5592
  {
4868
5593
  rootRef,
@@ -4894,7 +5619,7 @@ function Editor({
4894
5619
  )
4895
5620
  }
4896
5621
  ),
4897
- hoveredBehind && !(selectedEmbed && selectedEmbed.blockIndex === hoveredBehind.blockIndex && selectedEmbed.offset === hoveredBehind.offset && (selectedEmbed.cellIndex ?? -1) === (hoveredBehind.cellIndex ?? -1)) && /* @__PURE__ */ jsx12(
5622
+ hoveredBehind && !(selectedEmbed && selectedEmbed.blockIndex === hoveredBehind.blockIndex && selectedEmbed.offset === hoveredBehind.offset && (selectedEmbed.cellIndex ?? -1) === (hoveredBehind.cellIndex ?? -1)) && /* @__PURE__ */ jsx13(
4898
5623
  BehindImageSelectAffordance,
4899
5624
  {
4900
5625
  rootRef,
@@ -4915,8 +5640,8 @@ function Editor({
4915
5640
  })
4916
5641
  }
4917
5642
  ),
4918
- hoveredLink && hoveredLink.href && /* @__PURE__ */ jsx12(LinkHoverTooltip, { href: hoveredLink.href, rect: hoveredLink.rect }),
4919
- awareness && /* @__PURE__ */ jsx12(
5643
+ hoveredLink && hoveredLink.href && /* @__PURE__ */ jsx13(LinkHoverTooltip, { href: hoveredLink.href, rect: hoveredLink.rect }),
5644
+ awareness && /* @__PURE__ */ jsx13(
4920
5645
  RemoteCursorsOverlay,
4921
5646
  {
4922
5647
  rootRef,
@@ -4928,7 +5653,7 @@ function Editor({
4928
5653
  ]
4929
5654
  }
4930
5655
  );
4931
- return /* @__PURE__ */ jsx12(EditorProvider, { editor, children: body });
5656
+ return /* @__PURE__ */ jsx13(EditorProvider, { editor, children: body });
4932
5657
  }
4933
5658
  function groupTopLevels(snapshot) {
4934
5659
  const out = [];
@@ -4982,7 +5707,7 @@ function renderSlot(slot, topLevels) {
4982
5707
  start: slot.fragment.start,
4983
5708
  end: slot.fragment.end
4984
5709
  };
4985
- return /* @__PURE__ */ jsx12(
5710
+ return /* @__PURE__ */ jsx13(
4986
5711
  NodeView,
4987
5712
  {
4988
5713
  block: top.block,
@@ -4993,7 +5718,7 @@ function renderSlot(slot, topLevels) {
4993
5718
  );
4994
5719
  }
4995
5720
  if (slot.tableFragment && top.kind === "block" && top.block.type === "table") {
4996
- return /* @__PURE__ */ jsx12(
5721
+ return /* @__PURE__ */ jsx13(
4997
5722
  NodeView,
4998
5723
  {
4999
5724
  block: top.block,
@@ -5013,7 +5738,7 @@ function renderTopLevel(top) {
5013
5738
  const tree = buildListTree(top.items);
5014
5739
  return renderListTree(tree, top, top.ordinalStart, `list-${top.key}`);
5015
5740
  }
5016
- return /* @__PURE__ */ jsx12(NodeView, { block: top.block, index: top.blockIndex }, top.key);
5741
+ return /* @__PURE__ */ jsx13(NodeView, { block: top.block, index: top.blockIndex }, top.key);
5017
5742
  }
5018
5743
  function renderListFragment(top, frag) {
5019
5744
  const ranges = topLevelItemRanges(top.items);
@@ -5055,9 +5780,9 @@ function buildListTree(items) {
5055
5780
  function renderListTree(tree, top, start, key) {
5056
5781
  const className = `ed-list ed-list-${top.listKind}`;
5057
5782
  const style = top.listStyle ? { listStyleType: top.listStyle } : void 0;
5058
- const items = tree.map((node) => /* @__PURE__ */ jsx12(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children, `nested-${node.entry.index}`) : null }, node.entry.index));
5783
+ const items = tree.map((node) => /* @__PURE__ */ jsx13(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children, `nested-${node.entry.index}`) : null }, node.entry.index));
5059
5784
  if (top.listKind === "ordered") {
5060
- return /* @__PURE__ */ jsx12(
5785
+ return /* @__PURE__ */ jsx13(
5061
5786
  "ol",
5062
5787
  {
5063
5788
  className,
@@ -5069,12 +5794,12 @@ function renderListTree(tree, top, start, key) {
5069
5794
  key
5070
5795
  );
5071
5796
  }
5072
- return /* @__PURE__ */ jsx12("ul", { className, "data-list-kind": "bullet", style, children: items }, key);
5797
+ return /* @__PURE__ */ jsx13("ul", { className, "data-list-kind": "bullet", style, children: items }, key);
5073
5798
  }
5074
5799
  function renderNestedListTree(tree, key) {
5075
5800
  const kind = tree[0]?.entry.block.attrs.listKind === "ordered" ? "ordered" : "bullet";
5076
5801
  const Tag = kind === "ordered" ? "ol" : "ul";
5077
- return /* @__PURE__ */ jsx12(Tag, { className: `ed-list ed-list-${kind}`, "data-list-kind": kind, children: tree.map((node) => /* @__PURE__ */ jsx12(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children, `nested-${node.entry.index}`) : null }, node.entry.index)) }, key);
5802
+ return /* @__PURE__ */ jsx13(Tag, { className: `ed-list ed-list-${kind}`, "data-list-kind": kind, children: tree.map((node) => /* @__PURE__ */ jsx13(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children, `nested-${node.entry.index}`) : null }, node.entry.index)) }, key);
5078
5803
  }
5079
5804
  function clampListLevel2(l) {
5080
5805
  if (typeof l !== "number" || !Number.isFinite(l)) return 0;
@@ -5103,14 +5828,80 @@ function caretRangeFromPoint(x, y) {
5103
5828
 
5104
5829
  // src/Toolbar.tsx
5105
5830
  import {
5106
- useCallback as useCallback8,
5107
- useEffect as useEffect10,
5108
- useRef as useRef12,
5109
- useState as useState11
5831
+ useCallback as useCallback9,
5832
+ useEffect as useEffect11,
5833
+ useRef as useRef13,
5834
+ useState as useState12
5110
5835
  } from "react";
5111
- import { ANSWER_LINE_MAX, TABLE_BORDER_COLOR } from "@sofereditor/core";
5112
- import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
5113
- var FONT_FAMILIES = ["Arial"];
5836
+ import { ANSWER_LINE_MAX, isFormulaEmbed as isFormulaEmbed3, TABLE_BORDER_COLOR } from "@sofereditor/core";
5837
+
5838
+ // src/TableBorderPanel.tsx
5839
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
5840
+ var BORDER_PRESETS = [
5841
+ { key: "all", label: "Todas", glyph: "\u229E" },
5842
+ { key: "outer", label: "S\xF3 externas", glyph: "\u25A1" },
5843
+ { key: "horizontal", label: "S\xF3 horizontais", glyph: "\u25A4" },
5844
+ { key: "vertical", label: "S\xF3 verticais", glyph: "\u25A5" },
5845
+ { key: "none", label: "Nenhuma", glyph: "\u2B1A" }
5846
+ ];
5847
+ var BORDER_MENU_GLYPH = "\u229E";
5848
+ function TableBorderPanel({
5849
+ preset,
5850
+ color,
5851
+ onPreset,
5852
+ onColor,
5853
+ onResetColor
5854
+ }) {
5855
+ return /* @__PURE__ */ jsxs14("div", { className: "ed-border-panel", children: [
5856
+ /* @__PURE__ */ jsx14("div", { className: "ed-border-presets", children: BORDER_PRESETS.map((p) => /* @__PURE__ */ jsxs14(
5857
+ "button",
5858
+ {
5859
+ type: "button",
5860
+ className: "ed-border-preset",
5861
+ "aria-pressed": preset === p.key,
5862
+ title: p.label,
5863
+ onClick: (e) => {
5864
+ e.preventDefault();
5865
+ onPreset(p.key);
5866
+ },
5867
+ children: [
5868
+ /* @__PURE__ */ jsx14("span", { className: "ed-border-glyph", "aria-hidden": true, children: p.glyph }),
5869
+ p.label
5870
+ ]
5871
+ },
5872
+ p.key
5873
+ )) }),
5874
+ /* @__PURE__ */ jsx14("hr", {}),
5875
+ /* @__PURE__ */ jsxs14("label", { className: "ed-toolbar-label ed-border-color", children: [
5876
+ /* @__PURE__ */ jsx14("span", { className: "ed-toolbar-swatch", "aria-hidden": true, style: { background: color } }),
5877
+ "Cor da linha",
5878
+ /* @__PURE__ */ jsx14(
5879
+ "input",
5880
+ {
5881
+ type: "color",
5882
+ value: color,
5883
+ onChange: (e) => onColor(e.target.value),
5884
+ "aria-label": "Cor da linha da borda"
5885
+ }
5886
+ )
5887
+ ] }),
5888
+ /* @__PURE__ */ jsx14(
5889
+ "button",
5890
+ {
5891
+ type: "button",
5892
+ className: "ed-border-reset",
5893
+ onClick: (e) => {
5894
+ e.preventDefault();
5895
+ onResetColor();
5896
+ },
5897
+ children: "Padr\xE3o"
5898
+ }
5899
+ )
5900
+ ] });
5901
+ }
5902
+
5903
+ // src/Toolbar.tsx
5904
+ import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
5114
5905
  var FONT_SIZES = ["8pt", "10pt", "11pt", "12pt", "14pt", "16pt", "18pt", "24pt", "32pt", "48pt"];
5115
5906
  var BLOCK_OPTIONS = [
5116
5907
  { value: "paragraph", label: "Par\xE1grafo", type: "paragraph" },
@@ -5184,11 +5975,6 @@ function Toolbar({ className }) {
5184
5975
  const onHighlightChange = (e) => {
5185
5976
  setMark("highlight", e.target.value);
5186
5977
  };
5187
- const onFontFamilyChange = (e) => {
5188
- const v = e.target.value;
5189
- if (v === "") removeMark("fontFamily");
5190
- else setMark("fontFamily", v);
5191
- };
5192
5978
  const onFontSizeChange = (e) => {
5193
5979
  const v = e.target.value;
5194
5980
  if (v === "") removeMark("fontSize");
@@ -5213,14 +5999,14 @@ function Toolbar({ className }) {
5213
5999
  }
5214
6000
  setAlign(value);
5215
6001
  };
5216
- const onInsertImageClick = useCallback8(
6002
+ const onInsertImageClick = useCallback9(
5217
6003
  (e) => {
5218
6004
  e.preventDefault();
5219
6005
  imageInputRef.current?.click();
5220
6006
  },
5221
6007
  []
5222
6008
  );
5223
- const onImageInputChange = useCallback8(
6009
+ const onImageInputChange = useCallback9(
5224
6010
  (e) => {
5225
6011
  const file = e.target.files?.[0];
5226
6012
  if (file) void editor.insertImageFromFile(file);
@@ -5228,14 +6014,14 @@ function Toolbar({ className }) {
5228
6014
  },
5229
6015
  [editor]
5230
6016
  );
5231
- const imageInputRef = useRef12(null);
6017
+ const imageInputRef = useRef13(null);
5232
6018
  const onToggleDir = (e) => {
5233
6019
  e.preventDefault();
5234
6020
  const next = blockDir === "rtl" ? "ltr" : "rtl";
5235
6021
  setBlockAttr("dir", next);
5236
6022
  };
5237
6023
  const linkActive = isMarkActive("link");
5238
- const onLinkClick = useCallback8(
6024
+ const onLinkClick = useCallback9(
5239
6025
  (e) => {
5240
6026
  e.preventDefault();
5241
6027
  const currentHref = active.link && typeof active.link === "object" && "href" in active.link ? active.link.href : "";
@@ -5249,7 +6035,6 @@ function Toolbar({ className }) {
5249
6035
  );
5250
6036
  const colorValue = typeof active.color === "string" ? active.color : "#000000";
5251
6037
  const highlightValue = typeof active.highlight === "string" ? active.highlight : "#fff176";
5252
- const fontFamilyValue = typeof active.fontFamily === "string" ? active.fontFamily : "";
5253
6038
  const fontSizeValue = typeof active.fontSize === "string" ? active.fontSize : "";
5254
6039
  const blockValue = blockSelectValue(blockType, blockLevel);
5255
6040
  const selectedEmbed = editor.getSelectedEmbed();
@@ -5266,7 +6051,7 @@ function Toolbar({ className }) {
5266
6051
  sel.cellIndex
5267
6052
  );
5268
6053
  };
5269
- return /* @__PURE__ */ jsxs12(
6054
+ return /* @__PURE__ */ jsxs15(
5270
6055
  "div",
5271
6056
  {
5272
6057
  className: className ?? "ed-toolbar",
@@ -5274,7 +6059,7 @@ function Toolbar({ className }) {
5274
6059
  "aria-label": "Editor toolbar",
5275
6060
  onMouseDown: stop,
5276
6061
  children: [
5277
- /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsxs12(
6062
+ /* @__PURE__ */ jsx15(Group, { children: /* @__PURE__ */ jsxs15(
5278
6063
  "select",
5279
6064
  {
5280
6065
  className: "ed-toolbar-select",
@@ -5283,23 +6068,23 @@ function Toolbar({ className }) {
5283
6068
  onMouseDown: stop,
5284
6069
  "aria-label": "Tipo de bloco",
5285
6070
  children: [
5286
- blockValue === "" && /* @__PURE__ */ jsx13("option", { value: "", children: "\u2014 (misto)" }),
5287
- BLOCK_OPTIONS.map((o) => /* @__PURE__ */ jsx13("option", { value: o.value, children: o.label }, o.value))
6071
+ blockValue === "" && /* @__PURE__ */ jsx15("option", { value: "", children: "\u2014 (misto)" }),
6072
+ BLOCK_OPTIONS.map((o) => /* @__PURE__ */ jsx15("option", { value: o.value, children: o.label }, o.value))
5288
6073
  ]
5289
6074
  }
5290
6075
  ) }),
5291
- /* @__PURE__ */ jsxs12(Group, { children: [
5292
- /* @__PURE__ */ jsx13(MarkButton, { title: "Negrito (\u2318B)", pressed: isMarkActive("bold"), onClick: onToggle("bold"), children: /* @__PURE__ */ jsx13("strong", { children: "B" }) }),
5293
- /* @__PURE__ */ jsx13(MarkButton, { title: "It\xE1lico (\u2318I)", pressed: isMarkActive("italic"), onClick: onToggle("italic"), children: /* @__PURE__ */ jsx13("em", { children: "I" }) }),
5294
- /* @__PURE__ */ jsx13(MarkButton, { title: "Sublinhado (\u2318U)", pressed: isMarkActive("underline"), onClick: onToggle("underline"), children: /* @__PURE__ */ jsx13("u", { children: "U" }) }),
5295
- /* @__PURE__ */ jsx13(MarkButton, { title: "Tachado (\u2318\u21E7X)", pressed: isMarkActive("strike"), onClick: onToggle("strike"), children: /* @__PURE__ */ jsx13("s", { children: "S" }) })
6076
+ /* @__PURE__ */ jsxs15(Group, { children: [
6077
+ /* @__PURE__ */ jsx15(MarkButton, { title: "Negrito (\u2318B)", pressed: isMarkActive("bold"), onClick: onToggle("bold"), children: /* @__PURE__ */ jsx15("strong", { children: "B" }) }),
6078
+ /* @__PURE__ */ jsx15(MarkButton, { title: "It\xE1lico (\u2318I)", pressed: isMarkActive("italic"), onClick: onToggle("italic"), children: /* @__PURE__ */ jsx15("em", { children: "I" }) }),
6079
+ /* @__PURE__ */ jsx15(MarkButton, { title: "Sublinhado (\u2318U)", pressed: isMarkActive("underline"), onClick: onToggle("underline"), children: /* @__PURE__ */ jsx15("u", { children: "U" }) }),
6080
+ /* @__PURE__ */ jsx15(MarkButton, { title: "Tachado (\u2318\u21E7X)", pressed: isMarkActive("strike"), onClick: onToggle("strike"), children: /* @__PURE__ */ jsx15("s", { children: "S" }) })
5296
6081
  ] }),
5297
- /* @__PURE__ */ jsxs12(Group, { children: [
5298
- /* @__PURE__ */ jsxs12("label", { className: "ed-toolbar-label", children: [
5299
- /* @__PURE__ */ jsx13("span", { className: "ed-toolbar-swatch", "aria-hidden": true, style: { background: colorValue } }),
5300
- /* @__PURE__ */ jsx13("input", { type: "color", value: colorValue, onChange: onColorChange, onMouseDown: stop, "aria-label": "Cor do texto" })
6082
+ /* @__PURE__ */ jsxs15(Group, { children: [
6083
+ /* @__PURE__ */ jsxs15("label", { className: "ed-toolbar-label", children: [
6084
+ /* @__PURE__ */ jsx15("span", { className: "ed-toolbar-swatch", "aria-hidden": true, style: { background: colorValue } }),
6085
+ /* @__PURE__ */ jsx15("input", { type: "color", value: colorValue, onChange: onColorChange, onMouseDown: stop, "aria-label": "Cor do texto" })
5301
6086
  ] }),
5302
- /* @__PURE__ */ jsx13(
6087
+ /* @__PURE__ */ jsx15(
5303
6088
  "button",
5304
6089
  {
5305
6090
  type: "button",
@@ -5313,8 +6098,8 @@ function Toolbar({ className }) {
5313
6098
  children: "\u232B"
5314
6099
  }
5315
6100
  ),
5316
- /* @__PURE__ */ jsxs12("label", { className: "ed-toolbar-label", title: "Marca-texto", children: [
5317
- /* @__PURE__ */ jsx13(
6101
+ /* @__PURE__ */ jsxs15("label", { className: "ed-toolbar-label", title: "Marca-texto", children: [
6102
+ /* @__PURE__ */ jsx15(
5318
6103
  "span",
5319
6104
  {
5320
6105
  className: "ed-toolbar-swatch ed-toolbar-swatch--highlight",
@@ -5322,7 +6107,7 @@ function Toolbar({ className }) {
5322
6107
  style: { background: highlightValue }
5323
6108
  }
5324
6109
  ),
5325
- /* @__PURE__ */ jsx13(
6110
+ /* @__PURE__ */ jsx15(
5326
6111
  "input",
5327
6112
  {
5328
6113
  type: "color",
@@ -5333,7 +6118,7 @@ function Toolbar({ className }) {
5333
6118
  }
5334
6119
  )
5335
6120
  ] }),
5336
- /* @__PURE__ */ jsx13(
6121
+ /* @__PURE__ */ jsx15(
5337
6122
  "button",
5338
6123
  {
5339
6124
  type: "button",
@@ -5348,37 +6133,21 @@ function Toolbar({ className }) {
5348
6133
  }
5349
6134
  )
5350
6135
  ] }),
5351
- /* @__PURE__ */ jsxs12(Group, { children: [
5352
- /* @__PURE__ */ jsxs12(
5353
- "select",
5354
- {
5355
- className: "ed-toolbar-select",
5356
- value: fontFamilyValue,
5357
- onChange: onFontFamilyChange,
5358
- onMouseDown: stop,
5359
- "aria-label": "Fam\xEDlia da fonte",
5360
- children: [
5361
- /* @__PURE__ */ jsx13("option", { value: "", children: "Fonte\u2026" }),
5362
- FONT_FAMILIES.map((f) => /* @__PURE__ */ jsx13("option", { value: f, children: f }, f))
5363
- ]
5364
- }
5365
- ),
5366
- /* @__PURE__ */ jsxs12(
5367
- "select",
5368
- {
5369
- className: "ed-toolbar-select",
5370
- value: fontSizeValue,
5371
- onChange: onFontSizeChange,
5372
- onMouseDown: stop,
5373
- "aria-label": "Tamanho da fonte",
5374
- children: [
5375
- /* @__PURE__ */ jsx13("option", { value: "", children: "Tamanho\u2026" }),
5376
- FONT_SIZES.map((s) => /* @__PURE__ */ jsx13("option", { value: s, children: s }, s))
5377
- ]
5378
- }
5379
- )
5380
- ] }),
5381
- /* @__PURE__ */ jsx13(Group, { children: ALIGN_OPTIONS.map((a) => /* @__PURE__ */ jsx13(
6136
+ /* @__PURE__ */ jsx15(Group, { children: /* @__PURE__ */ jsxs15(
6137
+ "select",
6138
+ {
6139
+ className: "ed-toolbar-select",
6140
+ value: fontSizeValue,
6141
+ onChange: onFontSizeChange,
6142
+ onMouseDown: stop,
6143
+ "aria-label": "Tamanho da fonte",
6144
+ children: [
6145
+ /* @__PURE__ */ jsx15("option", { value: "", children: "Tamanho\u2026" }),
6146
+ FONT_SIZES.map((s) => /* @__PURE__ */ jsx15("option", { value: s, children: s }, s))
6147
+ ]
6148
+ }
6149
+ ) }),
6150
+ /* @__PURE__ */ jsx15(Group, { children: ALIGN_OPTIONS.map((a) => /* @__PURE__ */ jsx15(
5382
6151
  "button",
5383
6152
  {
5384
6153
  type: "button",
@@ -5391,7 +6160,7 @@ function Toolbar({ className }) {
5391
6160
  },
5392
6161
  a.value
5393
6162
  )) }),
5394
- /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsx13(
6163
+ /* @__PURE__ */ jsx15(Group, { children: /* @__PURE__ */ jsx15(
5395
6164
  "button",
5396
6165
  {
5397
6166
  type: "button",
@@ -5403,8 +6172,8 @@ function Toolbar({ className }) {
5403
6172
  children: blockDir === "rtl" ? "RTL" : "LTR"
5404
6173
  }
5405
6174
  ) }),
5406
- /* @__PURE__ */ jsxs12(Group, { children: [
5407
- /* @__PURE__ */ jsx13(
6175
+ /* @__PURE__ */ jsxs15(Group, { children: [
6176
+ /* @__PURE__ */ jsx15(
5408
6177
  "button",
5409
6178
  {
5410
6179
  type: "button",
@@ -5419,7 +6188,7 @@ function Toolbar({ className }) {
5419
6188
  children: "\u2022"
5420
6189
  }
5421
6190
  ),
5422
- /* @__PURE__ */ jsx13(
6191
+ /* @__PURE__ */ jsx15(
5423
6192
  "button",
5424
6193
  {
5425
6194
  type: "button",
@@ -5434,7 +6203,7 @@ function Toolbar({ className }) {
5434
6203
  children: "1."
5435
6204
  }
5436
6205
  ),
5437
- /* @__PURE__ */ jsx13(
6206
+ /* @__PURE__ */ jsx15(
5438
6207
  "button",
5439
6208
  {
5440
6209
  type: "button",
@@ -5448,7 +6217,7 @@ function Toolbar({ className }) {
5448
6217
  children: "\u21E4"
5449
6218
  }
5450
6219
  ),
5451
- /* @__PURE__ */ jsx13(
6220
+ /* @__PURE__ */ jsx15(
5452
6221
  "button",
5453
6222
  {
5454
6223
  type: "button",
@@ -5463,7 +6232,7 @@ function Toolbar({ className }) {
5463
6232
  }
5464
6233
  )
5465
6234
  ] }),
5466
- /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsx13(
6235
+ /* @__PURE__ */ jsx15(Group, { children: /* @__PURE__ */ jsx15(
5467
6236
  "button",
5468
6237
  {
5469
6238
  type: "button",
@@ -5475,12 +6244,12 @@ function Toolbar({ className }) {
5475
6244
  children: "\u{1F517}"
5476
6245
  }
5477
6246
  ) }),
5478
- /* @__PURE__ */ jsxs12(Group, { children: [
5479
- /* @__PURE__ */ jsx13(TableMenu, {}),
5480
- /* @__PURE__ */ jsx13(AnswerLinesMenu, {})
6247
+ /* @__PURE__ */ jsxs15(Group, { children: [
6248
+ /* @__PURE__ */ jsx15(TableMenu, {}),
6249
+ /* @__PURE__ */ jsx15(AnswerLinesMenu, {})
5481
6250
  ] }),
5482
- /* @__PURE__ */ jsxs12(Group, { children: [
5483
- /* @__PURE__ */ jsx13(
6251
+ /* @__PURE__ */ jsxs15(Group, { children: [
6252
+ /* @__PURE__ */ jsx15(
5484
6253
  "button",
5485
6254
  {
5486
6255
  type: "button",
@@ -5491,7 +6260,7 @@ function Toolbar({ className }) {
5491
6260
  children: "\u{1F5BC}"
5492
6261
  }
5493
6262
  ),
5494
- /* @__PURE__ */ jsx13(
6263
+ /* @__PURE__ */ jsx15(
5495
6264
  "input",
5496
6265
  {
5497
6266
  ref: imageInputRef,
@@ -5500,10 +6269,26 @@ function Toolbar({ className }) {
5500
6269
  hidden: true,
5501
6270
  onChange: onImageInputChange
5502
6271
  }
6272
+ ),
6273
+ /* @__PURE__ */ jsx15(
6274
+ "button",
6275
+ {
6276
+ type: "button",
6277
+ className: "ed-toolbar-btn",
6278
+ title: "Inserir f\xF3rmula",
6279
+ onMouseDown: stop,
6280
+ onClick: (e) => {
6281
+ e.preventDefault();
6282
+ void editor.requestFormula().then((r) => r ? editor.insertFormula(r.latex, r.display) : void 0).catch((err) => {
6283
+ console.error("Falha ao inserir f\xF3rmula:", err);
6284
+ });
6285
+ },
6286
+ children: "\u221Ax"
6287
+ }
5503
6288
  )
5504
6289
  ] }),
5505
- selectedEmbed && /* @__PURE__ */ jsxs12(Group, { children: [
5506
- IMAGE_LAYOUT_OPTIONS.map((opt) => /* @__PURE__ */ jsx13(
6290
+ selectedEmbed && /* @__PURE__ */ jsxs15(Group, { children: [
6291
+ IMAGE_LAYOUT_OPTIONS.map((opt) => /* @__PURE__ */ jsx15(
5507
6292
  "button",
5508
6293
  {
5509
6294
  type: "button",
@@ -5516,7 +6301,25 @@ function Toolbar({ className }) {
5516
6301
  },
5517
6302
  opt.value
5518
6303
  )),
5519
- /* @__PURE__ */ jsx13(
6304
+ isFormulaEmbed3(selectedEmbed.embed) ? /* @__PURE__ */ jsx15(
6305
+ "button",
6306
+ {
6307
+ type: "button",
6308
+ className: "ed-toolbar-btn",
6309
+ title: "Editar f\xF3rmula",
6310
+ onMouseDown: stop,
6311
+ onClick: (e) => {
6312
+ e.preventDefault();
6313
+ if (!isFormulaEmbed3(selectedEmbed.embed)) return;
6314
+ const f = selectedEmbed.embed.formula;
6315
+ void editor.requestFormula(f.latex, f.display).then((r) => {
6316
+ if (!r) return;
6317
+ void editor.insertFormula(r.latex, r.display);
6318
+ });
6319
+ },
6320
+ children: "Editar f\xF3rmula"
6321
+ }
6322
+ ) : /* @__PURE__ */ jsx15(
5520
6323
  "button",
5521
6324
  {
5522
6325
  type: "button",
@@ -5546,7 +6349,7 @@ function Toolbar({ className }) {
5546
6349
  }
5547
6350
  )
5548
6351
  ] }),
5549
- /* @__PURE__ */ jsx13(Group, { children: /* @__PURE__ */ jsx13(
6352
+ /* @__PURE__ */ jsx15(Group, { children: /* @__PURE__ */ jsx15(
5550
6353
  "button",
5551
6354
  {
5552
6355
  type: "button",
@@ -5566,11 +6369,11 @@ function Toolbar({ className }) {
5566
6369
  }
5567
6370
  function AnswerLinesMenu() {
5568
6371
  const editor = useEditorContext();
5569
- const [open, setOpen] = useState11(false);
5570
- const [count, setCount] = useState11(5);
5571
- const [spacing, setSpacing] = useState11(1.5);
5572
- const rootRef = useRef12(null);
5573
- useEffect10(() => {
6372
+ const [open, setOpen] = useState12(false);
6373
+ const [count, setCount] = useState12(5);
6374
+ const [spacing, setSpacing] = useState12(1.5);
6375
+ const rootRef = useRef13(null);
6376
+ useEffect11(() => {
5574
6377
  if (!open) return;
5575
6378
  const onDown = (e) => {
5576
6379
  if (!rootRef.current) return;
@@ -5581,8 +6384,8 @@ function AnswerLinesMenu() {
5581
6384
  return () => document.removeEventListener("mousedown", onDown);
5582
6385
  }, [open]);
5583
6386
  const clamped = Math.max(1, Math.min(ANSWER_LINE_MAX, Math.trunc(count) || 1));
5584
- return /* @__PURE__ */ jsxs12("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
5585
- /* @__PURE__ */ jsx13(
6387
+ return /* @__PURE__ */ jsxs15("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
6388
+ /* @__PURE__ */ jsx15(
5586
6389
  "button",
5587
6390
  {
5588
6391
  type: "button",
@@ -5597,7 +6400,7 @@ function AnswerLinesMenu() {
5597
6400
  children: "\u2630"
5598
6401
  }
5599
6402
  ),
5600
- open && /* @__PURE__ */ jsxs12(
6403
+ open && /* @__PURE__ */ jsxs15(
5601
6404
  "div",
5602
6405
  {
5603
6406
  className: "ed-table-popover ed-answerlines-popover",
@@ -5606,9 +6409,9 @@ function AnswerLinesMenu() {
5606
6409
  if (!keepsOwnMouseDown(e.target)) e.preventDefault();
5607
6410
  },
5608
6411
  children: [
5609
- /* @__PURE__ */ jsxs12("label", { className: "ed-toolbar-label", children: [
6412
+ /* @__PURE__ */ jsxs15("label", { className: "ed-toolbar-label", children: [
5610
6413
  "Quantidade",
5611
- /* @__PURE__ */ jsx13(
6414
+ /* @__PURE__ */ jsx15(
5612
6415
  "input",
5613
6416
  {
5614
6417
  type: "number",
@@ -5620,23 +6423,23 @@ function AnswerLinesMenu() {
5620
6423
  }
5621
6424
  )
5622
6425
  ] }),
5623
- /* @__PURE__ */ jsxs12("label", { className: "ed-toolbar-label", children: [
6426
+ /* @__PURE__ */ jsxs15("label", { className: "ed-toolbar-label", children: [
5624
6427
  "Entrelinha",
5625
- /* @__PURE__ */ jsxs12(
6428
+ /* @__PURE__ */ jsxs15(
5626
6429
  "select",
5627
6430
  {
5628
6431
  value: String(spacing),
5629
6432
  onChange: (e) => setSpacing(Number(e.target.value)),
5630
6433
  "aria-label": "Entrelinha",
5631
6434
  children: [
5632
- /* @__PURE__ */ jsx13("option", { value: "1", children: "Simples" }),
5633
- /* @__PURE__ */ jsx13("option", { value: "1.5", children: "1,5" }),
5634
- /* @__PURE__ */ jsx13("option", { value: "2", children: "Duplo" })
6435
+ /* @__PURE__ */ jsx15("option", { value: "1", children: "Simples" }),
6436
+ /* @__PURE__ */ jsx15("option", { value: "1.5", children: "1,5" }),
6437
+ /* @__PURE__ */ jsx15("option", { value: "2", children: "Duplo" })
5635
6438
  ]
5636
6439
  }
5637
6440
  )
5638
6441
  ] }),
5639
- /* @__PURE__ */ jsxs12(
6442
+ /* @__PURE__ */ jsxs15(
5640
6443
  "button",
5641
6444
  {
5642
6445
  type: "button",
@@ -5660,9 +6463,10 @@ function AnswerLinesMenu() {
5660
6463
  function TableMenu() {
5661
6464
  const editor = useEditorContext();
5662
6465
  const inTable = editor.isInTable();
5663
- const [open, setOpen] = useState11(false);
5664
- const rootRef = useRef12(null);
5665
- useEffect10(() => {
6466
+ const [open, setOpen] = useState12(false);
6467
+ const [bordersOpen, setBordersOpen] = useState12(false);
6468
+ const rootRef = useRef13(null);
6469
+ useEffect11(() => {
5666
6470
  if (!open) return;
5667
6471
  const onDown = (e) => {
5668
6472
  if (!rootRef.current) return;
@@ -5672,8 +6476,11 @@ function TableMenu() {
5672
6476
  document.addEventListener("mousedown", onDown);
5673
6477
  return () => document.removeEventListener("mousedown", onDown);
5674
6478
  }, [open]);
5675
- return /* @__PURE__ */ jsxs12("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
5676
- /* @__PURE__ */ jsx13(
6479
+ useEffect11(() => {
6480
+ if (!open) setBordersOpen(false);
6481
+ }, [open]);
6482
+ return /* @__PURE__ */ jsxs15("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
6483
+ /* @__PURE__ */ jsx15(
5677
6484
  "button",
5678
6485
  {
5679
6486
  type: "button",
@@ -5688,7 +6495,7 @@ function TableMenu() {
5688
6495
  children: "\u25A6"
5689
6496
  }
5690
6497
  ),
5691
- open && /* @__PURE__ */ jsxs12(
6498
+ open && /* @__PURE__ */ jsxs15(
5692
6499
  "div",
5693
6500
  {
5694
6501
  className: "ed-table-popover",
@@ -5697,7 +6504,7 @@ function TableMenu() {
5697
6504
  if (!keepsOwnMouseDown(e.target)) e.preventDefault();
5698
6505
  },
5699
6506
  children: [
5700
- /* @__PURE__ */ jsx13(
6507
+ /* @__PURE__ */ jsx15(
5701
6508
  TableSizePicker,
5702
6509
  {
5703
6510
  onPick: (rows, cols) => {
@@ -5706,34 +6513,34 @@ function TableMenu() {
5706
6513
  }
5707
6514
  }
5708
6515
  ),
5709
- inTable && /* @__PURE__ */ jsxs12("div", { className: "ed-table-actions", children: [
5710
- /* @__PURE__ */ jsx13("hr", {}),
5711
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
6516
+ inTable && /* @__PURE__ */ jsxs15("div", { className: "ed-table-actions", children: [
6517
+ /* @__PURE__ */ jsx15("hr", {}),
6518
+ /* @__PURE__ */ jsx15("button", { type: "button", onClick: () => {
5712
6519
  setOpen(false);
5713
6520
  editor.insertRowAbove();
5714
6521
  }, children: "Inserir linha acima" }),
5715
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
6522
+ /* @__PURE__ */ jsx15("button", { type: "button", onClick: () => {
5716
6523
  setOpen(false);
5717
6524
  editor.insertRowBelow();
5718
6525
  }, children: "Inserir linha abaixo" }),
5719
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
6526
+ /* @__PURE__ */ jsx15("button", { type: "button", onClick: () => {
5720
6527
  setOpen(false);
5721
6528
  editor.insertColumnLeft();
5722
6529
  }, children: "Inserir coluna \xE0 esquerda" }),
5723
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
6530
+ /* @__PURE__ */ jsx15("button", { type: "button", onClick: () => {
5724
6531
  setOpen(false);
5725
6532
  editor.insertColumnRight();
5726
6533
  }, children: "Inserir coluna \xE0 direita" }),
5727
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
6534
+ /* @__PURE__ */ jsx15("button", { type: "button", onClick: () => {
5728
6535
  setOpen(false);
5729
6536
  editor.deleteCurrentRow();
5730
6537
  }, children: "Excluir linha" }),
5731
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
6538
+ /* @__PURE__ */ jsx15("button", { type: "button", onClick: () => {
5732
6539
  setOpen(false);
5733
6540
  editor.deleteCurrentColumn();
5734
6541
  }, children: "Excluir coluna" }),
5735
- /* @__PURE__ */ jsx13("hr", {}),
5736
- editor.hasTableRectSelection() && /* @__PURE__ */ jsx13(
6542
+ /* @__PURE__ */ jsx15("hr", {}),
6543
+ editor.hasTableRectSelection() && /* @__PURE__ */ jsx15(
5737
6544
  "button",
5738
6545
  {
5739
6546
  type: "button",
@@ -5744,21 +6551,21 @@ function TableMenu() {
5744
6551
  children: "Mesclar c\xE9lulas selecionadas"
5745
6552
  }
5746
6553
  ),
5747
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
6554
+ /* @__PURE__ */ jsx15("button", { type: "button", onClick: () => {
5748
6555
  setOpen(false);
5749
6556
  editor.mergeRight();
5750
6557
  }, children: "Mesclar com c\xE9lula \xE0 direita" }),
5751
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
6558
+ /* @__PURE__ */ jsx15("button", { type: "button", onClick: () => {
5752
6559
  setOpen(false);
5753
6560
  editor.mergeDown();
5754
6561
  }, children: "Mesclar com c\xE9lula abaixo" }),
5755
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
6562
+ /* @__PURE__ */ jsx15("button", { type: "button", onClick: () => {
5756
6563
  setOpen(false);
5757
6564
  editor.splitCell();
5758
6565
  }, children: "Dividir c\xE9lulas mescladas" }),
5759
- /* @__PURE__ */ jsx13("hr", {}),
5760
- /* @__PURE__ */ jsxs12("label", { className: "ed-toolbar-label ed-table-bgcolor", children: [
5761
- /* @__PURE__ */ jsx13(
6566
+ /* @__PURE__ */ jsx15("hr", {}),
6567
+ /* @__PURE__ */ jsxs15("label", { className: "ed-toolbar-label ed-table-bgcolor", children: [
6568
+ /* @__PURE__ */ jsx15(
5762
6569
  "span",
5763
6570
  {
5764
6571
  className: "ed-toolbar-swatch",
@@ -5767,7 +6574,7 @@ function TableMenu() {
5767
6574
  }
5768
6575
  ),
5769
6576
  "Cor de fundo da c\xE9lula",
5770
- /* @__PURE__ */ jsx13(
6577
+ /* @__PURE__ */ jsx15(
5771
6578
  "input",
5772
6579
  {
5773
6580
  type: "color",
@@ -5777,62 +6584,39 @@ function TableMenu() {
5777
6584
  }
5778
6585
  )
5779
6586
  ] }),
5780
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => {
6587
+ /* @__PURE__ */ jsx15("button", { type: "button", onClick: () => {
5781
6588
  setOpen(false);
5782
6589
  editor.setCellBackground(null);
5783
6590
  }, children: "Remover cor de fundo" }),
5784
- /* @__PURE__ */ jsx13("hr", {}),
5785
- /* @__PURE__ */ jsxs12("label", { className: "ed-toolbar-label", children: [
5786
- "Bordas",
5787
- /* @__PURE__ */ jsxs12(
5788
- "select",
5789
- {
5790
- value: editor.getTableBorderPreset(),
5791
- onChange: (e) => editor.setTableBorderPreset(e.target.value),
5792
- "aria-label": "Bordas da tabela",
5793
- children: [
5794
- /* @__PURE__ */ jsx13("option", { value: "all", children: "Todas" }),
5795
- /* @__PURE__ */ jsx13("option", { value: "outer", children: "S\xF3 externas" }),
5796
- /* @__PURE__ */ jsx13("option", { value: "horizontal", children: "S\xF3 horizontais" }),
5797
- /* @__PURE__ */ jsx13("option", { value: "vertical", children: "S\xF3 verticais" }),
5798
- /* @__PURE__ */ jsx13("option", { value: "none", children: "Nenhuma" })
5799
- ]
5800
- }
5801
- )
5802
- ] }),
5803
- /* @__PURE__ */ jsxs12("label", { className: "ed-toolbar-label ed-table-bgcolor", children: [
5804
- /* @__PURE__ */ jsx13(
5805
- "span",
5806
- {
5807
- className: "ed-toolbar-swatch",
5808
- "aria-hidden": true,
5809
- style: { background: editor.getTableBorderColor() ?? TABLE_BORDER_COLOR }
5810
- }
5811
- ),
5812
- "Cor da borda",
5813
- /* @__PURE__ */ jsx13(
5814
- "input",
5815
- {
5816
- type: "color",
5817
- value: editor.getTableBorderColor() ?? TABLE_BORDER_COLOR,
5818
- onChange: (e) => editor.setTableBorderColor(e.target.value),
5819
- "aria-label": "Cor da borda"
5820
- }
5821
- )
5822
- ] }),
5823
- /* @__PURE__ */ jsx13(
6591
+ /* @__PURE__ */ jsx15("hr", {}),
6592
+ /* @__PURE__ */ jsx15(
5824
6593
  "button",
5825
6594
  {
5826
6595
  type: "button",
5827
- onClick: () => {
5828
- setOpen(false);
5829
- editor.setTableBorderColor(null);
6596
+ className: "ed-border-toggle",
6597
+ "aria-pressed": bordersOpen,
6598
+ "aria-expanded": bordersOpen,
6599
+ title: "Bordas da tabela",
6600
+ "aria-label": "Bordas da tabela",
6601
+ onClick: (e) => {
6602
+ e.preventDefault();
6603
+ setBordersOpen((v) => !v);
5830
6604
  },
5831
- children: "Restaurar cor padr\xE3o"
6605
+ children: BORDER_MENU_GLYPH
6606
+ }
6607
+ ),
6608
+ bordersOpen && /* @__PURE__ */ jsx15(
6609
+ TableBorderPanel,
6610
+ {
6611
+ preset: editor.getTableBorderPreset(),
6612
+ color: editor.getTableBorderColor() ?? TABLE_BORDER_COLOR,
6613
+ onPreset: (p) => editor.setTableBorderPreset(p),
6614
+ onColor: (c) => editor.setTableBorderColor(c),
6615
+ onResetColor: () => editor.setTableBorderColor(null)
5832
6616
  }
5833
6617
  ),
5834
- /* @__PURE__ */ jsx13("hr", {}),
5835
- /* @__PURE__ */ jsx13(
6618
+ /* @__PURE__ */ jsx15("hr", {}),
6619
+ /* @__PURE__ */ jsx15(
5836
6620
  "button",
5837
6621
  {
5838
6622
  type: "button",
@@ -5853,11 +6637,11 @@ function TableMenu() {
5853
6637
  var PICKER_MAX_ROWS = 8;
5854
6638
  var PICKER_MAX_COLS = 10;
5855
6639
  function TableSizePicker({ onPick }) {
5856
- const [hover, setHover] = useState11(null);
6640
+ const [hover, setHover] = useState12(null);
5857
6641
  const label = hover ? `${hover.r + 1} \xD7 ${hover.c + 1}` : "Inserir tabela";
5858
- return /* @__PURE__ */ jsxs12("div", { className: "ed-table-picker", children: [
5859
- /* @__PURE__ */ jsx13("div", { className: "ed-table-picker-label", children: label }),
5860
- /* @__PURE__ */ jsx13(
6642
+ return /* @__PURE__ */ jsxs15("div", { className: "ed-table-picker", children: [
6643
+ /* @__PURE__ */ jsx15("div", { className: "ed-table-picker-label", children: label }),
6644
+ /* @__PURE__ */ jsx15(
5861
6645
  "div",
5862
6646
  {
5863
6647
  className: "ed-table-picker-grid",
@@ -5870,7 +6654,7 @@ function TableSizePicker({ onPick }) {
5870
6654
  { length: PICKER_MAX_ROWS },
5871
6655
  (_, r) => Array.from({ length: PICKER_MAX_COLS }, (_2, c) => {
5872
6656
  const filled = hover != null && r <= hover.r && c <= hover.c;
5873
- return /* @__PURE__ */ jsx13(
6657
+ return /* @__PURE__ */ jsx15(
5874
6658
  "button",
5875
6659
  {
5876
6660
  type: "button",
@@ -5900,10 +6684,10 @@ function blockSelectValue(type, level) {
5900
6684
  return type;
5901
6685
  }
5902
6686
  function Group({ children }) {
5903
- return /* @__PURE__ */ jsx13("div", { className: "ed-toolbar-group", children });
6687
+ return /* @__PURE__ */ jsx15("div", { className: "ed-toolbar-group", children });
5904
6688
  }
5905
6689
  function MarkButton({ title, pressed, onClick, children }) {
5906
- return /* @__PURE__ */ jsx13(
6690
+ return /* @__PURE__ */ jsx15(
5907
6691
  "button",
5908
6692
  {
5909
6693
  type: "button",
@@ -5920,6 +6704,7 @@ export {
5920
6704
  A4_PAGE,
5921
6705
  Editor,
5922
6706
  EditorProvider,
6707
+ FormulaDialog,
5923
6708
  ImageCaptionDialog,
5924
6709
  LinkDialog,
5925
6710
  NodeView,