@wrrdev/fenix-ui 1.1.15 → 1.1.16

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.
@@ -3337,6 +3337,43 @@ function defineFxRadio() {
3337
3337
  return defineElement("fx-radio", FxRadio);
3338
3338
  }
3339
3339
  defineFxRadio();
3340
+ function toInt(value, fallback) {
3341
+ return Number.isFinite(value) ? Math.trunc(value) : fallback;
3342
+ }
3343
+ function range(start, end) {
3344
+ const out = [];
3345
+ for (let p = start; p <= end; p++) out.push(p);
3346
+ return out;
3347
+ }
3348
+ function pageRange(current, count, options = {}) {
3349
+ const pages = Math.max(0, toInt(count, 0));
3350
+ if (pages === 0) return [];
3351
+ const boundaries = Math.max(0, toInt(options.boundaries ?? 1, 1));
3352
+ const siblings = Math.max(0, toInt(options.siblings ?? 1, 1));
3353
+ const page = Math.min(Math.max(1, toInt(current, 1)), pages);
3354
+ if (pages <= boundaries * 2 + siblings * 2 + 3) return range(1, pages);
3355
+ const startPages = range(1, Math.min(boundaries, pages));
3356
+ const endPages = range(
3357
+ Math.max(pages - boundaries + 1, boundaries + 1),
3358
+ pages
3359
+ );
3360
+ const siblingsStart = Math.max(
3361
+ Math.min(page - siblings, pages - boundaries - siblings * 2 - 1),
3362
+ boundaries + 2
3363
+ );
3364
+ const siblingsEnd = Math.min(
3365
+ Math.max(page + siblings, boundaries + siblings * 2 + 2),
3366
+ endPages.length > 0 ? endPages[0] - 2 : pages - 1
3367
+ );
3368
+ const items = [...startPages];
3369
+ if (siblingsStart > boundaries + 2) items.push("ellipsis");
3370
+ else if (boundaries + 1 < pages - boundaries) items.push(boundaries + 1);
3371
+ items.push(...range(siblingsStart, siblingsEnd));
3372
+ if (siblingsEnd < pages - boundaries - 1) items.push("ellipsis");
3373
+ else if (pages - boundaries > boundaries) items.push(pages - boundaries);
3374
+ items.push(...endPages);
3375
+ return items;
3376
+ }
3340
3377
  const LOCALE = "pt-BR";
3341
3378
  const PIPES = {
3342
3379
  /** Formata como moeda brasileira (R$). */
@@ -3991,12 +4028,15 @@ const _FxTable = class _FxTable extends FxElement {
3991
4028
  const bodyHtml = rows.length ? rows.map(
3992
4029
  (row, i) => `<tr part="row" data-index="${i}">${cols.map((c) => `<td part="cell" style="text-align:${c.align}">${this.cellHtml(c, row)}</td>`).join("")}</tr>`
3993
4030
  ).join("") : `<tr><td class="empty" colspan="${cols.length || 1}">${esc(this.getAttr("empty-message", "Nenhum registro encontrado"))}</td></tr>`;
4031
+ const pageButtons = pageRange(this.page + 1, pages).map(
4032
+ (item) => item === "ellipsis" ? `<span class="ellipsis" part="ellipsis" aria-hidden="true">…</span>` : `<button type="button" class="pg-btn" part="page" data-pg="${item - 1}"${item === this.page + 1 ? ' aria-current="page"' : ""}>${item}</button>`
4033
+ ).join("");
3994
4034
  const pagerHtml = !paginated ? "" : `
3995
4035
  <div class="pager" part="pager">
3996
4036
  <span class="info">Página ${this.page + 1} de ${pages} · ${total} registros</span>
3997
4037
  <button type="button" class="pg-btn" part="first" aria-label="Primeira página" data-pg="first" ${this.page === 0 ? "disabled" : ""}>${fenixIconHtml("first_page")}</button>
3998
4038
  <button type="button" class="pg-btn" part="prev" aria-label="Página anterior" data-pg="prev" ${this.page === 0 ? "disabled" : ""}>${fenixIconHtml("navigate_before")}</button>
3999
- ${Array.from({ length: pages }, (_, p) => `<button type="button" class="pg-btn" data-pg="${p}" aria-current="${p === this.page}">${p + 1}</button>`).join("")}
4039
+ ${pageButtons}
4000
4040
  <button type="button" class="pg-btn" part="next" aria-label="Próxima página" data-pg="next" ${this.page >= pages - 1 ? "disabled" : ""}>${fenixIconHtml("navigate_next")}</button>
4001
4041
  <button type="button" class="pg-btn" part="last" aria-label="Última página" data-pg="last" ${this.page >= pages - 1 ? "disabled" : ""}>${fenixIconHtml("last_page")}</button>
4002
4042
  <label class="info">${esc("Por página:")}
@@ -4352,7 +4392,7 @@ _FxTable.styles = css`
4352
4392
  .pg-btn .fx-icon {
4353
4393
  font-size: calc(var(--fx-font-size) - 1px);
4354
4394
  }
4355
- .pg-btn:hover:not(:disabled):not([aria-current="true"]) {
4395
+ .pg-btn:hover:not(:disabled):not([aria-current="page"]) {
4356
4396
  border-color: var(--fx-color-primary);
4357
4397
  color: var(--fx-color-primary);
4358
4398
  }
@@ -4360,12 +4400,25 @@ _FxTable.styles = css`
4360
4400
  opacity: 0.5;
4361
4401
  cursor: not-allowed;
4362
4402
  }
4363
- .pg-btn[aria-current="true"] {
4403
+ .pg-btn[aria-current="page"] {
4364
4404
  background: var(--fx-color-primary);
4365
4405
  border-color: var(--fx-color-primary);
4366
4406
  color: #fff;
4367
4407
  font-weight: var(--fx-font-weight);
4368
4408
  }
4409
+ /* Elipse da janela de páginas (1 … 499 [500] 501 … 1000): ocupa o
4410
+ mesmo espaço de um botão para o rodapé não "pular" ao navegar,
4411
+ mas não é clicável. */
4412
+ .pager .ellipsis {
4413
+ display: inline-flex;
4414
+ align-items: center;
4415
+ justify-content: center;
4416
+ min-width: var(--fx-size-sm);
4417
+ height: var(--fx-size-sm);
4418
+ color: var(--fx-text-muted);
4419
+ font-size: calc(var(--fx-font-size) - 2px);
4420
+ user-select: none;
4421
+ }
4369
4422
  /* O seletor "Por página" só mostra números, então não pode herdar a
4370
4423
  largura padrão do <fx-select> (200px / 180px em size="sm"), que
4371
4424
  deixava o rodapé da paginação desproporcional. O limite tem que ser
@@ -6118,10 +6171,10 @@ function rootOf(editor) {
6118
6171
  const root = editor.getRootNode();
6119
6172
  return typeof ShadowRoot !== "undefined" && root instanceof ShadowRoot ? root : document;
6120
6173
  }
6121
- function isRangeInside(editor, range) {
6122
- if (!range) return false;
6123
- const start = range.startContainer;
6124
- const end = range.endContainer;
6174
+ function isRangeInside(editor, range2) {
6175
+ if (!range2) return false;
6176
+ const start = range2.startContainer;
6177
+ const end = range2.endContainer;
6125
6178
  return editor.contains(start) && editor.contains(end);
6126
6179
  }
6127
6180
  function readSelectionRange(root) {
@@ -6132,10 +6185,10 @@ function readSelectionRange(root) {
6132
6185
  const ranges = selection.getComposedRanges({ shadowRoots: [root] });
6133
6186
  const first = ranges[0];
6134
6187
  if (first) {
6135
- const range = document.createRange();
6136
- range.setStart(first.startContainer, first.startOffset);
6137
- range.setEnd(first.endContainer, first.endOffset);
6138
- return range;
6188
+ const range2 = document.createRange();
6189
+ range2.setStart(first.startContainer, first.startOffset);
6190
+ range2.setEnd(first.endContainer, first.endOffset);
6191
+ return range2;
6139
6192
  }
6140
6193
  } catch {
6141
6194
  }
@@ -6143,41 +6196,41 @@ function readSelectionRange(root) {
6143
6196
  return selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
6144
6197
  }
6145
6198
  function getRange(editor, fallback) {
6146
- const range = readSelectionRange(rootOf(editor));
6147
- if (isRangeInside(editor, range)) return range;
6199
+ const range2 = readSelectionRange(rootOf(editor));
6200
+ if (isRangeInside(editor, range2)) return range2;
6148
6201
  if (isRangeInside(editor, fallback ?? null)) return fallback ?? null;
6149
6202
  return null;
6150
6203
  }
6151
6204
  function saveRange(editor) {
6152
- const range = getRange(editor);
6153
- return range ? range.cloneRange() : null;
6205
+ const range2 = getRange(editor);
6206
+ return range2 ? range2.cloneRange() : null;
6154
6207
  }
6155
- function restoreRange(editor, range) {
6156
- if (!range || !isRangeInside(editor, range)) return;
6208
+ function restoreRange(editor, range2) {
6209
+ if (!range2 || !isRangeInside(editor, range2)) return;
6157
6210
  editor.focus({ preventScroll: true });
6158
6211
  const selection = document.getSelection();
6159
6212
  if (!selection) return;
6160
6213
  selection.removeAllRanges();
6161
- selection.addRange(range);
6214
+ selection.addRange(range2);
6162
6215
  }
6163
6216
  function placeCaretAtEnd(editor) {
6164
- const range = document.createRange();
6165
- range.selectNodeContents(editor);
6166
- range.collapse(false);
6217
+ const range2 = document.createRange();
6218
+ range2.selectNodeContents(editor);
6219
+ range2.collapse(false);
6167
6220
  const selection = document.getSelection();
6168
6221
  if (!selection) return;
6169
6222
  selection.removeAllRanges();
6170
- selection.addRange(range);
6223
+ selection.addRange(range2);
6171
6224
  }
6172
- function getBlock(editor, range) {
6173
- const active = range ?? getRange(editor);
6225
+ function getBlock(editor, range2) {
6226
+ const active = range2 ?? getRange(editor);
6174
6227
  if (!active) return null;
6175
6228
  const node = active.startContainer;
6176
6229
  const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
6177
6230
  const block = el?.closest(BLOCK_SELECTOR) ?? null;
6178
6231
  return block && editor.contains(block) ? block : null;
6179
6232
  }
6180
- function getSelectedBlocks(editor, range) {
6233
+ function getSelectedBlocks(editor, range2) {
6181
6234
  const active = getRange(editor);
6182
6235
  if (!active) return [];
6183
6236
  if (active.collapsed) {
@@ -6197,11 +6250,11 @@ function closestInEditor(editor, node, selector) {
6197
6250
  const match = el?.closest(selector) ?? null;
6198
6251
  return match && editor.contains(match) ? match : null;
6199
6252
  }
6200
- function setSelection(range) {
6253
+ function setSelection(range2) {
6201
6254
  const selection = document.getSelection();
6202
6255
  if (!selection) return;
6203
6256
  selection.removeAllRanges();
6204
- selection.addRange(range);
6257
+ selection.addRange(range2);
6205
6258
  }
6206
6259
  function nativeExec(command, value) {
6207
6260
  const exec = document.execCommand;
@@ -6214,16 +6267,16 @@ function nativeExec(command, value) {
6214
6267
  }
6215
6268
  function insertHtml(editor, html) {
6216
6269
  if (nativeExec("insertHTML", html)) return true;
6217
- const range = getRange(editor);
6218
- if (!range) {
6270
+ const range2 = getRange(editor);
6271
+ if (!range2) {
6219
6272
  editor.insertAdjacentHTML("beforeend", html);
6220
6273
  placeCaretAtEnd(editor);
6221
6274
  return true;
6222
6275
  }
6223
- range.deleteContents();
6224
- const fragment = range.createContextualFragment(html);
6276
+ range2.deleteContents();
6277
+ const fragment = range2.createContextualFragment(html);
6225
6278
  const last = fragment.lastChild;
6226
- range.insertNode(fragment);
6279
+ range2.insertNode(fragment);
6227
6280
  if (last) {
6228
6281
  const next = document.createRange();
6229
6282
  next.setStartAfter(last);
@@ -6239,12 +6292,12 @@ function unwrap(el) {
6239
6292
  el.remove();
6240
6293
  }
6241
6294
  function wrapSelection(editor, tag) {
6242
- const range = getRange(editor);
6243
- if (!range) return false;
6295
+ const range2 = getRange(editor);
6296
+ if (!range2) return false;
6244
6297
  const el = document.createElement(tag);
6245
- if (range.collapsed) {
6298
+ if (range2.collapsed) {
6246
6299
  el.appendChild(document.createTextNode("​"));
6247
- range.insertNode(el);
6300
+ range2.insertNode(el);
6248
6301
  const caret = document.createRange();
6249
6302
  caret.setStart(el.firstChild ?? el, 1);
6250
6303
  caret.collapse(true);
@@ -6252,10 +6305,10 @@ function wrapSelection(editor, tag) {
6252
6305
  return true;
6253
6306
  }
6254
6307
  try {
6255
- range.surroundContents(el);
6308
+ range2.surroundContents(el);
6256
6309
  } catch {
6257
- el.appendChild(range.extractContents());
6258
- range.insertNode(el);
6310
+ el.appendChild(range2.extractContents());
6311
+ range2.insertNode(el);
6259
6312
  }
6260
6313
  return true;
6261
6314
  }
@@ -6271,9 +6324,9 @@ function toggleInline(editor, tag) {
6271
6324
  };
6272
6325
  const nativeCommand = nativeMap[tag];
6273
6326
  if (nativeCommand && nativeExec(nativeCommand)) return true;
6274
- const range = getRange(editor);
6275
- if (!range) return false;
6276
- const current = (range.startContainer.nodeType === Node.ELEMENT_NODE ? range.startContainer : range.startContainer.parentElement)?.closest(tag);
6327
+ const range2 = getRange(editor);
6328
+ if (!range2) return false;
6329
+ const current = (range2.startContainer.nodeType === Node.ELEMENT_NODE ? range2.startContainer : range2.startContainer.parentElement)?.closest(tag);
6277
6330
  if (current && editor.contains(current)) {
6278
6331
  unwrap(current);
6279
6332
  return true;
@@ -6322,31 +6375,31 @@ function toggleList(editor, ordered) {
6322
6375
  list.appendChild(li);
6323
6376
  block.remove();
6324
6377
  }
6325
- const range = document.createRange();
6326
- range.selectNodeContents(list.lastElementChild ?? list);
6327
- range.collapse(false);
6328
- setSelection(range);
6378
+ const range2 = document.createRange();
6379
+ range2.selectNodeContents(list.lastElementChild ?? list);
6380
+ range2.collapse(false);
6381
+ setSelection(range2);
6329
6382
  return true;
6330
6383
  }
6331
6384
  function removeFormat(editor) {
6332
6385
  if (nativeExec("removeFormat")) return true;
6333
- const range = getRange(editor);
6334
- if (!range) return false;
6335
- const root = range.commonAncestorContainer;
6386
+ const range2 = getRange(editor);
6387
+ if (!range2) return false;
6388
+ const root = range2.commonAncestorContainer;
6336
6389
  const container = root.nodeType === Node.ELEMENT_NODE ? root : root.parentElement;
6337
6390
  if (!container) return false;
6338
6391
  const tags = ["strong", "b", "em", "i", "u", "s", "strike", "span", "mark", "code", "sub", "sup"];
6339
6392
  for (const el of Array.from(container.querySelectorAll(tags.join(",")))) {
6340
- if (range.intersectsNode(el)) unwrap(el);
6393
+ if (range2.intersectsNode(el)) unwrap(el);
6341
6394
  }
6342
6395
  return true;
6343
6396
  }
6344
6397
  const linkHtml = (href, label, target) => `<a href="${escapeAttr(href)}" target="${target}" rel="noopener noreferrer">${escapeText(label)}</a>`;
6345
6398
  function applyLink(editor, href, text, target = "_blank") {
6346
6399
  const label = text?.trim() || href;
6347
- const range = getRange(editor);
6348
- if (!range) return insertHtml(editor, linkHtml(href, label, target));
6349
- const anchor = (range.startContainer.nodeType === Node.ELEMENT_NODE ? range.startContainer : range.startContainer.parentElement)?.closest("a");
6400
+ const range2 = getRange(editor);
6401
+ if (!range2) return insertHtml(editor, linkHtml(href, label, target));
6402
+ const anchor = (range2.startContainer.nodeType === Node.ELEMENT_NODE ? range2.startContainer : range2.startContainer.parentElement)?.closest("a");
6350
6403
  if (anchor && editor.contains(anchor)) {
6351
6404
  anchor.setAttribute("href", href);
6352
6405
  anchor.setAttribute("target", target);
@@ -6354,9 +6407,9 @@ function applyLink(editor, href, text, target = "_blank") {
6354
6407
  if (text && text !== anchor.textContent) anchor.textContent = text;
6355
6408
  return true;
6356
6409
  }
6357
- if (!range.collapsed) {
6410
+ if (!range2.collapsed) {
6358
6411
  if (nativeExec("createLink", href)) {
6359
- const created = (range.startContainer.nodeType === Node.ELEMENT_NODE ? range.startContainer : range.startContainer.parentElement)?.closest("a");
6412
+ const created = (range2.startContainer.nodeType === Node.ELEMENT_NODE ? range2.startContainer : range2.startContainer.parentElement)?.closest("a");
6360
6413
  created?.setAttribute("target", target);
6361
6414
  created?.setAttribute("rel", "noopener noreferrer");
6362
6415
  return true;
@@ -6366,10 +6419,10 @@ function applyLink(editor, href, text, target = "_blank") {
6366
6419
  el.setAttribute("target", target);
6367
6420
  el.setAttribute("rel", "noopener noreferrer");
6368
6421
  try {
6369
- range.surroundContents(el);
6422
+ range2.surroundContents(el);
6370
6423
  } catch {
6371
- el.appendChild(range.extractContents());
6372
- range.insertNode(el);
6424
+ el.appendChild(range2.extractContents());
6425
+ range2.insertNode(el);
6373
6426
  }
6374
6427
  return true;
6375
6428
  }
@@ -6377,9 +6430,9 @@ function applyLink(editor, href, text, target = "_blank") {
6377
6430
  }
6378
6431
  function unlink(editor) {
6379
6432
  if (nativeExec("unlink")) return true;
6380
- const range = getRange(editor);
6381
- if (!range) return false;
6382
- const anchor = (range.startContainer.nodeType === Node.ELEMENT_NODE ? range.startContainer : range.startContainer.parentElement)?.closest("a");
6433
+ const range2 = getRange(editor);
6434
+ if (!range2) return false;
6435
+ const anchor = (range2.startContainer.nodeType === Node.ELEMENT_NODE ? range2.startContainer : range2.startContainer.parentElement)?.closest("a");
6383
6436
  if (anchor && editor.contains(anchor)) {
6384
6437
  unwrap(anchor);
6385
6438
  return true;
@@ -6447,10 +6500,10 @@ function cellPosition(table, cell) {
6447
6500
  }
6448
6501
  return null;
6449
6502
  }
6450
- function selectedCells(table, range) {
6503
+ function selectedCells(table, range2) {
6451
6504
  return Array.from(table.querySelectorAll("td,th")).filter((cell) => {
6452
6505
  try {
6453
- return range.intersectsNode(cell);
6506
+ return range2.intersectsNode(cell);
6454
6507
  } catch {
6455
6508
  return false;
6456
6509
  }
@@ -6462,8 +6515,8 @@ function copyCellAttributes(from, to) {
6462
6515
  to.setAttribute(attr.name, attr.value);
6463
6516
  }
6464
6517
  }
6465
- function mergeSelectedCells(table, range) {
6466
- const cells = selectedCells(table, range);
6518
+ function mergeSelectedCells(table, range2) {
6519
+ const cells = selectedCells(table, range2);
6467
6520
  if (cells.length < 2) return null;
6468
6521
  const { matrix } = tableMatrix(table);
6469
6522
  const positions = cells.map((cell) => ({ cell, position: cellPosition(table, cell) })).filter((item) => Boolean(item.position));
@@ -6846,9 +6899,9 @@ const _FxEditor = class _FxEditor extends FxFormElement {
6846
6899
  mergeCells() {
6847
6900
  const table = __privateMethod(this, _FxEditor_instances, currentTable_fn).call(this);
6848
6901
  const editor = this.editor;
6849
- const range = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
6850
- if (!table || !range) return false;
6851
- const merged = mergeSelectedCells(table, range);
6902
+ const range2 = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
6903
+ if (!table || !range2) return false;
6904
+ const merged = mergeSelectedCells(table, range2);
6852
6905
  if (!merged) return false;
6853
6906
  placeCaretAtEnd(merged);
6854
6907
  __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
@@ -6858,8 +6911,8 @@ const _FxEditor = class _FxEditor extends FxFormElement {
6858
6911
  splitCell() {
6859
6912
  const table = __privateMethod(this, _FxEditor_instances, currentTable_fn).call(this);
6860
6913
  const editor = this.editor;
6861
- const range = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
6862
- const cell = editor ? closestInEditor(editor, range?.startContainer ?? null, "td,th") : null;
6914
+ const range2 = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
6915
+ const cell = editor ? closestInEditor(editor, range2?.startContainer ?? null, "td,th") : null;
6863
6916
  if (!table || !cell) return false;
6864
6917
  const created = splitCell(table, cell);
6865
6918
  if (!created.length) return false;
@@ -7119,8 +7172,8 @@ fits_fn = function(extra) {
7119
7172
  const max = this.maxlength;
7120
7173
  if (!max) return true;
7121
7174
  const editor = this.editor;
7122
- const range = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
7123
- const selected = range && !range.collapsed ? range.toString().length : 0;
7175
+ const range2 = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
7176
+ const selected = range2 && !range2.collapsed ? range2.toString().length : 0;
7124
7177
  return this.text.length - selected + extra <= max;
7125
7178
  };
7126
7179
  limitError_fn = function() {
@@ -7243,9 +7296,9 @@ bindGlobalSelection_fn = function() {
7243
7296
  const handler = () => {
7244
7297
  const editor = this.editor;
7245
7298
  if (!editor) return;
7246
- const range = getRange(editor, __privateGet(this, _lastRange));
7247
- if (!range) return;
7248
- __privateSet(this, _lastRange, range.cloneRange());
7299
+ const range2 = getRange(editor, __privateGet(this, _lastRange));
7300
+ if (!range2) return;
7301
+ __privateSet(this, _lastRange, range2.cloneRange());
7249
7302
  cancelAnimationFrame(__privateGet(this, _selectionRaf));
7250
7303
  __privateSet(this, _selectionRaf, requestAnimationFrame(() => __privateMethod(this, _FxEditor_instances, updateToolbar_fn).call(this)));
7251
7304
  };
@@ -7370,8 +7423,8 @@ renderToolbar_fn = function() {
7370
7423
  updateToolbar_fn = function() {
7371
7424
  const editor = this.editor;
7372
7425
  if (!editor) return;
7373
- const range = getRange(editor, __privateGet(this, _lastRange));
7374
- if (!range) return;
7426
+ const range2 = getRange(editor, __privateGet(this, _lastRange));
7427
+ if (!range2) return;
7375
7428
  const setActive = (cmd, active) => {
7376
7429
  const button = this.root.querySelector(`[data-cmd="${cmd}"]`);
7377
7430
  if (!button) return;
@@ -7379,7 +7432,7 @@ updateToolbar_fn = function() {
7379
7432
  button.setAttribute("aria-pressed", String(active));
7380
7433
  };
7381
7434
  const ancestor = (selector) => {
7382
- const node = range.startContainer;
7435
+ const node = range2.startContainer;
7383
7436
  const el = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
7384
7437
  const match = el?.closest(selector);
7385
7438
  return Boolean(match && editor.contains(match));
@@ -7391,7 +7444,7 @@ updateToolbar_fn = function() {
7391
7444
  setActive("code", ancestor("code"));
7392
7445
  setActive("insertUnorderedList", ancestor("ul"));
7393
7446
  setActive("insertOrderedList", ancestor("ol"));
7394
- const block = getBlock(editor, range);
7447
+ const block = getBlock(editor, range2);
7395
7448
  const blockTag = block?.tagName.toLowerCase() ?? "p";
7396
7449
  const blockSelect = this.root.querySelector("[data-block]");
7397
7450
  if (blockSelect) {
@@ -7635,9 +7688,9 @@ handleKeydown_fn = function(event) {
7635
7688
  tabInTable_fn = function(backwards) {
7636
7689
  const editor = this.editor;
7637
7690
  if (!editor) return false;
7638
- const range = getRange(editor, __privateGet(this, _lastRange));
7639
- if (!range) return false;
7640
- const cell = closestInEditor(editor, range.startContainer, "td,th");
7691
+ const range2 = getRange(editor, __privateGet(this, _lastRange));
7692
+ if (!range2) return false;
7693
+ const cell = closestInEditor(editor, range2.startContainer, "td,th");
7641
7694
  const table = cell?.closest("table");
7642
7695
  if (!cell || !table) return false;
7643
7696
  const cells = Array.from(table.querySelectorAll("td,th"));
@@ -7807,14 +7860,14 @@ openLinkDialog_fn = async function(existing) {
7807
7860
  const editor = this.editor;
7808
7861
  if (!editor) return;
7809
7862
  if (existing) __privateMethod(this, _FxEditor_instances, selectAnchor_fn).call(this, existing);
7810
- let range = getRange(editor, __privateGet(this, _lastRange));
7811
- if (!range) {
7863
+ let range2 = getRange(editor, __privateGet(this, _lastRange));
7864
+ if (!range2) {
7812
7865
  placeCaretAtEnd(editor);
7813
- range = getRange(editor);
7814
- __privateSet(this, _lastRange, range?.cloneRange() ?? null);
7866
+ range2 = getRange(editor);
7867
+ __privateSet(this, _lastRange, range2?.cloneRange() ?? null);
7815
7868
  }
7816
- const anchor = existing ?? closestInEditor(editor, range?.startContainer ?? null, "a");
7817
- const selected = range && !range.collapsed ? range.toString() : anchor?.textContent ?? "";
7869
+ const anchor = existing ?? closestInEditor(editor, range2?.startContainer ?? null, "a");
7870
+ const selected = range2 && !range2.collapsed ? range2.toString() : anchor?.textContent ?? "";
7818
7871
  const result = await __privateMethod(this, _FxEditor_instances, openDialog_fn).call(this, "Link", [
7819
7872
  { name: "url", label: "URL", type: "url", value: anchor?.getAttribute("href") ?? "", placeholder: "https://..." },
7820
7873
  { name: "text", label: "Texto (quando não há seleção)", value: selected, placeholder: "Texto do link" },
@@ -8037,13 +8090,13 @@ selectAnchor_fn = function(anchor) {
8037
8090
  const editor = this.editor;
8038
8091
  if (!editor) return;
8039
8092
  editor.focus({ preventScroll: true });
8040
- const range = document.createRange();
8041
- range.selectNodeContents(anchor);
8093
+ const range2 = document.createRange();
8094
+ range2.selectNodeContents(anchor);
8042
8095
  const selection = document.getSelection();
8043
8096
  if (!selection) return;
8044
8097
  selection.removeAllRanges();
8045
- selection.addRange(range);
8046
- __privateSet(this, _lastRange, range.cloneRange());
8098
+ selection.addRange(range2);
8099
+ __privateSet(this, _lastRange, range2.cloneRange());
8047
8100
  };
8048
8101
  handleLinkOverlayClick_fn = function(event) {
8049
8102
  const action = event.target.closest("[data-link-action]");
@@ -8314,19 +8367,19 @@ hidePanel_fn = function() {
8314
8367
  currentTable_fn = function() {
8315
8368
  const editor = this.editor;
8316
8369
  if (!editor) return null;
8317
- const range = getRange(editor, __privateGet(this, _lastRange));
8318
- return closestInEditor(editor, range?.startContainer ?? null, "table");
8370
+ const range2 = getRange(editor, __privateGet(this, _lastRange));
8371
+ return closestInEditor(editor, range2?.startContainer ?? null, "table");
8319
8372
  };
8320
8373
  tableAction_fn = function(action) {
8321
8374
  const table = __privateMethod(this, _FxEditor_instances, currentTable_fn).call(this);
8322
8375
  if (!table) return;
8323
8376
  const editor = this.editor;
8324
- const range = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
8325
- const cell = editor ? closestInEditor(editor, range?.startContainer ?? null, "td,th") : null;
8377
+ const range2 = editor ? getRange(editor, __privateGet(this, _lastRange)) : null;
8378
+ const cell = editor ? closestInEditor(editor, range2?.startContainer ?? null, "td,th") : null;
8326
8379
  const row = cell?.parentElement;
8327
8380
  if (action === "merge-cells") {
8328
- if (!range) return;
8329
- const merged = mergeSelectedCells(table, range);
8381
+ if (!range2) return;
8382
+ const merged = mergeSelectedCells(table, range2);
8330
8383
  if (!merged) return;
8331
8384
  placeCaretAtEnd(merged);
8332
8385
  __privateMethod(this, _FxEditor_instances, afterCommand_fn).call(this);
@@ -13101,17 +13154,16 @@ const _FxPagination = class _FxPagination extends FxElement {
13101
13154
  const pages = this.pages;
13102
13155
  const current = Math.min(Math.max(1, this.page), pages);
13103
13156
  const opts = (this.getAttr("rows-options", "5,10,20,50") || "").split(",").map((s) => s.trim()).filter(Boolean);
13104
- const window_ = [];
13105
- for (let p = Math.max(1, current - 2); p <= Math.min(pages, current + 2); p++) window_.push(p);
13106
- const from = total0(current, this.rows);
13157
+ const pageButtons = pageRange(current, pages).map(
13158
+ (item) => item === "ellipsis" ? `<span class="ellipsis" part="ellipsis" aria-hidden="true">…</span>` : `<button type="button" class="nav ${item === current ? "active" : ""}" part="page" data-go="${item}"${item === current ? ' aria-current="page"' : ""}>${item}</button>`
13159
+ ).join("");
13160
+ const from = (current - 1) * this.rows + 1;
13107
13161
  const to = Math.min(current * this.rows, this.total);
13108
13162
  this.setTemplate(`
13109
13163
  <span class="info">${this.total ? `${from}-${to} de ${this.total}` : "0 itens"}</span>
13110
13164
  <button type="button" class="nav" part="first" aria-label="Primeira página" data-go="1" ${current <= 1 ? "disabled" : ""}>${fenixIconHtml("first_page")}</button>
13111
13165
  <button type="button" class="nav" part="prev" aria-label="Página anterior" data-go="${current - 1}" ${current <= 1 ? "disabled" : ""}>${fenixIconHtml("navigate_before")}</button>
13112
- ${window_[0] !== 1 && pages > 5 ? `<button type="button" class="nav" data-go="1">1</button>` : ""}
13113
- ${window_.map((p) => `<button type="button" class="nav ${p === current ? "active" : ""}" data-go="${p}">${p}</button>`).join("")}
13114
- ${window_[window_.length - 1] !== pages && pages > 5 ? `<button type="button" class="nav" data-go="${pages}">${pages}</button>` : ""}
13166
+ ${pageButtons}
13115
13167
  <button type="button" class="nav" part="next" aria-label="Próxima página" data-go="${current + 1}" ${current >= pages ? "disabled" : ""}>${fenixIconHtml("navigate_next")}</button>
13116
13168
  <button type="button" class="nav" part="last" aria-label="Última página" data-go="${pages}" ${current >= pages ? "disabled" : ""}>${fenixIconHtml("last_page")}</button>
13117
13169
  ${opts.length ? `
@@ -13119,9 +13171,6 @@ const _FxPagination = class _FxPagination extends FxElement {
13119
13171
  ${opts.map((o) => `<option value="${esc(o)}">${esc(o)}</option>`).join("")}
13120
13172
  </fx-select>` : ""}
13121
13173
  `);
13122
- function total0(page, rows) {
13123
- return (page - 1) * rows + 1;
13124
- }
13125
13174
  this.root.querySelectorAll(".nav[data-go]").forEach((btn) => {
13126
13175
  btn.addEventListener("click", () => {
13127
13176
  const target = Number(btn.dataset.go);
@@ -13153,6 +13202,7 @@ _FxPagination.styles = css`
13153
13202
  :host {
13154
13203
  display: flex;
13155
13204
  align-items: center;
13205
+ flex-wrap: wrap;
13156
13206
  gap: var(--fx-space-sm);
13157
13207
  font-family: var(--fx-font-family);
13158
13208
  font-size: var(--fx-font-size);
@@ -13190,6 +13240,18 @@ _FxPagination.styles = css`
13190
13240
  color: #fff;
13191
13241
  font-weight: 600;
13192
13242
  }
13243
+ /* Elipse entre a janela de páginas e as bordas: ocupa o mesmo espaço de
13244
+ um botão (para o rodapé não "pular" ao navegar) mas não é clicável. */
13245
+ .ellipsis {
13246
+ display: inline-flex;
13247
+ align-items: center;
13248
+ justify-content: center;
13249
+ min-width: var(--fx-size-sm);
13250
+ height: var(--fx-size-sm);
13251
+ color: var(--fx-text-muted);
13252
+ font-size: calc(var(--fx-font-size) - 2px);
13253
+ user-select: none;
13254
+ }
13193
13255
  .info { color: var(--fx-text-muted); font-size: calc(var(--fx-font-size) - 2px); }
13194
13256
  fx-select { vertical-align: middle; }
13195
13257
  fx-select::part(trigger) {
@@ -13525,8 +13587,8 @@ const _FxKnob = class _FxKnob extends FxFormElement {
13525
13587
  const min = this.min;
13526
13588
  const max = this.max;
13527
13589
  const value = this.clampValue(this.value);
13528
- const range = max - min;
13529
- const pct = range > 0 ? (value - min) / range : 0;
13590
+ const range2 = max - min;
13591
+ const pct = range2 > 0 ? (value - min) / range2 : 0;
13530
13592
  const sizeNum = this.getSizeNum();
13531
13593
  const strokeW = this.strokeWidth;
13532
13594
  const radius = (sizeNum - strokeW) / 2;