ooxml-ui 1.8.4 → 1.9.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.
Files changed (87) hide show
  1. package/dist/{chunk-CTPXTRDT.js → chunk-PH7IBZOZ.js} +1 -1
  2. package/dist/docx/columns-dialog.d.ts +1 -1
  3. package/dist/docx/editor-core.d.ts +2 -0
  4. package/dist/docx/page-controller.d.ts +3 -2
  5. package/dist/docx/print-drag-scroll.d.ts +7 -0
  6. package/dist/docx/print-editing-geometry.d.ts +2 -0
  7. package/dist/docx/print-editing-index.d.ts +30 -0
  8. package/dist/docx/print-editing.d.ts +12 -0
  9. package/dist/docx/print-keyboard-navigation.d.ts +18 -0
  10. package/dist/docx/print-layout-view.d.ts +6 -10
  11. package/dist/docx/print-layout.d.ts +2 -2
  12. package/dist/docx/print-picture.d.ts +1 -0
  13. package/dist/docx.js +677 -20
  14. package/dist/index.js +2 -2
  15. package/dist/pptx/{chunk-KMNNTEGF.cjs → chunk-BFZDO2DY.cjs} +429 -194
  16. package/dist/pptx/{chunk-VRFNAF3Q.mjs → chunk-F7BBPOVJ.mjs} +9 -0
  17. package/dist/pptx/{chunk-STXGHV25.cjs → chunk-HWW2UVUP.cjs} +161 -4
  18. package/dist/pptx/{chunk-GHFJ46NS.mjs → chunk-KBCKCW5M.mjs} +371 -161
  19. package/dist/pptx/{chunk-NVYVHNPD.mjs → chunk-MKVKISFW.mjs} +1 -1
  20. package/dist/pptx/{chunk-NKHPE4PS.cjs → chunk-PKDISDDZ.cjs} +2 -2
  21. package/dist/pptx/{chunk-SM3CWDIQ.cjs → chunk-QVYJB7G2.cjs} +9 -0
  22. package/dist/pptx/chunk-SABFKDRM.mjs +286 -0
  23. package/dist/pptx/dom/elements/image.d.ts.map +1 -1
  24. package/dist/pptx/dom/index.cjs +221 -213
  25. package/dist/pptx/dom/index.mjs +24 -16
  26. package/dist/pptx/i18n/index.cjs +6 -6
  27. package/dist/pptx/i18n/index.mjs +1 -1
  28. package/dist/pptx/i18n/translations-en.d.ts.map +1 -1
  29. package/dist/pptx/index.cjs +2834 -2766
  30. package/dist/pptx/index.mjs +4 -4
  31. package/dist/pptx/render/find-replace.d.ts +1 -1
  32. package/dist/pptx/render/find-replace.d.ts.map +1 -1
  33. package/dist/pptx/render/format-painter.cjs +5 -5
  34. package/dist/pptx/render/format-painter.mjs +2 -2
  35. package/dist/pptx/render/index.d.ts +3 -0
  36. package/dist/pptx/render/index.d.ts.map +1 -1
  37. package/dist/pptx/render/inspector-helpers.cjs +12 -12
  38. package/dist/pptx/render/inspector-helpers.d.ts.map +1 -1
  39. package/dist/pptx/render/inspector-helpers.mjs +1 -1
  40. package/dist/pptx/render/inspector-number.d.ts +15 -0
  41. package/dist/pptx/render/inspector-number.d.ts.map +1 -0
  42. package/dist/pptx/render/picture-frame.d.ts +52 -0
  43. package/dist/pptx/render/picture-frame.d.ts.map +1 -0
  44. package/dist/pptx/render/ribbon-home-commands.d.ts +11 -2
  45. package/dist/pptx/render/ribbon-home-commands.d.ts.map +1 -1
  46. package/dist/pptx/render/share-session.d.ts.map +1 -1
  47. package/dist/pptx/render/slide-operations.d.ts +2 -1
  48. package/dist/pptx/render/slide-operations.d.ts.map +1 -1
  49. package/dist/pptx/render/slide-package-clipboard.d.ts +31 -0
  50. package/dist/pptx/render/slide-package-clipboard.d.ts.map +1 -0
  51. package/dist/pptx/render/slide-sorter-context-menu.d.ts +3 -5
  52. package/dist/pptx/render/slide-sorter-context-menu.d.ts.map +1 -1
  53. package/dist/pptx/render/slide-sorter-state.d.ts +8 -1
  54. package/dist/pptx/render/slide-sorter-state.d.ts.map +1 -1
  55. package/dist/pptx/render/text-advanced.d.ts.map +1 -1
  56. package/dist/pptx/render/text-style-scope.d.ts +41 -1
  57. package/dist/pptx/render/text-style-scope.d.ts.map +1 -1
  58. package/dist/pptx/render/text-style-update.d.ts.map +1 -1
  59. package/dist/pptx/web-components/index.d.ts +2 -0
  60. package/dist/pptx/web-components/index.d.ts.map +1 -1
  61. package/dist/pptx/web-components/slide-clipboard.d.ts +14 -0
  62. package/dist/pptx/web-components/slide-clipboard.d.ts.map +1 -0
  63. package/dist/teams.js +1 -1
  64. package/dist/visio/format-pane-fields.d.ts +2 -0
  65. package/dist/visio/page-setup-action.d.ts +1 -1
  66. package/dist/visio/page-setup-dialog-form.d.ts +1 -1
  67. package/dist/visio/ribbon-action.d.ts +1 -1
  68. package/dist/visio/viewer-accessibility.d.ts +17 -0
  69. package/dist/visio/viewer-insert-dialog.d.ts +2 -1
  70. package/dist/visio/viewer-review.d.ts +2 -0
  71. package/dist/visio.js +304 -14
  72. package/dist/xlsx/commands/pivots.d.ts +2 -0
  73. package/dist/xlsx/commands/sparklines.d.ts +2 -0
  74. package/dist/xlsx/dialogs/help-dialogs.d.ts +2 -2
  75. package/dist/xlsx/dialogs/page-header.d.ts +4 -0
  76. package/dist/xlsx/dialogs/page-setup-tabs.d.ts +6 -1
  77. package/dist/xlsx/dialogs/pivots.d.ts +2 -0
  78. package/dist/xlsx/dialogs/print-preview.d.ts +2 -0
  79. package/dist/xlsx/dialogs/sparklines.d.ts +4 -0
  80. package/dist/xlsx/print-cell.d.ts +4 -0
  81. package/dist/xlsx/print-header.d.ts +7 -0
  82. package/dist/xlsx/print-pages.d.ts +4 -0
  83. package/dist/xlsx/print.d.ts +4 -12
  84. package/dist/xlsx.js +1078 -287
  85. package/package.json +3 -3
  86. package/dist/pptx/chunk-VD7HRMTA.mjs +0 -137
  87. /package/dist/{chunk-SUHT5S2P.js → chunk-SKYBYVYH.js} +0 -0
package/dist/xlsx.js CHANGED
@@ -1,9 +1,9 @@
1
- import './chunk-CTPXTRDT.js';
1
+ import './chunk-PH7IBZOZ.js';
2
2
  import { syncRibbonAddIns } from './chunk-W6AV3GHC.js';
3
3
  export { RIBBON_ADD_IN_EVENT } from './chunk-W6AV3GHC.js';
4
4
  import { defineSmartArt } from './chunk-PXIYHFZ5.js';
5
- import { withExtension, saveExtension, downloadBytes, emit, emitEvent, blobFor, announceFileCommand, pickFile } from './chunk-SUHT5S2P.js';
6
- export { XLSX_EDITOR_EVENTS } from './chunk-SUHT5S2P.js';
5
+ import { withExtension, saveExtension, downloadBytes, emit, emitEvent, blobFor, announceFileCommand, pickFile } from './chunk-SKYBYVYH.js';
6
+ export { XLSX_EDITOR_EVENTS } from './chunk-SKYBYVYH.js';
7
7
  import './chunk-SNV6YKPC.js';
8
8
  import { shadcnBridge } from './chunk-S6ZXU442.js';
9
9
  import { range_control_default, createRibbonOverflow, defineBackstage, defineRibbon, defineRibbonActions, defineTitleBar, defineStatusBar, defineZoomSlider, rangeControl, defineDialog, runKeyTips, assignKeyTips, defineCheckbox, defineGallery, defineColorGrid, defineContextMenu, defineCommentsPane, parseSvgPreview } from './chunk-O7APCA5N.js';
@@ -11,9 +11,9 @@ import { getIcon, registerIcon } from './chunk-M6GF5ED2.js';
11
11
  import { definePresence } from './chunk-L7JV5FVE.js';
12
12
  import { withTokens } from './chunk-OGNNNTKI.js';
13
13
  import './chunk-SPNWHKSR.js';
14
- import { SPECIAL_CODES, FRACTION_CODES, AUTOSUM_FUNCTIONS, themeToCssVars, lightTheme, darkTheme, ICON_ACCENTS, ICON_PATHS, normalizeThemeMode, applyThemeColors, parseSelectionRef, selectionRef, normalizeEditorLocale, DirtyState, createCommandRegistry, createDialogRegistry, activeRef, createSelectionModel, SheetSelections, translator, initialSelection, sheetBaseName, historyOf, onRibbonTabsChange, activeChart, editChart, ribbonTabs, isTabHidden, selectTab, setTabHidden, tabButton, searchCommands, formatNumber, TEMPLATES, createTemplateWorkbook, isMenuSeparator, registerRibbonTabs, installFormatPainter, SHEET_ICONS, clipboardCommands, fontCommands, alignmentCommands, numberCommands, cellCommands, editingCommands, pageLayoutCommands, formulaCommands, dataCommands, contextualCommands, reviewTab, viewTab, helpTab, editBridge, CellViewCache, QUADRANTS, columnHeaderHeight, rowHeaderWidth, GridGeometry, cellRange, scrollToReveal, buildItems, fitNumber, cssFont, clampAddress, selectCell, movingEnd, extendSelection, moveWithinSelection, rowsRange, colsRange, ALL_RANGE, tabMenu, editing, icon, DATA_BAR_COLORS, dataBarRule, COLOR_SCALES, colorScaleRule, iconSetRule, target, tableAt, viewing, activeTable, numberFormatOptions, FONT_NAMES, FONT_SIZES, BORDER_PRESETS, ORIENTATIONS, ACCOUNTING_FORMATS, themePaletteItems, MARGIN_PRESETS, PAPER_SIZES, FUNCTION_MENUS, MORE_FUNCTION_CATEGORIES, functionsIn, isSingleCell, spanRange, selectionCellCount, addRange, activeStyle, selectSpecial, insertFunctionCall, guessHeader, regionOf, HIGHLIGHT_STYLES, ICON_SETS, TABLE_STYLES, tableStylePreview, resolveNameBox, absoluteReference, nameForRange, fillPaint, iconSvg, colSelected, rowSelected, rowHeaderMenu, columnHeaderMenu, cellMenu, recentFunctions, evaluateRef, buildChart, detectCategory, CATEGORIES, TIME_CODES, DATE_CODES, DEFAULT_OPTIONS, cellStyleItems, textDecoration, justify, alignItems, textAlign, hasBorders, edgeCss, diagonalSvg, SYMBOLS, buildCode, UNSET, dxfCss, negativeCodes, iconCount, iconThresholds, rowsOf, colsOf } from 'ooxml-core/xlsx/ui';
14
+ import { SPECIAL_CODES, FRACTION_CODES, AUTOSUM_FUNCTIONS, themeToCssVars, lightTheme, darkTheme, ICON_ACCENTS, ICON_PATHS, normalizeThemeMode, applyThemeColors, parseSelectionRef, selectionRef, normalizeEditorLocale, DirtyState, createCommandRegistry, createDialogRegistry, activeRef, createSelectionModel, SheetSelections, translator, initialSelection, sheetBaseName, historyOf, onRibbonTabsChange, activeChart, editChart, ribbonTabs, isTabHidden, selectTab, setTabHidden, tabButton, searchCommands, formatNumber, TEMPLATES, createTemplateWorkbook, isMenuSeparator, registerRibbonTabs, installFormatPainter, SHEET_ICONS, clipboardCommands, fontCommands, alignmentCommands, numberCommands, cellCommands, editingCommands, pageLayoutCommands, pageBreakCommands, formulaCommands, dataCommands, contextualCommands, reviewTab, viewTab, helpTab, editBridge, CellViewCache, QUADRANTS, columnHeaderHeight, rowHeaderWidth, GridGeometry, cellRange, scrollToReveal, buildItems, fitNumber, cssFont, clampAddress, selectCell, movingEnd, extendSelection, moveWithinSelection, rowsRange, colsRange, ALL_RANGE, tabMenu, editing, icon, DATA_BAR_COLORS, dataBarRule, COLOR_SCALES, colorScaleRule, iconSetRule, target, tableAt, viewing, activeTable, numberFormatOptions, FONT_NAMES, FONT_SIZES, BORDER_PRESETS, ORIENTATIONS, ACCOUNTING_FORMATS, themePaletteItems, MARGIN_PRESETS, PAPER_SIZES, FUNCTION_MENUS, MORE_FUNCTION_CATEGORIES, functionsIn, isSingleCell, spanRange, selectionCellCount, addRange, activeStyle, selectSpecial, insertFunctionCall, guessHeader, regionOf, HIGHLIGHT_STYLES, ICON_SETS, TABLE_STYLES, tableStylePreview, resolveNameBox, absoluteReference, nameForRange, fillPaint, iconSvg, colSelected, rowSelected, rowHeaderMenu, columnHeaderMenu, cellMenu, recentFunctions, evaluateRef, buildChart, detectCategory, CATEGORIES, TIME_CODES, DATE_CODES, DEFAULT_OPTIONS, cellStyleItems, textDecoration, justify, alignItems, textAlign, hasBorders, edgeCss, diagonalSvg, SYMBOLS, buildCode, UNSET, dxfCss, negativeCodes, iconCount, iconThresholds, rowsOf, colsOf } from 'ooxml-core/xlsx/ui';
15
15
  export { EDITOR_LOCALES, THEME_KEYS, normalizeEditorLocale, registerRibbonTabs, themeToCssVars, darkTheme as xlsxDarkTheme, lightTheme as xlsxLightTheme } from 'ooxml-core/xlsx/ui';
16
- import { createWorksheet, createEditSession, approximateMeasure, createWorkbook, MAX_ROW, MAX_COL, chartView, createRefEvaluator, chartBarSpacing, CHART_FILL_PARTS, selectionStats, formatSelectionStat, formatRange, chartSeriesTransparencyPatch, chartSeriesTransparency, chartSeriesGradientPatch, chartSeriesSolidFillPatch, chartSeriesFillPatch, chartWithElementFills, chartElementTransparencyPatch, chartElementTransparency, chartElementGradientPatch, chartElementSolidFillPatch, chartElementFillPatch, chartElementFill, usedRange, chartGradientStopTransparency, createGridMetrics, mergeView, cellView, resolveColor, DEFAULT_THEME, nextSheetName, FUNCTION_CATALOG, mergeAt, visibleCells, getCell, cellInputText, closeParens, isFormulaText, parseCellInput, referenceTarget, formatAddress, navigate, anchorToPixelBox, renderChartSvg, pixelBoxToAnchor, listValidationOptions, validationAt, getValue, resolvePasteOptions, DEFAULT_COL_WIDTH, nameAtCaret, functionMatches, callAtCaret, splice, acceptsReference, translateFormula, isCellError, layoutRemoteSelections, parseHtmlTable, toggleAbsolute, rangeContains, formatValue, isDateFormat, pictureAnchorAt, validateDefinedName, parseAddress, styleAt, parseRange, rangesIntersect, chartColorScheme, coloredReferences, syntaxParams, activeParam, columnLabel, THEME_SLOTS, normalizeRange, currentRegion, autoFitColumnWidth, validateSheetName, dateToSerial, IMAGE_EXTENSIONS, verifySheetPassword, verifyWorkbookPassword, sheetByName, quoteSheetName, serialToDate, BUILTIN_NUMBER_FORMATS, pixelsToColumnWidth, validateTableName } from 'ooxml-core/xlsx';
16
+ import { createWorksheet, createEditSession, approximateMeasure, createWorkbook, MAX_ROW, MAX_COL, chartView, createRefEvaluator, chartBarSpacing, CHART_FILL_PARTS, selectionStats, formatSelectionStat, printRange, formatRange, chartSeriesTransparencyPatch, chartSeriesTransparency, chartSeriesGradientPatch, chartSeriesSolidFillPatch, chartSeriesFillPatch, chartWithElementFills, chartElementTransparencyPatch, chartElementTransparency, chartElementGradientPatch, chartElementSolidFillPatch, chartElementFillPatch, chartElementFill, chartGradientStopTransparency, paginateWorksheet, resolveColor, DEFAULT_THEME, pageHeaderFooter, createGridMetrics, createPrintMergeIndex, formatAddress, cellView, renderHeaderFooterRuns, nextSheetName, FUNCTION_CATALOG, mergeAt, visibleCells, getCell, cellInputText, closeParens, isFormulaText, parseCellInput, referenceTarget, navigate, anchorToPixelBox, renderChartSvg, pixelBoxToAnchor, listValidationOptions, validationAt, getValue, resolvePasteOptions, DEFAULT_COL_WIDTH, nameAtCaret, functionMatches, callAtCaret, splice, acceptsReference, translateFormula, isCellError, layoutRemoteSelections, parseHtmlTable, toggleAbsolute, rangeContains, formatValue, isDateFormat, pictureAnchorAt, selectedSparklineGroups, pivotTableAt, validateDefinedName, usedRange, parseAddress, parseRange, styleAt, rangesIntersect, chartColorScheme, coloredReferences, syntaxParams, activeParam, columnLabel, THEME_SLOTS, normalizeRange, currentRegion, autoFitColumnWidth, validateSheetName, dateToSerial, IMAGE_EXTENSIONS, verifySheetPassword, verifyWorkbookPassword, sheetByName, quoteSheetName, pivotSourceData, printTitles, formatPrintTitleSpan, parsePrintTitleSpan, serialToDate, BUILTIN_NUMBER_FORMATS, pixelsToColumnWidth, validateTableName } from 'ooxml-core/xlsx';
17
17
  import { hyperlinkPolicy } from 'ooxml-core/opc';
18
18
  import { resolveChartGradient, sortGradientStops, withChartGradientDirection, buildChartGradientDef, chartGradientMarkup, CHART_COLOR_PALETTES, chartPaletteColors } from 'ooxml-core/chart';
19
19
  import { render } from 'lit';
@@ -69,35 +69,35 @@ var DEFAULT_AUTHOR_NAME = "Author";
69
69
  function isXlsxEditorAttribute(name) {
70
70
  return XLSX_EDITOR_ATTRIBUTES.includes(name);
71
71
  }
72
- function applyAttribute(target24, name, value) {
72
+ function applyAttribute(target29, name, value) {
73
73
  switch (name) {
74
74
  case "locale":
75
- if (normalizeEditorLocale(value ?? "en") !== target24.locale) target24.locale = value ?? "en";
75
+ if (normalizeEditorLocale(value ?? "en") !== target29.locale) target29.locale = value ?? "en";
76
76
  return;
77
77
  case "read-only":
78
- if ((value !== null && value !== "false") !== target24.readOnly)
79
- target24.readOnly = value !== null && value !== "false";
78
+ if ((value !== null && value !== "false") !== target29.readOnly)
79
+ target29.readOnly = value !== null && value !== "false";
80
80
  return;
81
81
  case "file-name": {
82
82
  const next = value || DEFAULT_FILE_NAME;
83
- if (next !== target24.fileName) target24.fileName = next;
83
+ if (next !== target29.fileName) target29.fileName = next;
84
84
  return;
85
85
  }
86
86
  case "author-name": {
87
87
  const next = value || DEFAULT_AUTHOR_NAME;
88
- if (next !== target24.authorName) target24.authorName = next;
88
+ if (next !== target29.authorName) target29.authorName = next;
89
89
  return;
90
90
  }
91
91
  case "theme": {
92
92
  const next = normalizeThemeMode(value);
93
- if (next !== target24.theme) target24.theme = next;
93
+ if (next !== target29.theme) target29.theme = next;
94
94
  return;
95
95
  }
96
96
  case "show-toolbar":
97
- if (value !== "false" !== target24.showToolbar) target24.showToolbar = value !== "false";
97
+ if (value !== "false" !== target29.showToolbar) target29.showToolbar = value !== "false";
98
98
  return;
99
99
  case "show-formula-bar":
100
- if (value !== "false" !== target24.showFormulaBar) target24.showFormulaBar = value !== "false";
100
+ if (value !== "false" !== target29.showFormulaBar) target29.showFormulaBar = value !== "false";
101
101
  }
102
102
  }
103
103
  function reflectAttribute(element, name, value) {
@@ -365,7 +365,7 @@ function renderInfo(page) {
365
365
  paragraph(
366
366
  page,
367
367
  t(
368
- "Charts and sparklines are shown but not edited; pivot tables, macros and other unsupported parts are kept in the file but not shown."
368
+ "Charts, sparklines and worksheet-range PivotTables support editing. Advanced PivotTables, macros and other unsupported parts are preserved."
369
369
  ),
370
370
  "xve-backstage-muted"
371
371
  )
@@ -426,6 +426,8 @@ function renderInfo(page) {
426
426
  layout.append(left, right);
427
427
  content.replaceChildren(heading(page, t("Info")), layout);
428
428
  }
429
+
430
+ // src/xlsx/print-cell.ts
429
431
  var escapeHtml = (text3) => text3.replace(/[&<>"']/g, (ch) => `&#${ch.charCodeAt(0)};`);
430
432
  var edge = (view) => view ? `${view.style === "double" ? 3 : view.widthPx}px ${view.style} ${view.color}` : "none";
431
433
  function cellCss(view) {
@@ -455,55 +457,89 @@ function cellCss(view) {
455
457
  else if (fill && "pattern" in fill) parts.push(`background:${fill.fg}`);
456
458
  return parts.join(";");
457
459
  }
458
- function printRange(workbook, sheetIndex) {
460
+ function printPageHeaders(workbook, sheetIndex, layout, page, title, options) {
459
461
  const sheet = workbook.sheets[sheetIndex];
460
- if (!sheet) return void 0;
461
- if (sheet.pageSetup?.printArea) return sheet.pageSetup.printArea;
462
- const used = usedRange(sheet);
463
- if (!used) return void 0;
464
- const end = { ...used.end };
465
- for (const merge of sheet.merges)
466
- if (merge.start.row <= end.row && merge.start.col <= end.col && merge.start.row >= used.start.row && merge.start.col >= used.start.col) {
467
- end.row = Math.max(end.row, merge.end.row);
468
- end.col = Math.max(end.col, merge.end.col);
469
- }
470
- return { start: used.start, end };
471
- }
472
- function buildPrintHtml(workbook, sheetIndex, title) {
462
+ const setup = sheet.pageSetup ?? {};
463
+ const number = (setup.firstPageNumber ?? 1) + page - 1;
464
+ const text3 = pageHeaderFooter(setup, page, number);
465
+ const context = {
466
+ page: number,
467
+ pages: layout.pages.length,
468
+ sheet: sheet.name,
469
+ file: (options.fileName ?? title).split(/[\\/]/).at(-1),
470
+ ...options.date ? { date: options.date } : {},
471
+ ...options.locale ? { locale: options.locale } : {}
472
+ };
473
+ const left = (setup.alignWithMargins === false ? 0.7 : layout.margins.left) * 96;
474
+ const right = (setup.alignWithMargins === false ? 0.7 : layout.margins.right) * 96;
475
+ const size = 11 * 96 / 72 * (setup.scaleWithDoc === false ? 1 : layout.scale);
476
+ const band2 = (kind, value) => {
477
+ if (!value) return "";
478
+ const sections = renderHeaderFooterRuns(value, context).sections;
479
+ const runs = (section) => sections[section].map(({ text: text4, style }) => {
480
+ const css = [
481
+ style.font ? `font-family:${style.font.replace(/["\\;<>]/g, "")}` : "",
482
+ style.size ? `font-size:${style.size / 11 * size}px` : "",
483
+ style.color ? `color:${style.color}` : "",
484
+ `font-weight:${style.bold ? 700 : 400}`,
485
+ `font-style:${style.italic ? "italic" : "normal"}`,
486
+ `text-decoration:${[style.underline ? "underline" : "", style.strike ? "line-through" : ""].filter(Boolean).join(" ") || "none"}`
487
+ ].filter(Boolean).join(";");
488
+ return `<span style="${escapeHtml(css)}">${escapeHtml(text4)}</span>`;
489
+ }).join("");
490
+ return `<div class="xve-print-${kind}" style="position:absolute;${kind === "header" ? "top" : "bottom"}:${layout.margins[kind] * 96}px;left:${left}px;right:${right}px;font-size:${size}px;display:flex;line-height:1.2">${["left", "center", "right"].map((section) => `<span style="width:33.333%;white-space:pre-wrap;text-align:${section};overflow:hidden">${runs(section)}</span>`).join("")}</div>`;
491
+ };
492
+ return band2("header", text3.header) + band2("footer", text3.footer);
493
+ }
494
+
495
+ // src/xlsx/print-pages.ts
496
+ function pageTable(workbook, sheetIndex, page) {
473
497
  const sheet = workbook.sheets[sheetIndex];
474
- const range2 = printRange(workbook, sheetIndex);
475
- const head = `<!doctype html><html><head><meta charset="utf-8"><title>${escapeHtml(title)}</title><style>
476
- @page{margin:12mm}body{margin:0;font-family:Calibri,sans-serif}table{border-collapse:collapse;table-layout:fixed}
477
- td{overflow:hidden;padding:0 3px;box-sizing:border-box;line-height:1.2}</style></head><body>`;
478
- if (!sheet || !range2) return `${head}</body></html>`;
479
498
  const metrics = createGridMetrics(sheet, { zoom: 100 });
480
- const cols = [];
481
- for (let c = range2.start.col; c <= range2.end.col; c++) if (!metrics.isColHidden(c)) cols.push(c);
482
- const colgroup = cols.map((c) => `<col style="width:${metrics.colWidth(c)}px">`).join("");
483
- const width = cols.reduce((sum, c) => sum + metrics.colWidth(c), 0);
484
- const rows = [];
485
- for (let r = range2.start.row; r <= range2.end.row; r++) {
486
- if (metrics.isRowHidden(r)) continue;
487
- const cells = [];
488
- for (const c of cols) {
489
- const merge = mergeView(sheet, r, c);
490
- if (merge.hidden) continue;
491
- const view = cellView(workbook, sheetIndex, r, c);
492
- let span = "";
493
- if (merge.anchor && merge.range) {
494
- const colspan = cols.filter(
495
- (col) => col >= merge.range.start.col && col <= merge.range.end.col
496
- ).length;
497
- let rowspan = 0;
498
- for (let row2 = merge.range.start.row; row2 <= Math.min(merge.range.end.row, range2.end.row); row2++)
499
- if (!metrics.isRowHidden(row2)) rowspan++;
500
- span = `${colspan > 1 ? ` colspan="${colspan}"` : ""}${rowspan > 1 ? ` rowspan="${rowspan}"` : ""}`;
501
- }
502
- cells.push(`<td${span} style="${escapeHtml(cellCss(view))}">${escapeHtml(view.text)}</td>`);
503
- }
504
- rows.push(`<tr style="height:${metrics.rowHeight(r)}px">${cells.join("")}</tr>`);
505
- }
506
- return `${head}<table style="width:${width}px"><colgroup>${colgroup}</colgroup><tbody>${rows.join("")}</tbody></table></body></html>`;
499
+ const headings = !!sheet.printOptions?.headings;
500
+ const merges = createPrintMergeIndex(sheet.merges, page.rows, page.columns);
501
+ const columns = `${headings ? '<col style="width:24px">' : ""}${page.columns.map((col) => `<col style="width:${metrics.colWidth(col)}px">`).join("")}`;
502
+ const header = headings ? `<tr style="height:24px"><th></th>${page.columns.map((col) => `<th>${formatAddress({ row: 0, col }).replace(/\d+$/, "")}</th>`).join("")}</tr>` : "";
503
+ const rows = page.rows.map((row2) => {
504
+ const cells = page.columns.map((col) => {
505
+ const merge = merges.at(row2, col);
506
+ if (merge && (row2 !== merge.row || col !== merge.col)) return "";
507
+ const view = cellView(
508
+ workbook,
509
+ sheetIndex,
510
+ merge?.range.start.row ?? row2,
511
+ merge?.range.start.col ?? col,
512
+ void 0,
513
+ { merged: !!merge }
514
+ );
515
+ let css = cellCss(view);
516
+ if (sheet.printOptions?.gridLines) {
517
+ for (const side of ["top", "right", "bottom", "left"])
518
+ if (!view.borders[side]) css += `;border-${side}:1px solid #d9d9d9`;
519
+ }
520
+ const span = `${merge && merge.colspan > 1 ? ` colspan="${merge.colspan}"` : ""}${merge && merge.rowspan > 1 ? ` rowspan="${merge.rowspan}"` : ""}`;
521
+ return `<td${span} style="${escapeHtml(css)}">${escapeHtml(view.text)}</td>`;
522
+ }).join("");
523
+ return `<tr style="height:${metrics.rowHeight(row2)}px">${headings ? `<th>${row2 + 1}</th>` : ""}${cells}</tr>`;
524
+ }).join("");
525
+ return `<table style="width:${page.width + (headings ? 24 : 0)}px"><colgroup>${columns}</colgroup><tbody>${header}${rows}</tbody></table>`;
526
+ }
527
+ function buildPrintHtml(workbook, sheetIndex, title, options = {}) {
528
+ const headerOptions = { date: /* @__PURE__ */ new Date(), ...options };
529
+ const layout = paginateWorksheet(workbook, sheetIndex);
530
+ const sheet = workbook.sheets[sheetIndex];
531
+ const pages = layout.pages.map((page) => {
532
+ const headings = sheet.printOptions?.headings ? 24 : 0;
533
+ const left = sheet.printOptions?.horizontalCentered ? Math.max(0, (layout.contentWidth - (page.width + headings) * layout.scale) / 2) : 0;
534
+ const top = sheet.printOptions?.verticalCentered ? Math.max(0, (layout.contentHeight - (page.height + headings) * layout.scale) / 2) : 0;
535
+ return `<section class="xve-print-page" data-page="${page.number}" style="position:relative;width:${layout.paperWidth}px;height:${layout.paperHeight}px;padding:${layout.margins.top}in ${layout.margins.right}in ${layout.margins.bottom}in ${layout.margins.left}in">${printPageHeaders(workbook, sheetIndex, layout, page.number, title, headerOptions)}<div class="xve-print-content" style="width:${layout.contentWidth}px;height:${layout.contentHeight}px"><div style="position:absolute;left:${left}px;top:${top}px;transform:scale(${layout.scale});transform-origin:top left">${pageTable(workbook, sheetIndex, page)}</div></div></section>`;
536
+ }).join("");
537
+ return `<!doctype html><html><head><meta charset="utf-8"><title>${escapeHtml(title)}</title><style>
538
+ @page{size:${layout.paperWidth / 96}in ${layout.paperHeight / 96}in;margin:0}
539
+ body{margin:0;background:#e8eaed;font-family:Calibri,sans-serif}.xve-print-page{box-sizing:border-box;background:white;margin:16px auto;box-shadow:0 1px 5px #0003;overflow:hidden;break-after:page}.xve-print-content{position:relative;overflow:hidden}
540
+ table{border-collapse:collapse;table-layout:fixed}td{overflow:hidden;padding:0 3px;box-sizing:border-box;line-height:1.2}th{box-sizing:border-box;font-size:12px;font-weight:400;color:#444;border:1px solid #ccc;overflow:hidden}
541
+ @media print{body{background:white}.xve-print-page{margin:0;box-shadow:none}.xve-print-page:last-child{break-after:auto}}
542
+ </style></head><body>${pages}</body></html>`;
507
543
  }
508
544
  var PRINT_FRAME_TIMEOUT_MS = 6e4;
509
545
  var pendingFrames = /* @__PURE__ */ new WeakMap();
@@ -514,9 +550,9 @@ function printHtml(doc, html) {
514
550
  frame.tabIndex = -1;
515
551
  frame.style.cssText = "position:fixed;right:0;bottom:0;width:0;height:0;border:0;visibility:hidden";
516
552
  doc.body.append(frame);
517
- const target24 = frame.contentWindow;
553
+ const target29 = frame.contentWindow;
518
554
  const frameDoc = frame.contentDocument;
519
- if (!target24 || !frameDoc) {
555
+ if (!target29 || !frameDoc) {
520
556
  frame.remove();
521
557
  return;
522
558
  }
@@ -526,18 +562,18 @@ function printHtml(doc, html) {
526
562
  let safety;
527
563
  const cleanup = () => {
528
564
  if (safety !== void 0) clearTimeout(safety);
529
- target24.removeEventListener("afterprint", cleanup);
565
+ target29.removeEventListener("afterprint", cleanup);
530
566
  frame.remove();
531
567
  if (pendingFrames.get(doc) === cleanup) pendingFrames.delete(doc);
532
568
  };
533
569
  pendingFrames.set(doc, cleanup);
534
- target24.addEventListener("afterprint", cleanup);
570
+ target29.addEventListener("afterprint", cleanup);
535
571
  safety = setTimeout(cleanup, PRINT_FRAME_TIMEOUT_MS);
536
572
  setTimeout(() => {
537
573
  if (!frame.isConnected) return;
538
574
  try {
539
- target24.focus();
540
- target24.print();
575
+ target29.focus();
576
+ target29.print();
541
577
  } catch (error) {
542
578
  cleanup();
543
579
  console.error("xlsx-editor: printing failed", error);
@@ -647,7 +683,7 @@ function renderPrint(page) {
647
683
  paragraph(
648
684
  page,
649
685
  t(
650
- "Printing uses the browser print dialog and prints the active sheet as a table. Page breaks, headers, footers and scaling are approximate."
686
+ "Browser printing includes page setup, manual breaks, leading print titles and header/footer fields. Drawings and unsupported formatting are preserved but not rendered."
651
687
  ),
652
688
  "xve-backstage-muted"
653
689
  )
@@ -1169,10 +1205,10 @@ function listBox(ctx, label, onChange, onActivate) {
1169
1205
  box.setAttribute("role", "listbox");
1170
1206
  box.setAttribute("aria-label", ctx.t(label));
1171
1207
  box.tabIndex = 0;
1172
- let selected;
1208
+ let selected2;
1173
1209
  const options = () => [...box.querySelectorAll('[role="option"]')];
1174
1210
  const choose = (value, notify = true) => {
1175
- selected = value;
1211
+ selected2 = value;
1176
1212
  for (const option of options()) {
1177
1213
  const on = option.dataset.value === value;
1178
1214
  option.setAttribute("aria-selected", String(on));
@@ -1185,7 +1221,7 @@ function listBox(ctx, label, onChange, onActivate) {
1185
1221
  };
1186
1222
  box.addEventListener("keydown", (event) => {
1187
1223
  const list = options();
1188
- const index = list.findIndex((o) => o.dataset.value === selected);
1224
+ const index = list.findIndex((o) => o.dataset.value === selected2);
1189
1225
  const move = (to) => {
1190
1226
  const next = list[Math.max(0, Math.min(list.length - 1, to))];
1191
1227
  if (next?.dataset.value !== void 0) choose(next.dataset.value);
@@ -1194,7 +1230,7 @@ function listBox(ctx, label, onChange, onActivate) {
1194
1230
  else if (event.key === "ArrowUp") move(index - 1);
1195
1231
  else if (event.key === "Home") move(0);
1196
1232
  else if (event.key === "End") move(list.length - 1);
1197
- else if (event.key === "Enter" && selected !== void 0 && onActivate) onActivate(selected);
1233
+ else if (event.key === "Enter" && selected2 !== void 0 && onActivate) onActivate(selected2);
1198
1234
  else return;
1199
1235
  event.preventDefault();
1200
1236
  event.stopPropagation();
@@ -1214,10 +1250,10 @@ function listBox(ctx, label, onChange, onActivate) {
1214
1250
  return option;
1215
1251
  })
1216
1252
  );
1217
- if (selected !== void 0 && items2.some(([v]) => v === selected)) choose(selected, false);
1218
- else selected = void 0;
1253
+ if (selected2 !== void 0 && items2.some(([v]) => v === selected2)) choose(selected2, false);
1254
+ else selected2 = void 0;
1219
1255
  },
1220
- value: () => selected,
1256
+ value: () => selected2,
1221
1257
  select: (value) => choose(value)
1222
1258
  };
1223
1259
  }
@@ -1369,6 +1405,7 @@ function showDialog(ctx, spec, handle) {
1369
1405
  defineDialog(ctx.host.ownerDocument.defaultView?.customElements);
1370
1406
  ensureStyles(ctx);
1371
1407
  const doc = ctx.host.ownerDocument;
1408
+ const opener = ctx.root.activeElement ?? doc.activeElement;
1372
1409
  const dialog = doc.createElement("office-ui-dialog");
1373
1410
  dialog.setAttribute("heading", ctx.t(spec.heading));
1374
1411
  dialog.dataset.dialog = spec.name;
@@ -1390,6 +1427,9 @@ function showDialog(ctx, spec, handle) {
1390
1427
  done = true;
1391
1428
  dialog.removeAttribute("open");
1392
1429
  dialog.remove();
1430
+ if (ctx.grid()) ctx.grid()?.focus();
1431
+ else if (opener instanceof doc.defaultView.HTMLElement && opener.isConnected)
1432
+ opener.focus({ preventScroll: true });
1393
1433
  resolve(result);
1394
1434
  };
1395
1435
  let submitting = false;
@@ -1762,10 +1802,10 @@ function findShortcut(event, mac) {
1762
1802
  return SHORTCUTS.find((shortcut) => shortcut.keys.some((spec) => matchesKeys(event, spec, mac)));
1763
1803
  }
1764
1804
  function inTextField(event) {
1765
- const target24 = event.composedPath()[0];
1766
- if (!(target24 instanceof Element)) return false;
1767
- if (target24.closest(".xve-grid-host")) return false;
1768
- return target24.matches(
1805
+ const target29 = event.composedPath()[0];
1806
+ if (!(target29 instanceof Element)) return false;
1807
+ if (target29.closest(".xve-grid-host")) return false;
1808
+ return target29.matches(
1769
1809
  'input:not([type="checkbox"]):not([type="radio"]):not([type="range"]), textarea, select, [contenteditable=""], [contenteditable="true"]'
1770
1810
  );
1771
1811
  }
@@ -1935,11 +1975,11 @@ function alignmentTab(init) {
1935
1975
  const alignment = patch();
1936
1976
  return Object.keys(alignment).length ? { alignment } : {};
1937
1977
  },
1938
- apply: (target24) => {
1978
+ apply: (target29) => {
1939
1979
  if (!changed.has("merge") || merge.input.checked === merged) return;
1940
- for (const range2 of target24.ranges)
1941
- if (merge.input.checked) target24.session.merge(target24.sheet, range2, "merge");
1942
- else target24.session.unmerge(target24.sheet, range2);
1980
+ for (const range2 of target29.ranges)
1981
+ if (merge.input.checked) target29.session.merge(target29.sheet, range2, "merge");
1982
+ else target29.session.unmerge(target29.sheet, range2);
1943
1983
  },
1944
1984
  focus: () => horizontal.focus()
1945
1985
  };
@@ -1981,11 +2021,14 @@ function mountPopover(anchor, pop, expanded = anchor, onClose) {
1981
2021
  doc.addEventListener("pointerdown", outside, true);
1982
2022
  doc.addEventListener("keydown", escape, true);
1983
2023
  closeOpen = () => {
2024
+ const active2 = root instanceof ShadowRoot ? root.activeElement : doc.activeElement;
2025
+ const restoreFocus = active2 !== null && pop.contains(active2);
1984
2026
  doc.removeEventListener("pointerdown", outside, true);
1985
2027
  doc.removeEventListener("keydown", escape, true);
1986
2028
  pop.remove();
1987
2029
  expanded.setAttribute("aria-expanded", "false");
1988
2030
  closeOpen = void 0;
2031
+ if (restoreFocus && anchor.isConnected) anchor.focus({ preventScroll: true });
1989
2032
  };
1990
2033
  return true;
1991
2034
  }
@@ -2020,12 +2063,12 @@ function openMenu(anchor, entries, label = "") {
2020
2063
  item.setAttribute("role", entry.checked === void 0 ? "menuitem" : "menuitemcheckbox");
2021
2064
  if (entry.checked !== void 0) item.setAttribute("aria-checked", String(entry.checked));
2022
2065
  item.disabled = entry.disabled ?? false;
2023
- const icon7 = doc.createElement("span");
2024
- icon7.className = "ribbon-menu-icon";
2025
- if (entry.icon) icon7.append(ribbonIcon(doc, entry.icon, 16));
2066
+ const icon9 = doc.createElement("span");
2067
+ icon9.className = "ribbon-menu-icon";
2068
+ if (entry.icon) icon9.append(ribbonIcon(doc, entry.icon, 16));
2026
2069
  const text3 = doc.createElement("span");
2027
2070
  text3.textContent = entry.label;
2028
- item.append(icon7, text3);
2071
+ item.append(icon9, text3);
2029
2072
  if (entry.shortcut) {
2030
2073
  const keys = doc.createElement("span");
2031
2074
  keys.className = "ribbon-menu-shortcut";
@@ -2065,9 +2108,9 @@ function openList(anchor, items2, current, choose, options = {}) {
2065
2108
  }
2066
2109
  arrowNavigation(pop, '[role="option"]');
2067
2110
  if (!mountPopover(anchor, pop, options.expanded ?? anchor)) return;
2068
- const selected = pop.querySelector('[aria-selected="true"]') ?? pop.querySelector('[role="option"]');
2069
- selected?.scrollIntoView?.({ block: "center" });
2070
- selected?.focus({ preventScroll: true });
2111
+ const selected2 = pop.querySelector('[aria-selected="true"]') ?? pop.querySelector('[role="option"]');
2112
+ selected2?.scrollIntoView?.({ block: "center" });
2113
+ selected2?.focus({ preventScroll: true });
2071
2114
  }
2072
2115
 
2073
2116
  // src/xlsx/ribbon/color-grid.ts
@@ -3044,9 +3087,9 @@ function openGoTo(ctx) {
3044
3087
  buttons: [special],
3045
3088
  opened: () => reference.focus(),
3046
3089
  submit: () => {
3047
- const target24 = resolveReference(ctx, reference.value);
3048
- if (!target24) return invalid(ctx, reference, "Reference is not valid.");
3049
- selectOn(ctx, target24.sheet, target24.range);
3090
+ const target29 = resolveReference(ctx, reference.value);
3091
+ if (!target29) return invalid(ctx, reference, "Reference is not valid.");
3092
+ selectOn(ctx, target29.sheet, target29.range);
3050
3093
  return reference.value.trim();
3051
3094
  }
3052
3095
  },
@@ -3828,7 +3871,14 @@ function menuEntries(scope, items2) {
3828
3871
  ...command.shortcut ? { shortcut: command.shortcut } : {},
3829
3872
  ...checked === void 0 ? {} : { checked },
3830
3873
  disabled: !ctx.commands.isEnabled(command.id),
3831
- run: () => void ctx.commands.run(command.id, item.arg)
3874
+ run: () => {
3875
+ const origin = ctx.root.activeElement;
3876
+ void Promise.resolve(ctx.commands.run(command.id, item.arg)).then(() => {
3877
+ const active2 = ctx.root.activeElement;
3878
+ if (active2 === origin && active2?.closest('[part~="ribbon"]') || !active2 && ctx.host.ownerDocument.activeElement === ctx.host.ownerDocument.body)
3879
+ ctx.grid()?.focus();
3880
+ });
3881
+ }
3832
3882
  });
3833
3883
  }
3834
3884
  while (entries.length && "separator" in entries[entries.length - 1]) entries.pop();
@@ -4098,6 +4148,8 @@ var SUPPORTED_FEATURES = [
4098
4148
  "Conditional formatting display",
4099
4149
  "Tables",
4100
4150
  "Charts (display and basic editing)",
4151
+ "Sparklines (create, format and clear)",
4152
+ "Worksheet-range PivotTables (one row field, optional column field and one value field)",
4101
4153
  "Comments and notes",
4102
4154
  "Hyperlinks",
4103
4155
  "Data validation",
@@ -4105,8 +4157,7 @@ var SUPPORTED_FEATURES = [
4105
4157
  "Freeze panes"
4106
4158
  ];
4107
4159
  var UNSUPPORTED_FEATURES = [
4108
- "Pivot tables (kept in the file but not shown)",
4109
- "Creating or editing sparklines (existing ones are shown)",
4160
+ "Advanced PivotTable layouts, grouping and external data sources (preserved)",
4110
4161
  "Show Formulas",
4111
4162
  "Manual calculation",
4112
4163
  "Outline (grouping) for columns",
@@ -4275,9 +4326,9 @@ function openNameManager(ctx) {
4275
4326
  const newButton = button(ctx, "New...");
4276
4327
  const editButton = button(ctx, "Edit...");
4277
4328
  const deleteButton = button(ctx, "Delete");
4278
- let selected;
4329
+ let selected2;
4279
4330
  const sync = () => {
4280
- const editable = !!selected && !ctx.readOnly();
4331
+ const editable = !!selected2 && !ctx.readOnly();
4281
4332
  editButton.disabled = !editable;
4282
4333
  deleteButton.disabled = !editable;
4283
4334
  newButton.disabled = ctx.readOnly();
@@ -4294,7 +4345,7 @@ function openNameManager(ctx) {
4294
4345
  }
4295
4346
  const body = table.createTBody();
4296
4347
  const names2 = visibleNames(workbook?.definedNames ?? []);
4297
- if (selected && !names2.includes(selected)) selected = void 0;
4348
+ if (selected2 && !names2.includes(selected2)) selected2 = void 0;
4298
4349
  for (const name of names2) {
4299
4350
  const value = nameValue(ctx, name);
4300
4351
  const kind = filter.value;
@@ -4305,12 +4356,12 @@ function openNameManager(ctx) {
4305
4356
  const tr = body.insertRow();
4306
4357
  tr.tabIndex = 0;
4307
4358
  tr.dataset.name = name.name;
4308
- if (name === selected) tr.setAttribute("aria-selected", "true");
4359
+ if (name === selected2) tr.setAttribute("aria-selected", "true");
4309
4360
  const scope = name.localSheet === void 0 ? ctx.t("Workbook") : workbook?.sheets[name.localSheet]?.name ?? "";
4310
4361
  for (const text3 of [name.name, value.text, `=${name.formula}`, scope, name.comment ?? ""])
4311
4362
  tr.insertCell().textContent = text3;
4312
4363
  const pick = () => {
4313
- selected = name;
4364
+ selected2 = name;
4314
4365
  for (const other of body.rows) other.removeAttribute("aria-selected");
4315
4366
  tr.setAttribute("aria-selected", "true");
4316
4367
  sync();
@@ -4334,17 +4385,17 @@ function openNameManager(ctx) {
4334
4385
  render3();
4335
4386
  });
4336
4387
  editButton.addEventListener("click", async () => {
4337
- if (!selected) return;
4338
- const props2 = { name: selected.name };
4339
- if (selected.localSheet !== void 0) props2.localSheet = selected.localSheet;
4388
+ if (!selected2) return;
4389
+ const props2 = { name: selected2.name };
4390
+ if (selected2.localSheet !== void 0) props2.localSheet = selected2.localSheet;
4340
4391
  await ctx.dialogs.open("define-name", props2);
4341
4392
  render3();
4342
4393
  });
4343
4394
  deleteButton.addEventListener("click", () => {
4344
4395
  const session = ctx.session();
4345
- if (!selected || !session || ctx.readOnly()) return;
4346
- session.deleteDefinedName(selected.name, selected.localSheet);
4347
- selected = void 0;
4396
+ if (!selected2 || !session || ctx.readOnly()) return;
4397
+ session.deleteDefinedName(selected2.name, selected2.localSheet);
4398
+ selected2 = void 0;
4348
4399
  render3();
4349
4400
  });
4350
4401
  render3();
@@ -5160,7 +5211,7 @@ function cfManagerDialog(ctx) {
5160
5211
  const t = target(ctx);
5161
5212
  if (!t) return Promise.resolve(void 0);
5162
5213
  let entries = stageRules(t.ws.conditionalFormats);
5163
- let selected = entries.length ? 0 : -1;
5214
+ let selected2 = entries.length ? 0 : -1;
5164
5215
  const scope = select(
5165
5216
  ctx,
5166
5217
  [
@@ -5191,15 +5242,15 @@ function cfManagerDialog(ctx) {
5191
5242
  const entry = entries[i];
5192
5243
  const tr = el(ctx, "tr");
5193
5244
  tr.dataset.index = String(i);
5194
- tr.setAttribute("aria-selected", String(i === selected));
5245
+ tr.setAttribute("aria-selected", String(i === selected2));
5195
5246
  tr.addEventListener("click", (event) => {
5196
- if (selected === i || event.target.tagName === "INPUT") {
5197
- selected = i;
5247
+ if (selected2 === i || event.target.tagName === "INPUT") {
5248
+ selected2 = i;
5198
5249
  for (const other of table.querySelectorAll("tr[data-index]"))
5199
5250
  other.setAttribute("aria-selected", String(other === tr));
5200
5251
  return;
5201
5252
  }
5202
- selected = i;
5253
+ selected2 = i;
5203
5254
  render3();
5204
5255
  });
5205
5256
  const desc = el(ctx, "td");
@@ -5250,11 +5301,11 @@ function cfManagerDialog(ctx) {
5250
5301
  };
5251
5302
  const move = (delta) => {
5252
5303
  if (!commitRanges()) return;
5253
- const to = selected + delta;
5254
- if (selected < 0 || to < 0 || to >= entries.length) return;
5255
- const [entry] = entries.splice(selected, 1);
5304
+ const to = selected2 + delta;
5305
+ if (selected2 < 0 || to < 0 || to >= entries.length) return;
5306
+ const [entry] = entries.splice(selected2, 1);
5256
5307
  if (entry) entries.splice(to, 0, entry);
5257
- selected = to;
5308
+ selected2 = to;
5258
5309
  render3();
5259
5310
  };
5260
5311
  const newRule = button(ctx, "New Rule...");
@@ -5268,28 +5319,28 @@ function cfManagerDialog(ctx) {
5268
5319
  const result = await editRuleDialog(ctx);
5269
5320
  if (!result) return;
5270
5321
  entries.unshift(result);
5271
- selected = 0;
5322
+ selected2 = 0;
5272
5323
  render3();
5273
5324
  });
5274
5325
  editRule.addEventListener("click", async () => {
5275
5326
  if (!commitRanges()) return;
5276
- const entry = entries[selected];
5327
+ const entry = entries[selected2];
5277
5328
  if (!entry) return;
5278
5329
  const result = await editRuleDialog(ctx, entry);
5279
- if (result) entries[selected] = result;
5330
+ if (result) entries[selected2] = result;
5280
5331
  render3();
5281
5332
  });
5282
5333
  deleteRule.addEventListener("click", () => {
5283
- if (selected < 0) return;
5284
- entries.splice(selected, 1);
5285
- selected = Math.min(selected, entries.length - 1);
5334
+ if (selected2 < 0) return;
5335
+ entries.splice(selected2, 1);
5336
+ selected2 = Math.min(selected2, entries.length - 1);
5286
5337
  render3();
5287
5338
  });
5288
5339
  duplicate.addEventListener("click", () => {
5289
5340
  if (!commitRanges()) return;
5290
- const entry = entries[selected];
5341
+ const entry = entries[selected2];
5291
5342
  if (!entry) return;
5292
- entries.splice(selected, 0, structuredClone(entry));
5343
+ entries.splice(selected2, 0, structuredClone(entry));
5293
5344
  render3();
5294
5345
  });
5295
5346
  up.addEventListener("click", () => move(-1));
@@ -5297,11 +5348,11 @@ function cfManagerDialog(ctx) {
5297
5348
  table.addEventListener("keydown", (event) => {
5298
5349
  if (event.target !== table) return;
5299
5350
  const list = visible();
5300
- const at = list.indexOf(selected);
5351
+ const at = list.indexOf(selected2);
5301
5352
  const next = event.key === "ArrowDown" ? list[at + 1] : event.key === "ArrowUp" ? list[at - 1] : void 0;
5302
5353
  if (next === void 0) return;
5303
5354
  event.preventDefault();
5304
- selected = next;
5355
+ selected2 = next;
5305
5356
  render3();
5306
5357
  });
5307
5358
  scope.addEventListener("change", render3);
@@ -5852,7 +5903,7 @@ function sortDialog(ctx) {
5852
5903
  const header = checkbox(ctx, "My data has headers", guessHeader(t.ws, region));
5853
5904
  const levels = [];
5854
5905
  const list = el(ctx, "div", "xve-sort-levels");
5855
- let selected = 0;
5906
+ let selected2 = 0;
5856
5907
  const columnOptions = () => {
5857
5908
  const out = [];
5858
5909
  for (let col = region.start.col; col <= region.end.col; col++) {
@@ -5865,7 +5916,7 @@ function sortDialog(ctx) {
5865
5916
  const render3 = () => {
5866
5917
  list.replaceChildren(
5867
5918
  ...levels.map((level, i) => {
5868
- level.element.setAttribute("aria-selected", String(i === selected));
5919
+ level.element.setAttribute("aria-selected", String(i === selected2));
5869
5920
  const caption = level.element.querySelector(".xve-sort-caption");
5870
5921
  if (caption) caption.textContent = ctx.t(i === 0 ? "Sort by" : "Then by");
5871
5922
  return level.element;
@@ -5890,11 +5941,11 @@ function sortDialog(ctx) {
5890
5941
  const element = row(ctx, caption, column, on, order);
5891
5942
  const level = { element, column, order };
5892
5943
  element.addEventListener("focusin", () => {
5893
- selected = levels.indexOf(level);
5944
+ selected2 = levels.indexOf(level);
5894
5945
  render3();
5895
5946
  });
5896
5947
  levels.splice(at, 0, level);
5897
- selected = at;
5948
+ selected2 = at;
5898
5949
  render3();
5899
5950
  };
5900
5951
  addLevel(
@@ -5922,20 +5973,20 @@ function sortDialog(ctx) {
5922
5973
  });
5923
5974
  remove.addEventListener("click", () => {
5924
5975
  if (levels.length <= 1) return;
5925
- levels.splice(selected, 1);
5926
- selected = Math.max(0, Math.min(selected, levels.length - 1));
5976
+ levels.splice(selected2, 1);
5977
+ selected2 = Math.max(0, Math.min(selected2, levels.length - 1));
5927
5978
  render3();
5928
5979
  });
5929
5980
  copy.addEventListener("click", () => {
5930
- const level = levels[selected];
5931
- if (level) addLevel(Number(level.column.value), level.order.value === "desc", selected + 1);
5981
+ const level = levels[selected2];
5982
+ if (level) addLevel(Number(level.column.value), level.order.value === "desc", selected2 + 1);
5932
5983
  });
5933
5984
  const move = (delta) => {
5934
- const to = selected + delta;
5985
+ const to = selected2 + delta;
5935
5986
  if (to < 0 || to >= levels.length) return;
5936
- const [level] = levels.splice(selected, 1);
5987
+ const [level] = levels.splice(selected2, 1);
5937
5988
  if (level) levels.splice(to, 0, level);
5938
- selected = to;
5989
+ selected2 = to;
5939
5990
  render3();
5940
5991
  };
5941
5992
  up.addEventListener("click", () => move(-1));
@@ -6730,6 +6781,115 @@ function openMoveCopySheet(ctx) {
6730
6781
  }
6731
6782
  });
6732
6783
  }
6784
+
6785
+ // src/xlsx/dialogs/page-header.ts
6786
+ function headerTab(ctx, setup) {
6787
+ const changes = /* @__PURE__ */ new Map();
6788
+ const fields = [
6789
+ ["header", "Header:"],
6790
+ ["footer", "Footer:"],
6791
+ ["firstHeader", "First Page Header:"],
6792
+ ["firstFooter", "First Page Footer:"],
6793
+ ["evenHeader", "Even Page Header:"],
6794
+ ["evenFooter", "Even Page Footer:"]
6795
+ ];
6796
+ let active2;
6797
+ const inputs = fields.map(([key, label]) => {
6798
+ const original = setup[key] ?? "";
6799
+ const shown2 = original.startsWith("&C") && !/&[LR]/.test(original.slice(2)) ? original.slice(2) : original;
6800
+ const input = textArea(ctx, shown2, 2);
6801
+ const read = () => input.value ? /&[LCR]/.test(input.value) ? input.value : `&C${input.value}` : void 0;
6802
+ input.addEventListener("input", () => changes.set(key, read));
6803
+ input.addEventListener("change", () => changes.set(key, read));
6804
+ input.addEventListener("focus", () => {
6805
+ active2 = input;
6806
+ });
6807
+ return { key, input, field: field(ctx, label, input) };
6808
+ });
6809
+ active2 = inputs[0].input;
6810
+ const flags = [
6811
+ ["differentFirst", "Different first page", false],
6812
+ ["differentOddEven", "Different odd and even pages", false],
6813
+ ["scaleWithDoc", "Scale header and footer with document", true],
6814
+ ["alignWithMargins", "Align header and footer with margins", true]
6815
+ ];
6816
+ const checks = flags.map(([key, label, fallback]) => {
6817
+ const check = checkbox(ctx, label, setup[key] ?? fallback);
6818
+ check.input.addEventListener("change", () => {
6819
+ changes.set(key, () => check.input.checked);
6820
+ update();
6821
+ });
6822
+ return { key, ...check };
6823
+ });
6824
+ const update = () => {
6825
+ for (const input of inputs)
6826
+ if (input.key.startsWith("first") || input.key.startsWith("even"))
6827
+ input.input.disabled = !checks.find(
6828
+ (check) => check.key === (input.key.startsWith("first") ? "differentFirst" : "differentOddEven")
6829
+ ).input.checked;
6830
+ };
6831
+ update();
6832
+ const insert = select(
6833
+ ctx,
6834
+ [
6835
+ ["", "Insert Field"],
6836
+ ["&P", "Page Number"],
6837
+ ["&N", "Total Pages"],
6838
+ ["&A", "Sheet Name"],
6839
+ ["&F", "File Name"],
6840
+ ["&D", "Date"],
6841
+ ["&T", "Time"]
6842
+ ],
6843
+ ""
6844
+ );
6845
+ const insertCode = (control, wrap = false) => {
6846
+ if (!control.value || active2.disabled) return;
6847
+ const start = active2.selectionStart;
6848
+ const selected2 = wrap ? active2.value.slice(start, active2.selectionEnd) : "";
6849
+ active2.setRangeText(
6850
+ control.value + selected2 + (selected2 ? control.value : ""),
6851
+ start,
6852
+ active2.selectionEnd,
6853
+ "end"
6854
+ );
6855
+ active2.dispatchEvent(new ctx.host.ownerDocument.defaultView.Event("input", { bubbles: true }));
6856
+ control.value = "";
6857
+ active2.focus();
6858
+ };
6859
+ insert.addEventListener("change", () => insertCode(insert));
6860
+ const formatting = select(
6861
+ ctx,
6862
+ [
6863
+ ["", "Insert Formatting"],
6864
+ ["&B", "Bold"],
6865
+ ["&I", "Italic"],
6866
+ ["&U", "Underline"],
6867
+ ["&S", "Strikethrough"]
6868
+ ],
6869
+ ""
6870
+ );
6871
+ formatting.addEventListener("change", () => insertCode(formatting, true));
6872
+ return {
6873
+ panel: panel(
6874
+ ctx,
6875
+ row(ctx, field(ctx, "Insert Field", insert)),
6876
+ row(ctx, field(ctx, "Insert Formatting", formatting)),
6877
+ text(
6878
+ ctx,
6879
+ 'Formatting: &B bold, &I italic, &U underline, &S strike, &18 font size, &KFF0000 RGB color, &"Arial,Regular" font.'
6880
+ ),
6881
+ ...checks.map((check) => check.wrapper),
6882
+ text(
6883
+ ctx,
6884
+ "Use &L, &C and &R for sections. Fields: &P page, &N total pages, &A sheet, &F file, &D date, &T time. Use && for an ampersand. Unsupported formatting codes are preserved."
6885
+ ),
6886
+ ...inputs.map((input) => input.field)
6887
+ ),
6888
+ read: () => Object.fromEntries([...changes].map(([key, read]) => [key, read()]))
6889
+ };
6890
+ }
6891
+
6892
+ // src/xlsx/dialogs/page-setup-tabs.ts
6733
6893
  var DEFAULT_MARGINS = {
6734
6894
  top: 0.75,
6735
6895
  bottom: 0.75,
@@ -6738,8 +6898,13 @@ var DEFAULT_MARGINS = {
6738
6898
  header: 0.3,
6739
6899
  footer: 0.3
6740
6900
  };
6741
- var plainHeader = (value) => (value ?? "").replace(/&[LCR]/g, "");
6742
6901
  function pageTab(ctx, setup) {
6902
+ const firstNumber = numberInput(ctx, setup.firstPageNumber ?? 1, 0, 32767);
6903
+ const useFirstNumber = checkbox(
6904
+ ctx,
6905
+ "Use first page number",
6906
+ setup.firstPageNumber !== void 0
6907
+ );
6743
6908
  const orientation = radios(
6744
6909
  ctx,
6745
6910
  "Orientation",
@@ -6778,13 +6943,18 @@ function pageTab(ctx, setup) {
6778
6943
  field(ctx, "Pages wide", wide),
6779
6944
  field(ctx, "Pages tall", tall)
6780
6945
  ),
6781
- field(ctx, "Paper size", paper)
6946
+ field(ctx, "Paper size", paper),
6947
+ useFirstNumber.wrapper,
6948
+ field(ctx, "First page number", firstNumber)
6782
6949
  ),
6783
6950
  read() {
6784
6951
  const out = {
6952
+ firstPageNumber: useFirstNumber.input.checked ? Number(firstNumber.value) : void 0,
6785
6953
  orientation: orientation.get(),
6786
6954
  paperSize: Number(paper.value)
6787
6955
  };
6956
+ if (useFirstNumber.input.checked && (!Number.isInteger(out.firstPageNumber) || out.firstPageNumber < 0 || out.firstPageNumber > 32767))
6957
+ return "Enter a first page number between 0 and 32767.";
6788
6958
  if (scaling.get() === "fit") {
6789
6959
  const w = Number(wide.value);
6790
6960
  const h2 = Number(tall.value);
@@ -6845,26 +7015,33 @@ function marginsTab(ctx, setup, ws) {
6845
7015
  }
6846
7016
  };
6847
7017
  }
6848
- function headerTab(ctx, setup) {
6849
- const header = textInput(ctx, plainHeader(setup.header));
6850
- const footer = textInput(ctx, plainHeader(setup.footer));
6851
- return {
6852
- panel: panel(
6853
- ctx,
6854
- field(ctx, "Header:", header),
6855
- field(ctx, "Footer:", footer),
6856
- text(
6857
- ctx,
6858
- "The text is centered; left and right sections, fields and fonts are not supported yet."
6859
- )
6860
- ),
6861
- read: () => ({
6862
- header: header.value ? `&C${header.value}` : void 0,
6863
- footer: footer.value ? `&C${footer.value}` : void 0
6864
- })
6865
- };
6866
- }
6867
7018
  function sheetTab(ctx, setup, ws) {
7019
+ const existingTitles = printTitles(ctx.workbook(), ctx.activeSheet());
7020
+ const repeatRows = textInput(
7021
+ ctx,
7022
+ existingTitles.rows ? formatPrintTitleSpan(existingTitles.rows, "row") : ""
7023
+ );
7024
+ const repeatColumns = textInput(
7025
+ ctx,
7026
+ existingTitles.columns ? formatPrintTitleSpan(existingTitles.columns, "col") : ""
7027
+ );
7028
+ let titlesChanged = false;
7029
+ for (const input of [repeatRows, repeatColumns]) {
7030
+ input.addEventListener("input", () => {
7031
+ titlesChanged = true;
7032
+ });
7033
+ input.addEventListener("change", () => {
7034
+ titlesChanged = true;
7035
+ });
7036
+ }
7037
+ const order = select(
7038
+ ctx,
7039
+ [
7040
+ ["downThenOver", "Down, then over"],
7041
+ ["overThenDown", "Over, then down"]
7042
+ ],
7043
+ setup.pageOrder ?? "downThenOver"
7044
+ );
6868
7045
  const area = textInput(ctx, setup.printArea ? formatRange(setup.printArea) : "");
6869
7046
  const gridlines = checkbox(ctx, "Gridlines", !!ws.printOptions?.gridLines);
6870
7047
  const headings = checkbox(ctx, "Row and column headings", !!ws.printOptions?.headings);
@@ -6872,16 +7049,40 @@ function sheetTab(ctx, setup, ws) {
6872
7049
  panel: panel(
6873
7050
  ctx,
6874
7051
  field(ctx, "Print area", area),
7052
+ field(ctx, "Rows to repeat at top", repeatRows),
7053
+ field(ctx, "Columns to repeat at left", repeatColumns),
7054
+ ...existingTitles.unsupported ? [
7055
+ text(
7056
+ ctx,
7057
+ "Existing print titles are unsupported. Changing a title range replaces them; leaving the fields unchanged preserves them."
7058
+ )
7059
+ ] : [],
7060
+ field(ctx, "Page order", order),
6875
7061
  fieldset(ctx, "Print", gridlines.wrapper, headings.wrapper)
6876
7062
  ),
6877
7063
  gridlines: () => gridlines.input.checked,
7064
+ titles: () => {
7065
+ if (!titlesChanged) return void 0;
7066
+ try {
7067
+ return {
7068
+ rows: parsePrintTitleSpan(repeatRows.value, "row"),
7069
+ columns: parsePrintTitleSpan(repeatColumns.value, "col")
7070
+ };
7071
+ } catch {
7072
+ return "Print titles must be whole rows or whole columns.";
7073
+ }
7074
+ },
6878
7075
  headings: () => headings.input.checked,
6879
7076
  read() {
6880
7077
  const value = area.value.trim().replace(/^=/, "").replace(/^.*!/, "").replace(/\$/g, "");
6881
- if (!value) return { printArea: void 0 };
7078
+ if (!value)
7079
+ return {
7080
+ printArea: void 0,
7081
+ pageOrder: order.value
7082
+ };
6882
7083
  const range2 = parseRange(value);
6883
7084
  if (!range2) return "The reference is not valid.";
6884
- return { printArea: range2 };
7085
+ return { printArea: range2, pageOrder: order.value };
6885
7086
  }
6886
7087
  };
6887
7088
  }
@@ -6927,7 +7128,14 @@ function openPageSetup(ctx, props2 = {}) {
6927
7128
  }
6928
7129
  Object.assign(patch, result);
6929
7130
  }
7131
+ const titles = sheet.titles();
7132
+ if (typeof titles === "string") {
7133
+ view.show("sheet");
7134
+ ctx.toast(ctx.t(titles), "warning");
7135
+ return void 0;
7136
+ }
6930
7137
  t.session.batch("Page Setup", () => {
7138
+ if (titles) t.session.setPrintTitles(t.sheet, titles);
6931
7139
  t.session.setPageSetup(t.sheet, patch);
6932
7140
  const named = t.workbook.definedNames.some(
6933
7141
  (n) => n.name === "_xlnm.Print_Area" && n.localSheet === t.sheet
@@ -7726,11 +7934,446 @@ function openZoom(ctx) {
7726
7934
  }
7727
7935
  });
7728
7936
  }
7937
+ var TYPES3 = [
7938
+ ["line", "Line"],
7939
+ ["column", "Column"],
7940
+ ["stacked", "Win/Loss"]
7941
+ ];
7942
+ function openCreateSparklines(ctx, type = "line") {
7943
+ const t = target(ctx);
7944
+ if (!t) return Promise.resolve(void 0);
7945
+ const data = textInput(ctx);
7946
+ const locations = textInput(ctx, formatRange(t.range));
7947
+ const kind = select(ctx, TYPES3, type);
7948
+ const dates = textInput(ctx);
7949
+ return showDialog(ctx, {
7950
+ name: "create-sparklines",
7951
+ heading: "Create Sparklines",
7952
+ body: [
7953
+ field(ctx, "Data Range:", data),
7954
+ field(ctx, "Location Range:", locations),
7955
+ field(ctx, "Sparkline Type:", kind),
7956
+ field(ctx, "Date Range (optional):", dates)
7957
+ ],
7958
+ opened: () => data.focus(),
7959
+ submit: () => {
7960
+ const range2 = parseRange(locations.value.trim().replace(/^=/, "").replaceAll("$", ""));
7961
+ if (!range2) throw new Error("The reference is not valid.");
7962
+ t.session.batch("Create sparklines", () => {
7963
+ t.session.createSparklineGroup(t.sheet, data.value, range2, {
7964
+ type: kind.value
7965
+ });
7966
+ if (dates.value.trim()) t.session.setSparklineDateRange(t.sheet, [range2], dates.value);
7967
+ });
7968
+ ctx.selection.set({ ranges: [range2], active: range2.start, anchor: range2.start });
7969
+ return true;
7970
+ }
7971
+ });
7972
+ }
7973
+ function openSparklineSettings(ctx) {
7974
+ const t = target(ctx);
7975
+ const groups = t ? selectedSparklineGroups(t.ws, t.ranges) : [];
7976
+ const group = groups[0];
7977
+ if (!t || !group) return Promise.resolve(void 0);
7978
+ const dates = textInput(ctx, group.dateAxis ? group.dateFormula ?? "" : "");
7979
+ if (groups.some(
7980
+ (entry) => entry.dateAxis !== group.dateAxis || entry.dateFormula !== group.dateFormula
7981
+ )) {
7982
+ dates.value = "";
7983
+ dates.placeholder = ctx.t("Mixed");
7984
+ }
7985
+ let datesChanged = false;
7986
+ dates.addEventListener("input", () => {
7987
+ datesChanged = true;
7988
+ });
7989
+ dates.addEventListener("change", () => {
7990
+ datesChanged = true;
7991
+ });
7992
+ const changes = /* @__PURE__ */ new Map();
7993
+ const track = (input, key, read) => {
7994
+ const changed = () => {
7995
+ if (input.dataset.mixed && input.value === "") changes.delete(key);
7996
+ else changes.set(key, read);
7997
+ };
7998
+ input.addEventListener("input", changed);
7999
+ input.addEventListener("change", changed);
8000
+ };
8001
+ const mixed = (input, key) => {
8002
+ if (!groups.some((entry) => entry[key] !== group[key])) return;
8003
+ input.dataset.mixed = "true";
8004
+ if (input instanceof ctx.host.ownerDocument.defaultView.HTMLSelectElement) {
8005
+ const option = ctx.host.ownerDocument.createElement("option");
8006
+ option.value = "";
8007
+ option.textContent = ctx.t("Mixed");
8008
+ input.prepend(option);
8009
+ input.value = "";
8010
+ } else if (input.type === "checkbox") {
8011
+ input.indeterminate = true;
8012
+ input.checked = false;
8013
+ } else {
8014
+ input.value = "";
8015
+ input.placeholder = ctx.t("Mixed");
8016
+ }
8017
+ };
8018
+ const kind = select(ctx, TYPES3, group.type);
8019
+ const width = numberInput(ctx, group.lineWeight, 0, 1584, 0.25);
8020
+ const empty = select(
8021
+ ctx,
8022
+ [
8023
+ ["gap", "Gaps"],
8024
+ ["zero", "Zero"],
8025
+ ["span", "Connect data points"]
8026
+ ],
8027
+ group.displayEmptyCellsAs
8028
+ );
8029
+ const markers = [
8030
+ ["markers", "Markers"],
8031
+ ["high", "High Point"],
8032
+ ["low", "Low Point"],
8033
+ ["first", "First Point"],
8034
+ ["last", "Last Point"],
8035
+ ["negative", "Negative Points"]
8036
+ ];
8037
+ const checks = markers.map(([key, label]) => ({ key, ...checkbox(ctx, label, group[key]) }));
8038
+ const hidden = checkbox(ctx, "Show data in hidden rows and columns", group.displayHidden);
8039
+ const axis = checkbox(ctx, "Show horizontal axis", group.displayXAxis);
8040
+ const rtl = checkbox(ctx, "Plot right to left", group.rightToLeft);
8041
+ const scales = [
8042
+ ["individual", "Individual"],
8043
+ ["group", "Same for all sparklines"],
8044
+ ["custom", "Custom"]
8045
+ ];
8046
+ const minType = select(ctx, scales, group.minAxisType);
8047
+ const maxType = select(ctx, scales, group.maxAxisType);
8048
+ const min = numberInput(ctx, group.manualMin ?? 0, -1e308, 1e308, 0.1);
8049
+ const max = numberInput(ctx, group.manualMax ?? 1, -1e308, 1e308, 0.1);
8050
+ const updateLimits = () => {
8051
+ min.disabled = minType.value !== "custom";
8052
+ max.disabled = maxType.value !== "custom";
8053
+ };
8054
+ minType.addEventListener("change", updateLimits);
8055
+ maxType.addEventListener("change", updateLimits);
8056
+ updateLimits();
8057
+ const color = textInput(ctx, resolveColor(group.colorSeries, t.workbook.theme));
8058
+ color.type = "color";
8059
+ const negative = textInput(ctx, resolveColor(group.colorNegative, t.workbook.theme));
8060
+ negative.type = "color";
8061
+ const mixedColors = groups.some(
8062
+ (entry) => (resolveColor(entry.colorSeries, t.workbook.theme) ?? "#000000").toLowerCase() !== color.value.toLowerCase() || (resolveColor(entry.colorNegative, t.workbook.theme) ?? "#000000").toLowerCase() !== negative.value.toLowerCase()
8063
+ );
8064
+ for (const [input, key] of [
8065
+ [kind, "type"],
8066
+ [width, "lineWeight"],
8067
+ [empty, "displayEmptyCellsAs"],
8068
+ [hidden.input, "displayHidden"],
8069
+ [axis.input, "displayXAxis"],
8070
+ [rtl.input, "rightToLeft"],
8071
+ [minType, "minAxisType"],
8072
+ [maxType, "maxAxisType"],
8073
+ [min, "manualMin"],
8074
+ [max, "manualMax"]
8075
+ ])
8076
+ mixed(input, key);
8077
+ for (const check of checks) {
8078
+ mixed(check.input, check.key);
8079
+ track(check.input, check.key, () => ({ [check.key]: check.input.checked }));
8080
+ }
8081
+ track(kind, "type", () => ({ type: kind.value }));
8082
+ track(width, "lineWeight", () => ({ lineWeight: Number(width.value) }));
8083
+ track(empty, "displayEmptyCellsAs", () => ({
8084
+ displayEmptyCellsAs: empty.value
8085
+ }));
8086
+ track(hidden.input, "displayHidden", () => ({ displayHidden: hidden.input.checked }));
8087
+ track(axis.input, "displayXAxis", () => ({ displayXAxis: axis.input.checked }));
8088
+ track(rtl.input, "rightToLeft", () => ({ rightToLeft: rtl.input.checked }));
8089
+ track(minType, "minAxisType", () => ({
8090
+ minAxisType: minType.value,
8091
+ ...minType.value === "custom" ? { manualMin: Number(min.value) } : {}
8092
+ }));
8093
+ track(maxType, "maxAxisType", () => ({
8094
+ maxAxisType: maxType.value,
8095
+ ...maxType.value === "custom" ? { manualMax: Number(max.value) } : {}
8096
+ }));
8097
+ track(min, "manualMin", () => ({ manualMin: Number(min.value) }));
8098
+ track(max, "manualMax", () => ({ manualMax: Number(max.value) }));
8099
+ track(color, "colorSeries", () => ({ colorSeries: { rgb: color.value.slice(1) } }));
8100
+ track(negative, "colorNegative", () => ({ colorNegative: { rgb: negative.value.slice(1) } }));
8101
+ updateLimits();
8102
+ return showDialog(ctx, {
8103
+ name: "sparkline-settings",
8104
+ heading: "Sparkline Settings",
8105
+ wide: true,
8106
+ body: [
8107
+ text(ctx, "Changes apply to the entire selected sparkline groups."),
8108
+ text(ctx, "Only changed settings are applied."),
8109
+ field(ctx, "Sparkline Type:", kind),
8110
+ field(ctx, "Line Weight:", width),
8111
+ field(ctx, "Date Range (optional):", dates),
8112
+ text(ctx, "Leave the date range empty for a general axis."),
8113
+ fieldset(ctx, "Show", ...checks.map((check) => check.wrapper)),
8114
+ fieldset(
8115
+ ctx,
8116
+ "Colors",
8117
+ field(ctx, "Sparkline Color:", color),
8118
+ field(ctx, "Negative Color:", negative),
8119
+ ...mixedColors ? [text(ctx, "Colors vary between selected groups.")] : []
8120
+ ),
8121
+ fieldset(
8122
+ ctx,
8123
+ "Axis",
8124
+ field(ctx, "Minimum Axis:", minType),
8125
+ field(ctx, "Minimum Value:", min),
8126
+ field(ctx, "Maximum Axis:", maxType),
8127
+ field(ctx, "Maximum Value:", max),
8128
+ axis.wrapper,
8129
+ rtl.wrapper
8130
+ ),
8131
+ field(ctx, "Empty Cells:", empty),
8132
+ hidden.wrapper
8133
+ ],
8134
+ submit: () => {
8135
+ const patch = {};
8136
+ for (const read of changes.values()) Object.assign(patch, read());
8137
+ if (minType.value !== "custom") delete patch.manualMin;
8138
+ if (maxType.value !== "custom") delete patch.manualMax;
8139
+ if (patch.minAxisType === "custom" && !min.value.trim() || patch.maxAxisType === "custom" && !max.value.trim())
8140
+ throw new Error("The sparkline axis limits are not valid.");
8141
+ t.session.batch("Format sparklines", () => {
8142
+ if (datesChanged) t.session.setSparklineDateRange(t.sheet, t.ranges, dates.value);
8143
+ if (Object.keys(patch).length) t.session.setSparklineGroups(t.sheet, t.ranges, patch);
8144
+ });
8145
+ return true;
8146
+ }
8147
+ });
8148
+ }
8149
+ var AGGREGATES = [
8150
+ ["sum", "Sum"],
8151
+ ["count", "Count"],
8152
+ ["average", "Average"],
8153
+ ["min", "Min"],
8154
+ ["max", "Max"]
8155
+ ];
8156
+ function openPivotTable(ctx, settings = false) {
8157
+ const t = target(ctx);
8158
+ if (!t) return Promise.resolve(void 0);
8159
+ const pivot = settings ? pivotTableAt(t.ws, t.range.start) : void 0;
8160
+ if (settings && !pivot) return Promise.resolve(void 0);
8161
+ const source = textInput(ctx, pivot?.source ?? formatRange(t.range));
8162
+ const destination = textInput(
8163
+ ctx,
8164
+ formatAddress(pivot?.location.start ?? { row: t.range.start.row, col: t.range.end.col + 2 })
8165
+ );
8166
+ source.disabled = settings;
8167
+ destination.disabled = settings;
8168
+ const row2 = select(ctx, [], "");
8169
+ const second = select(ctx, [["", "(None)"]], "");
8170
+ const layout = select(
8171
+ ctx,
8172
+ [
8173
+ ["compact", "Compact Form"],
8174
+ ["outline", "Outline Form"],
8175
+ ["tabular", "Tabular Form"]
8176
+ ],
8177
+ pivot ? pivot.layout ?? "tabular" : "compact"
8178
+ );
8179
+ const position = select(
8180
+ ctx,
8181
+ [
8182
+ ["top", "Above each group"],
8183
+ ["bottom", "Below each group"]
8184
+ ],
8185
+ pivot?.subtotalPosition ?? (pivot ? "bottom" : "top")
8186
+ );
8187
+ const subtotals = checkbox(ctx, "Show subtotals", pivot?.subtotals !== false);
8188
+ const tabularNotice = text(ctx, "Tabular layout displays subtotals below groups.");
8189
+ const repeat = checkbox(ctx, "Repeat row labels", pivot?.repeatLabels ?? false);
8190
+ const column = select(ctx, [["", "(None)"]], "");
8191
+ const value = select(ctx, [], "");
8192
+ const aggregate = select(ctx, AGGREGATES, pivot?.aggregate ?? "sum");
8193
+ const loadFields = () => {
8194
+ let fields;
8195
+ try {
8196
+ fields = pivotSourceData(ctx.workbook(), t.sheet, source.value).fields;
8197
+ } catch {
8198
+ fields = [];
8199
+ }
8200
+ for (const [control, chosen, optional] of [
8201
+ [row2, pivot?.rowField, false],
8202
+ [second, pivot?.secondRowField, true],
8203
+ [column, pivot?.columnField, true],
8204
+ [value, pivot?.valueField, false]
8205
+ ]) {
8206
+ const previous = chosen ?? control.value;
8207
+ control.replaceChildren();
8208
+ for (const name of [...optional ? [""] : [], ...fields]) {
8209
+ const option = ctx.host.ownerDocument.createElement("option");
8210
+ option.value = name;
8211
+ option.textContent = name || ctx.t("(None)");
8212
+ control.append(option);
8213
+ }
8214
+ if (fields.includes(previous ?? "") || optional && !previous)
8215
+ control.value = previous ?? "";
8216
+ else if (control === value) control.value = fields.at(-1) ?? "";
8217
+ }
8218
+ };
8219
+ source.addEventListener("change", loadFields);
8220
+ loadFields();
8221
+ const updateRows = () => {
8222
+ subtotals.input.disabled = !second.value;
8223
+ repeat.input.disabled = !second.value || layout.value === "compact";
8224
+ position.disabled = !second.value || !subtotals.input.checked || layout.value === "tabular";
8225
+ tabularNotice.hidden = !second.value || !subtotals.input.checked || layout.value !== "tabular";
8226
+ };
8227
+ layout.addEventListener("change", updateRows);
8228
+ subtotals.input.addEventListener("change", updateRows);
8229
+ second.addEventListener("change", updateRows);
8230
+ source.addEventListener("change", updateRows);
8231
+ updateRows();
8232
+ return showDialog(ctx, {
8233
+ name: settings ? "pivot-settings" : "create-pivot-table",
8234
+ heading: settings ? "PivotTable Settings" : "Create PivotTable",
8235
+ body: [
8236
+ field(ctx, "Source Range:", source),
8237
+ field(ctx, "Destination Cell:", destination),
8238
+ field(ctx, "Row Field:", row2),
8239
+ field(ctx, "Second Row Field:", second),
8240
+ field(ctx, "Report Layout:", layout),
8241
+ subtotals.wrapper,
8242
+ field(ctx, "Subtotal Position:", position),
8243
+ tabularNotice,
8244
+ repeat.wrapper,
8245
+ field(ctx, "Column Field:", column),
8246
+ field(ctx, "Value Field:", value),
8247
+ field(ctx, "Summarize Values By:", aggregate)
8248
+ ],
8249
+ opened: () => (settings ? row2 : source).focus(),
8250
+ submit: () => {
8251
+ const options = {
8252
+ rowField: row2.value,
8253
+ layout: layout.value,
8254
+ subtotalPosition: position.value,
8255
+ secondRowField: second.value,
8256
+ subtotals: subtotals.input.checked,
8257
+ repeatLabels: repeat.input.checked,
8258
+ columnField: column.value,
8259
+ valueField: value.value,
8260
+ aggregate: aggregate.value
8261
+ };
8262
+ if (pivot) {
8263
+ if (pivot.rowField !== options.rowField || (pivot.layout ?? "tabular") !== options.layout || (pivot.subtotalPosition ?? "bottom") !== options.subtotalPosition || (pivot.secondRowField ?? "") !== options.secondRowField || pivot.subtotals !== false !== options.subtotals || (pivot.repeatLabels ?? false) !== options.repeatLabels || (pivot.columnField ?? "") !== options.columnField || pivot.valueField !== options.valueField || pivot.aggregate !== options.aggregate)
8264
+ t.session.refreshPivotTable(t.sheet, pivot.name, options);
8265
+ } else {
8266
+ const at = parseAddress(destination.value.trim().replaceAll("$", ""));
8267
+ if (!at) throw new Error("The reference is not valid.");
8268
+ t.session.createPivotTable(t.sheet, at, { ...options, source: source.value });
8269
+ ctx.selection.set({ ranges: [{ start: at, end: at }], active: at, anchor: at });
8270
+ }
8271
+ return true;
8272
+ }
8273
+ });
8274
+ }
8275
+ function openPrintPreview(ctx) {
8276
+ const t = target(ctx);
8277
+ if (!t) return Promise.resolve(void 0);
8278
+ const layout = paginateWorksheet(t.workbook, t.sheet);
8279
+ const fileName = ctx.host.fileName ?? t.ws.name;
8280
+ const html = buildPrintHtml(t.workbook, t.sheet, fileName, { locale: ctx.locale() });
8281
+ const frame = ctx.host.ownerDocument.createElement("iframe");
8282
+ frame.title = ctx.t("Print Preview");
8283
+ frame.srcdoc = html;
8284
+ frame.style.cssText = "width:100%;height:60vh;border:1px solid var(--xve-border,#ccc)";
8285
+ let page = 1;
8286
+ let actualSize = false;
8287
+ const previous = button(ctx, "Previous Page");
8288
+ const next = button(ctx, "Next Page");
8289
+ const zoom = button(ctx, "Actual Size");
8290
+ const count = text(ctx, "Page {page} of {count}", "xve-note", {
8291
+ page,
8292
+ count: layout.pages.length
8293
+ });
8294
+ const controls = ctx.host.ownerDocument.createElement("div");
8295
+ controls.style.cssText = "display:flex;align-items:center;gap:8px;flex-wrap:wrap";
8296
+ controls.append(previous, next, count, zoom);
8297
+ const update = () => {
8298
+ previous.disabled = page <= 1;
8299
+ next.disabled = page >= layout.pages.length;
8300
+ zoom.disabled = !layout.pages.length;
8301
+ count.textContent = ctx.t("Page {page} of {count}", {
8302
+ page: layout.pages.length ? page : 0,
8303
+ count: layout.pages.length
8304
+ });
8305
+ zoom.textContent = ctx.t(actualSize ? "Fit Page" : "Actual Size");
8306
+ const doc = frame.contentDocument;
8307
+ if (!doc) return;
8308
+ let style = doc.getElementById("preview-controls");
8309
+ if (!style) {
8310
+ style = doc.createElement("style");
8311
+ style.id = "preview-controls";
8312
+ style.setAttribute("media", "screen");
8313
+ doc.head.append(style);
8314
+ }
8315
+ const factor = actualSize ? 1 : Math.max(
8316
+ 0.05,
8317
+ Math.min(
8318
+ 1,
8319
+ (frame.clientWidth - 32) / layout.paperWidth,
8320
+ (frame.clientHeight - 32) / layout.paperHeight
8321
+ )
8322
+ );
8323
+ style.textContent = `.xve-print-page{display:none;zoom:${factor}}.xve-print-page[data-page="${page}"]{display:block}`;
8324
+ };
8325
+ previous.addEventListener("click", () => {
8326
+ page--;
8327
+ update();
8328
+ });
8329
+ next.addEventListener("click", () => {
8330
+ page++;
8331
+ update();
8332
+ });
8333
+ zoom.addEventListener("click", () => {
8334
+ actualSize = !actualSize;
8335
+ update();
8336
+ });
8337
+ frame.addEventListener("load", update);
8338
+ update();
8339
+ const print = button(ctx, "Print", true);
8340
+ print.disabled = !layout.pages.length;
8341
+ print.addEventListener("click", () => printHtml(ctx.host.ownerDocument, html));
8342
+ return showDialog(ctx, {
8343
+ name: "print-preview",
8344
+ heading: "Print Preview",
8345
+ wide: true,
8346
+ okLabel: null,
8347
+ cancelLabel: "Close",
8348
+ buttons: [print],
8349
+ body: [
8350
+ text(ctx, "Pages: {count} | Scale: {scale}%", "xve-note", {
8351
+ count: layout.pages.length,
8352
+ scale: Math.round(layout.scale * 100)
8353
+ }),
8354
+ text(
8355
+ ctx,
8356
+ "Preview uses worksheet dimensions. Fonts and printer margins may change pagination in Excel."
8357
+ ),
8358
+ ...layout.warnings.map((warning) => text(ctx, warning)),
8359
+ controls,
8360
+ frame
8361
+ ]
8362
+ });
8363
+ }
7729
8364
 
7730
8365
  // src/xlsx/dialogs/register-tools.ts
7731
8366
  var props = (value) => value && typeof value === "object" ? value : {};
7732
8367
  function registerToolDialogs(ctx) {
7733
8368
  const d = ctx.dialogs;
8369
+ d.register("print-preview", (c) => openPrintPreview(c));
8370
+ d.register("create-pivot-table", (c) => openPivotTable(c));
8371
+ d.register("pivot-settings", (c) => openPivotTable(c, true));
8372
+ d.register(
8373
+ "create-sparklines",
8374
+ (c, p) => openCreateSparklines(c, props(p).type)
8375
+ );
8376
+ d.register("sparkline-settings", (c) => openSparklineSettings(c));
7734
8377
  d.register("insert-chart", (c, p) => openInsertChart(c, props(p)));
7735
8378
  d.register("paste-special", (c) => openPasteSpecial(c));
7736
8379
  d.register("page-setup", (c, p) => openPageSetup(c, props(p)));
@@ -7919,7 +8562,7 @@ function chartColorGallerySections(ctx) {
7919
8562
  const selectedChart = activeChart(ctx);
7920
8563
  if (!workbook || !selectedChart) return [];
7921
8564
  const scheme = chartColorScheme(workbook.theme);
7922
- const selected = selectedChart.chart.colorPalette ?? 10;
8565
+ const selected2 = selectedChart.chart.colorPalette ?? 10;
7923
8566
  return ["colorful", "monochromatic"].map((group) => ({
7924
8567
  title: ctx.t(group === "colorful" ? "Colorful" : "Monochromatic"),
7925
8568
  columns: 1,
@@ -7931,7 +8574,7 @@ function chartColorGallerySections(ctx) {
7931
8574
  n: palette.index
7932
8575
  }),
7933
8576
  preview: swatchStripSvg(chartPaletteColors(palette, 6, scheme), { width: 96, height: 14 }),
7934
- applied: selected === palette.id
8577
+ applied: selected2 === palette.id
7935
8578
  }))
7936
8579
  }));
7937
8580
  }
@@ -8518,7 +9161,19 @@ function insertTab() {
8518
9161
  {
8519
9162
  id: "tables",
8520
9163
  label: "Tables",
8521
- controls: [{ kind: "button", command: "insert.table", size: "large" }]
9164
+ controls: [
9165
+ { kind: "button", command: "insert.table", size: "large" },
9166
+ { kind: "button", command: "insert.pivot-table", size: "large" },
9167
+ {
9168
+ kind: "menu",
9169
+ label: "PivotTable",
9170
+ items: [
9171
+ { command: "pivot.settings" },
9172
+ { command: "pivot.refresh" },
9173
+ { command: "pivot.delete" }
9174
+ ]
9175
+ }
9176
+ ]
8522
9177
  },
8523
9178
  {
8524
9179
  id: "illustrations",
@@ -8552,6 +9207,30 @@ function insertTab() {
8552
9207
  label: "Links",
8553
9208
  controls: [{ kind: "button", command: "insert.link", size: "large" }]
8554
9209
  },
9210
+ {
9211
+ id: "sparklines",
9212
+ label: "Sparklines",
9213
+ launcher: "sparkline.settings",
9214
+ controls: [
9215
+ { kind: "button", command: "insert.sparkline-line", size: "large" },
9216
+ { kind: "button", command: "insert.sparkline-column", size: "large" },
9217
+ { kind: "button", command: "insert.sparkline-stacked", size: "large" },
9218
+ {
9219
+ kind: "stack",
9220
+ controls: [
9221
+ { kind: "button", command: "sparkline.settings" },
9222
+ {
9223
+ kind: "menu",
9224
+ label: "Clear Sparklines",
9225
+ items: [
9226
+ { command: "sparkline.clear-selected" },
9227
+ { command: "sparkline.clear-groups" }
9228
+ ]
9229
+ }
9230
+ ]
9231
+ }
9232
+ ]
9233
+ },
8555
9234
  {
8556
9235
  id: "comments",
8557
9236
  label: "Comments",
@@ -8618,7 +9297,23 @@ function pageLayoutTab() {
8618
9297
  icon: "xl-printArea",
8619
9298
  size: "large",
8620
9299
  items: [{ command: "page.print-area-set" }, { command: "page.print-area-clear" }]
8621
- }
9300
+ },
9301
+ {
9302
+ kind: "menu",
9303
+ label: "Breaks",
9304
+ icon: "xl-printArea",
9305
+ size: "large",
9306
+ items: [
9307
+ { command: "page.break-row-insert" },
9308
+ { command: "page.break-col-insert" },
9309
+ sep2,
9310
+ { command: "page.break-row-remove" },
9311
+ { command: "page.break-col-remove" },
9312
+ sep2,
9313
+ { command: "page.breaks-reset" }
9314
+ ]
9315
+ },
9316
+ { kind: "button", command: "page.preview", size: "large" }
8622
9317
  ]
8623
9318
  },
8624
9319
  {
@@ -8665,6 +9360,99 @@ function registerSheetIcons() {
8665
9360
  registered = true;
8666
9361
  for (const [name, d] of Object.entries(SHEET_ICONS)) registerIcon(`xl-${name}`, d);
8667
9362
  }
9363
+ function hasSparklines(ctx) {
9364
+ const t = target(ctx);
9365
+ return !!t && selectedSparklineGroups(t.ws, t.ranges).length > 0;
9366
+ }
9367
+ function sparklineCommands() {
9368
+ return [
9369
+ ...[
9370
+ ["line", "Line Sparkline", "chartLine"],
9371
+ ["column", "Column Sparkline", "chartColumn"],
9372
+ ["stacked", "Win/Loss Sparkline", "chartColumn"]
9373
+ ].map(
9374
+ ([type, label, glyph]) => editing({
9375
+ id: `insert.sparkline-${type}`,
9376
+ label,
9377
+ icon: icon(glyph),
9378
+ lock: "objects",
9379
+ run: (ctx) => void ctx.dialogs.open("create-sparklines", { type })
9380
+ })
9381
+ ),
9382
+ editing({
9383
+ id: "sparkline.settings",
9384
+ label: "Sparkline Settings",
9385
+ icon: icon("chartLine"),
9386
+ lock: "objects",
9387
+ enabled: hasSparklines,
9388
+ run: (ctx) => void ctx.dialogs.open("sparkline-settings")
9389
+ }),
9390
+ ...[
9391
+ ["selected", false, "Clear Selected Sparklines"],
9392
+ ["groups", true, "Clear Sparkline Groups"]
9393
+ ].map(
9394
+ ([id, whole, label]) => editing({
9395
+ id: `sparkline.clear-${id}`,
9396
+ label,
9397
+ icon: icon("clear"),
9398
+ lock: "objects",
9399
+ enabled: hasSparklines,
9400
+ run: (ctx) => {
9401
+ const t = target(ctx);
9402
+ if (t) t.session.deleteSparklines(t.sheet, t.ranges, whole);
9403
+ }
9404
+ })
9405
+ )
9406
+ ];
9407
+ }
9408
+ function selected(ctx) {
9409
+ const t = target(ctx);
9410
+ const pivot = t ? pivotTableAt(t.ws, t.range.start) : void 0;
9411
+ return t && pivot ? { t, pivot } : void 0;
9412
+ }
9413
+ function pivotCommands() {
9414
+ return [
9415
+ editing({
9416
+ id: "insert.pivot-table",
9417
+ label: "PivotTable",
9418
+ icon: icon("table"),
9419
+ lock: "objects",
9420
+ run: (ctx) => void ctx.dialogs.open("create-pivot-table")
9421
+ }),
9422
+ editing({
9423
+ id: "pivot.settings",
9424
+ label: "PivotTable Settings",
9425
+ icon: icon("table"),
9426
+ lock: "objects",
9427
+ enabled: (ctx) => !!selected(ctx),
9428
+ run: (ctx) => void ctx.dialogs.open("pivot-settings")
9429
+ }),
9430
+ editing({
9431
+ id: "pivot.refresh",
9432
+ label: "Refresh PivotTable",
9433
+ icon: icon("table"),
9434
+ lock: "objects",
9435
+ enabled: (ctx) => !!selected(ctx),
9436
+ run: (ctx) => {
9437
+ const selection = selected(ctx);
9438
+ if (selection)
9439
+ selection.t.session.refreshPivotTable(selection.t.sheet, selection.pivot.name);
9440
+ }
9441
+ }),
9442
+ editing({
9443
+ id: "pivot.delete",
9444
+ label: "Delete PivotTable",
9445
+ icon: icon("clear"),
9446
+ lock: "objects",
9447
+ enabled: (ctx) => !!selected(ctx),
9448
+ run: (ctx) => {
9449
+ const selection = selected(ctx);
9450
+ if (selection)
9451
+ selection.t.session.deletePivotTable(selection.t.sheet, selection.pivot.name);
9452
+ }
9453
+ })
9454
+ ];
9455
+ }
8668
9456
  var ordered = (ctx) => [...target(ctx)?.ws.comments ?? []].sort(
8669
9457
  (a, b) => a.address.row - b.address.row || a.address.col - b.address.col
8670
9458
  );
@@ -8774,35 +9562,35 @@ function reviewCommands() {
8774
9562
  })
8775
9563
  ];
8776
9564
  }
8777
- function seriesFillBinding(selected) {
9565
+ function seriesFillBinding(selected2) {
8778
9566
  return {
8779
9567
  commandId: "chart.format-series",
8780
- key: selected,
8781
- fill: (chart) => chart.series[selected()]?.fill,
8782
- gradient: (view) => view.series[selected()]?.gradient,
8783
- paint: (view) => view.series[selected()]?.color,
9568
+ key: selected2,
9569
+ fill: (chart) => chart.series[selected2()]?.fill,
9570
+ gradient: (view) => view.series[selected2()]?.gradient,
9571
+ paint: (view) => view.series[selected2()]?.color,
8784
9572
  rectangular: (chart) => chart.chartType === "bar" || chart.chartType === "column",
8785
- color: (chart, color) => chartSeriesFillPatch(chart, selected(), color),
8786
- solid: (chart) => chartSeriesSolidFillPatch(chart, selected()),
8787
- edit: (chart, edit) => chartSeriesGradientPatch(chart, selected(), edit),
8788
- transparency: (chart) => chartSeriesTransparency(chart, selected()),
8789
- setTransparency: (chart, value) => chartSeriesTransparencyPatch(chart, selected(), value),
9573
+ color: (chart, color) => chartSeriesFillPatch(chart, selected2(), color),
9574
+ solid: (chart) => chartSeriesSolidFillPatch(chart, selected2()),
9575
+ edit: (chart, edit) => chartSeriesGradientPatch(chart, selected2(), edit),
9576
+ transparency: (chart) => chartSeriesTransparency(chart, selected2()),
9577
+ setTransparency: (chart, value) => chartSeriesTransparencyPatch(chart, selected2(), value),
8790
9578
  preview: (chart, patch) => ({ ...chart, ...patch })
8791
9579
  };
8792
9580
  }
8793
- function backgroundFillBinding(selected) {
9581
+ function backgroundFillBinding(selected2) {
8794
9582
  return {
8795
9583
  commandId: "chart.format-area",
8796
- key: selected,
8797
- fill: (chart) => chartElementFill(chart, selected()),
8798
- gradient: (view) => view.appearance?.[selected()]?.gradient,
8799
- paint: (view) => view.appearance?.[selected()]?.fillColor ?? (selected() === "chartArea" ? "#FFFFFF" : "none"),
9584
+ key: selected2,
9585
+ fill: (chart) => chartElementFill(chart, selected2()),
9586
+ gradient: (view) => view.appearance?.[selected2()]?.gradient,
9587
+ paint: (view) => view.appearance?.[selected2()]?.fillColor ?? (selected2() === "chartArea" ? "#FFFFFF" : "none"),
8800
9588
  rectangular: () => true,
8801
- color: (chart, color) => chartElementFillPatch(chart, selected(), color),
8802
- solid: (chart) => chartElementSolidFillPatch(chart, selected()),
8803
- edit: (chart, edit) => chartElementGradientPatch(chart, selected(), edit),
8804
- transparency: (chart) => chartElementTransparency(chart, selected()),
8805
- setTransparency: (chart, value) => chartElementTransparencyPatch(chart, selected(), value),
9589
+ color: (chart, color) => chartElementFillPatch(chart, selected2(), color),
9590
+ solid: (chart) => chartElementSolidFillPatch(chart, selected2()),
9591
+ edit: (chart, edit) => chartElementGradientPatch(chart, selected2(), edit),
9592
+ transparency: (chart) => chartElementTransparency(chart, selected2()),
9593
+ setTransparency: (chart, value) => chartElementTransparencyPatch(chart, selected2(), value),
8806
9594
  preview: (chart, patch) => chartWithElementFills(chart, patch.elementFills ?? {})
8807
9595
  };
8808
9596
  }
@@ -8864,7 +9652,7 @@ function createNumberRange(input, options) {
8864
9652
  }
8865
9653
 
8866
9654
  // src/xlsx/chart-series-transparency.ts
8867
- function createSeriesTransparency(ctx, selected, binding = seriesFillBinding(selected)) {
9655
+ function createSeriesTransparency(ctx, selected2, binding = seriesFillBinding(selected2)) {
8868
9656
  const element = el(ctx, "div");
8869
9657
  const input = numberInput(ctx, 0, 0, 100);
8870
9658
  const row2 = field(ctx, "Transparency", input);
@@ -8959,9 +9747,9 @@ function createGradientStopTrack(doc) {
8959
9747
  const next = event.key === "ArrowRight" ? index + 1 : event.key === "ArrowLeft" ? index - 1 : void 0;
8960
9748
  if (next === void 0 || current.disabled) return;
8961
9749
  event.preventDefault();
8962
- const selected = Math.max(0, Math.min(current.stops.length - 1, next));
8963
- current.onSelect(selected);
8964
- element.querySelectorAll("button")[selected]?.focus();
9750
+ const selected2 = Math.max(0, Math.min(current.stops.length - 1, next));
9751
+ current.onSelect(selected2);
9752
+ element.querySelectorAll("button")[selected2]?.focus();
8965
9753
  });
8966
9754
  return button2;
8967
9755
  })
@@ -9138,7 +9926,7 @@ function createGradientPresetGallery(doc) {
9138
9926
  update(options) {
9139
9927
  current = options;
9140
9928
  if (options.disabled) element.open = false;
9141
- const selected = officeGradientPresetId(options.fill);
9929
+ const selected2 = officeGradientPresetId(options.fill);
9142
9930
  element.state = {
9143
9931
  id: "gradient-presets",
9144
9932
  label: options.label,
@@ -9152,7 +9940,7 @@ function createGradientPresetGallery(doc) {
9152
9940
  items: OFFICE_GRADIENT_PRESETS.map((preset) => ({
9153
9941
  id: String(preset.id),
9154
9942
  label: options.translate(preset.label),
9155
- applied: preset.id === selected,
9943
+ applied: preset.id === selected2,
9156
9944
  preview: gradientGalleryPreview(
9157
9945
  `${prefix}-${preset.id}`,
9158
9946
  resolveChartGradient(
@@ -9206,10 +9994,10 @@ function createGradientTypeField(ctx, onPick) {
9206
9994
  };
9207
9995
  }
9208
9996
  function createChartGradientPreview(root, drawing, series, gradient) {
9209
- const target24 = typeof series === "number" ? `s${series}` : series;
9997
+ const target29 = typeof series === "number" ? `s${series}` : series;
9210
9998
  const nodes = Array.from(
9211
9999
  root.querySelectorAll(
9212
- `.xg-obj[data-index="${drawing}"] :is(linearGradient,radialGradient,pattern)[id$="-${target24}"]`
10000
+ `.xg-obj[data-index="${drawing}"] :is(linearGradient,radialGradient,pattern)[id$="-${target29}"]`
9213
10001
  )
9214
10002
  );
9215
10003
  const originals = nodes.map((node) => ({
@@ -9299,7 +10087,7 @@ function seriesRangePreview(ctx, chart, view, series, stop, drawing, track, colo
9299
10087
  }
9300
10088
 
9301
10089
  // src/xlsx/chart-series-gradient.ts
9302
- function createSeriesGradient(ctx, selected, binding = seriesFillBinding(selected)) {
10090
+ function createSeriesGradient(ctx, selected2, binding = seriesFillBinding(selected2)) {
9303
10091
  const element = el(ctx, "div", "xve-chart-series-gradient");
9304
10092
  const angle = numberInput(ctx, 90, 0, 360);
9305
10093
  const position = numberInput(ctx, 0, 0, 100);
@@ -9551,7 +10339,7 @@ function createSeriesGradient(ctx, selected, binding = seriesFillBinding(selecte
9551
10339
  }
9552
10340
 
9553
10341
  // src/xlsx/chart-series-fill.ts
9554
- function createSeriesFill(ctx, selected, binding = seriesFillBinding(selected)) {
10342
+ function createSeriesFill(ctx, selected2, binding = seriesFillBinding(selected2)) {
9555
10343
  const element = el(ctx, "div", "xve-chart-series-fill");
9556
10344
  const heading2 = el(ctx, "h3");
9557
10345
  const kind = select(ctx, []);
@@ -9559,8 +10347,8 @@ function createSeriesFill(ctx, selected, binding = seriesFillBinding(selected))
9559
10347
  const color = el(ctx, "button", "xve-input xve-chart-series-color");
9560
10348
  color.type = "button";
9561
10349
  const colorField = field(ctx, "Color", color);
9562
- const transparency = createSeriesTransparency(ctx, selected, binding);
9563
- const gradient = createSeriesGradient(ctx, selected, binding);
10350
+ const transparency = createSeriesTransparency(ctx, selected2, binding);
10351
+ const gradient = createSeriesGradient(ctx, selected2, binding);
9564
10352
  element.append(heading2, kindField, colorField, transparency.element, gradient.element);
9565
10353
  let current;
9566
10354
  const apply = (value) => {
@@ -9665,15 +10453,15 @@ function createChartSeriesPane(ctx, onOpen) {
9665
10453
  };
9666
10454
  closeButton.addEventListener("click", close);
9667
10455
  const body = el(ctx, "div", "xve-chart-series-body");
9668
- let selected = 0;
10456
+ let selected2 = 0;
9669
10457
  let shownWorkbook;
9670
10458
  let shownSheet = -1;
9671
10459
  let shownChart = -1;
9672
10460
  const seriesSelect = select(ctx, []);
9673
10461
  const seriesField = field(ctx, "Series", seriesSelect);
9674
- const fills = createSeriesFill(ctx, () => selected);
10462
+ const fills = createSeriesFill(ctx, () => selected2);
9675
10463
  seriesSelect.addEventListener("change", () => {
9676
- selected = Number(seriesSelect.value);
10464
+ selected2 = Number(seriesSelect.value);
9677
10465
  refresh();
9678
10466
  });
9679
10467
  const section = el(ctx, "h3");
@@ -9746,11 +10534,11 @@ function createChartSeriesPane(ctx, onOpen) {
9746
10534
  const chart = found?.chart;
9747
10535
  const workbook = ctx.workbook();
9748
10536
  if (workbook !== shownWorkbook || shownSheet !== ctx.activeSheet() || shownChart !== found?.index)
9749
- selected = 0;
10537
+ selected2 = 0;
9750
10538
  shownWorkbook = workbook;
9751
10539
  shownSheet = ctx.activeSheet();
9752
10540
  shownChart = found?.index ?? -1;
9753
- if (!chart?.series[selected]) selected = 0;
10541
+ if (!chart?.series[selected2]) selected2 = 0;
9754
10542
  const model = workbook && chart ? chartView(
9755
10543
  workbook,
9756
10544
  ctx.activeSheet(),
@@ -9765,7 +10553,7 @@ function createChartSeriesPane(ctx, onOpen) {
9765
10553
  return option;
9766
10554
  })
9767
10555
  );
9768
- seriesSelect.value = String(selected);
10556
+ seriesSelect.value = String(selected2);
9769
10557
  seriesSelect.disabled = !chart?.series.length || !ctx.commands.isEnabled("chart.format-series");
9770
10558
  fills.refresh(chart, model);
9771
10559
  const supported = chart?.chartType === "bar" || chart?.chartType === "column";
@@ -9804,7 +10592,7 @@ function createChartSeriesPane(ctx, onOpen) {
9804
10592
  element.hidden = false;
9805
10593
  refresh();
9806
10594
  if (typeof props2 === "number" && Number.isInteger(props2) && activeChart(ctx)?.chart.series[props2]) {
9807
- selected = props2;
10595
+ selected2 = props2;
9808
10596
  refresh();
9809
10597
  }
9810
10598
  overlap.focus();
@@ -9837,13 +10625,13 @@ function createChartAreaPane(ctx, onOpen) {
9837
10625
  closeButton.type = "button";
9838
10626
  closeButton.textContent = "\xD7";
9839
10627
  const body = el(ctx, "div", "xve-chart-series-body");
9840
- let selected = "chartArea";
9841
- const target24 = select(ctx, []);
9842
- const targetField = field(ctx, "Chart element", target24);
10628
+ let selected2 = "chartArea";
10629
+ const target29 = select(ctx, []);
10630
+ const targetField = field(ctx, "Chart element", target29);
9843
10631
  const fills = createSeriesFill(
9844
10632
  ctx,
9845
10633
  () => 0,
9846
- backgroundFillBinding(() => selected)
10634
+ backgroundFillBinding(() => selected2)
9847
10635
  );
9848
10636
  const close = () => {
9849
10637
  fills.refresh(void 0, void 0);
@@ -9869,13 +10657,13 @@ function createChartAreaPane(ctx, onOpen) {
9869
10657
  return;
9870
10658
  }
9871
10659
  const available = (part) => part === "title" ? !!found.chart.title : part === "legend" ? found.chart.showLegend : true;
9872
- for (const option of target24.options)
10660
+ for (const option of target29.options)
9873
10661
  option.disabled = !available(option.value);
9874
- if (!available(selected)) selected = "chartArea";
9875
- title.textContent = ctx.t(names[selected][1]);
10662
+ if (!available(selected2)) selected2 = "chartArea";
10663
+ title.textContent = ctx.t(names[selected2][1]);
9876
10664
  element.setAttribute("aria-label", title.textContent);
9877
- target24.value = selected;
9878
- target24.disabled = !ctx.commands.isEnabled("chart.format-area");
10665
+ target29.value = selected2;
10666
+ target29.disabled = !ctx.commands.isEnabled("chart.format-area");
9879
10667
  fills.refresh(
9880
10668
  found.chart,
9881
10669
  chartView(
@@ -9889,8 +10677,8 @@ function createChartAreaPane(ctx, onOpen) {
9889
10677
  const relocalize = () => {
9890
10678
  closeButton.setAttribute("aria-label", ctx.t("Close"));
9891
10679
  targetField.querySelector("span").textContent = ctx.t("Chart element");
9892
- target24.setAttribute("aria-label", ctx.t("Chart element"));
9893
- target24.replaceChildren(
10680
+ target29.setAttribute("aria-label", ctx.t("Chart element"));
10681
+ target29.replaceChildren(
9894
10682
  ...CHART_FILL_PARTS.map((part) => {
9895
10683
  const option = el(ctx, "option");
9896
10684
  option.value = part;
@@ -9900,18 +10688,18 @@ function createChartAreaPane(ctx, onOpen) {
9900
10688
  );
9901
10689
  refresh();
9902
10690
  };
9903
- target24.addEventListener("change", () => {
9904
- if (!target24.disabled && CHART_FILL_PARTS.includes(target24.value))
9905
- selected = target24.value;
10691
+ target29.addEventListener("change", () => {
10692
+ if (!target29.disabled && CHART_FILL_PARTS.includes(target29.value))
10693
+ selected2 = target29.value;
9906
10694
  refresh();
9907
10695
  });
9908
10696
  ctx.dialogs.register("format-chart-area", async (_ctx, part) => {
9909
10697
  if (!ctx.commands.isEnabled("chart.format-area")) return;
9910
10698
  onOpen();
9911
- selected = CHART_FILL_PARTS.includes(part) ? part : "chartArea";
10699
+ selected2 = CHART_FILL_PARTS.includes(part) ? part : "chartArea";
9912
10700
  element.hidden = false;
9913
10701
  refresh();
9914
- target24.focus();
10702
+ target29.focus();
9915
10703
  });
9916
10704
  relocalize();
9917
10705
  return { element, refresh, relocalize, close };
@@ -9929,7 +10717,10 @@ function allCommands() {
9929
10717
  ...editingCommands(),
9930
10718
  ...insertNowCommands(),
9931
10719
  ...insertCommands(),
10720
+ ...sparklineCommands(),
10721
+ ...pivotCommands(),
9932
10722
  ...pageLayoutCommands(),
10723
+ ...pageBreakCommands(),
9933
10724
  ...formulaCommands(),
9934
10725
  ...dataCommands(),
9935
10726
  ...reviewCommands(),
@@ -10270,7 +11061,7 @@ function createFunctionAssist(doc, container, t, catalog = FUNCTION_CATALOG) {
10270
11061
  const tip = h(doc, "div", "xg-assist-tip", { role: "tooltip" });
10271
11062
  container.append(root);
10272
11063
  let matches = [];
10273
- let selected = 0;
11064
+ let selected2 = 0;
10274
11065
  let token;
10275
11066
  let lastField;
10276
11067
  const close = () => {
@@ -10284,20 +11075,20 @@ function createFunctionAssist(doc, container, t, catalog = FUNCTION_CATALOG) {
10284
11075
  matches.forEach((info, index) => {
10285
11076
  const option = h(doc, "li", "xg-assist-option", {
10286
11077
  role: "option",
10287
- "aria-selected": String(index === selected)
11078
+ "aria-selected": String(index === selected2)
10288
11079
  });
10289
11080
  option.dataset.name = info.name;
10290
11081
  option.textContent = info.name;
10291
11082
  option.addEventListener("mousedown", (event) => {
10292
11083
  event.preventDefault();
10293
- selected = index;
11084
+ selected2 = index;
10294
11085
  if (lastField) accept(lastField);
10295
11086
  });
10296
11087
  list.append(option);
10297
11088
  });
10298
- desc.textContent = matches[selected]?.description ?? "";
11089
+ desc.textContent = matches[selected2]?.description ?? "";
10299
11090
  root.replaceChildren(list, desc);
10300
- list.children[selected]?.scrollIntoView?.({ block: "nearest" });
11091
+ list.children[selected2]?.scrollIntoView?.({ block: "nearest" });
10301
11092
  };
10302
11093
  const renderTip = (info, argIndex) => {
10303
11094
  const { name, params } = syntaxParams(info.syntax);
@@ -10320,7 +11111,7 @@ function createFunctionAssist(doc, container, t, catalog = FUNCTION_CATALOG) {
10320
11111
  root.replaceChildren(tip);
10321
11112
  };
10322
11113
  const accept = (field2) => {
10323
- const info = matches[selected];
11114
+ const info = matches[selected2];
10324
11115
  if (!info || !token) return;
10325
11116
  const next = splice(
10326
11117
  field2.input.value,
@@ -10342,10 +11133,10 @@ function createFunctionAssist(doc, container, t, catalog = FUNCTION_CATALOG) {
10342
11133
  token = nameAtCaret(text3, caret);
10343
11134
  const found = token ? functionMatches(token.prefix, 12, catalog) : [];
10344
11135
  if (found.length) {
10345
- const previous = matches[selected]?.name;
11136
+ const previous = matches[selected2]?.name;
10346
11137
  matches = found;
10347
11138
  const keep = previous ? found.findIndex((m) => m.name === previous) : -1;
10348
- selected = keep >= 0 ? keep : 0;
11139
+ selected2 = keep >= 0 ? keep : 0;
10349
11140
  root.hidden = false;
10350
11141
  renderList();
10351
11142
  return;
@@ -10371,7 +11162,7 @@ function createFunctionAssist(doc, container, t, catalog = FUNCTION_CATALOG) {
10371
11162
  }
10372
11163
  if (event.key === "ArrowDown" || event.key === "ArrowUp") {
10373
11164
  const step2 = event.key === "ArrowDown" ? 1 : -1;
10374
- selected = (selected + step2 + matches.length) % matches.length;
11165
+ selected2 = (selected2 + step2 + matches.length) % matches.length;
10375
11166
  renderList();
10376
11167
  } else if (event.key === "Tab" || event.key === "Enter" && !event.altKey) {
10377
11168
  accept(field2);
@@ -10626,11 +11417,11 @@ var CellEditor = class {
10626
11417
  }
10627
11418
  const refs = [];
10628
11419
  for (const ref of this.field.references()) {
10629
- const target24 = referenceTarget(ref.text);
10630
- if (!target24) continue;
10631
- if (target24.sheet !== void 0 && target24.sheet.toLowerCase() !== sheet.name.toLowerCase())
11420
+ const target29 = referenceTarget(ref.text);
11421
+ if (!target29) continue;
11422
+ if (target29.sheet !== void 0 && target29.sheet.toLowerCase() !== sheet.name.toLowerCase())
10632
11423
  continue;
10633
- refs.push({ range: target24.range, color: ref.color });
11424
+ refs.push({ range: target29.range, color: ref.color });
10634
11425
  }
10635
11426
  view.overlay.references = refs.length ? refs : void 0;
10636
11427
  view.schedule();
@@ -10900,9 +11691,9 @@ var DrawingLayer = class {
10900
11691
  }
10901
11692
  }
10902
11693
  #selection(node, index) {
10903
- const selected = this.#selected === index;
10904
- node.classList.toggle("xg-obj-sel", selected);
10905
- if (!selected) {
11694
+ const selected2 = this.#selected === index;
11695
+ node.classList.toggle("xg-obj-sel", selected2);
11696
+ if (!selected2) {
10906
11697
  for (const grip of node.querySelectorAll(".xg-grip")) grip.remove();
10907
11698
  } else if (!node.querySelector(".xg-grip")) {
10908
11699
  for (const pos of ["nw", "ne", "sw", "se"]) {
@@ -11021,9 +11812,9 @@ var GridA11y = class {
11021
11812
  }
11022
11813
  input;
11023
11814
  /** Updates the sink label and announces (debounced) after a selection change. */
11024
- update(selection, editing7) {
11815
+ update(selection, editing9) {
11025
11816
  const text3 = describeSelection(this.#view, selection);
11026
- if (!editing7) this.input.setAttribute("aria-label", text3);
11817
+ if (!editing9) this.input.setAttribute("aria-label", text3);
11027
11818
  if (this.#timer) clearTimeout(this.#timer);
11028
11819
  this.#timer = setTimeout(() => {
11029
11820
  this.live.textContent = text3;
@@ -11509,8 +12300,8 @@ function openMenuAtActive(view, refocus) {
11509
12300
  }
11510
12301
  function wireMenus(view, refocus) {
11511
12302
  const onMenu = (event) => {
11512
- const target24 = event.target;
11513
- if (target24.closest(".xg-editor-host.xg-editing, .xg-popup")) return;
12303
+ const target29 = event.target;
12304
+ if (target29.closest(".xg-editor-host.xg-editing, .xg-popup")) return;
11514
12305
  event.preventDefault();
11515
12306
  const hit = view.hitClient(event.clientX, event.clientY);
11516
12307
  const kind = hit.area === "row-header" ? "row" : hit.area === "col-header" ? "col" : "cell";
@@ -11571,8 +12362,8 @@ function startHeaderResize(view, axis, index, event) {
11571
12362
  }
11572
12363
  };
11573
12364
  draw();
11574
- const target24 = view.view;
11575
- target24.setPointerCapture?.(event.pointerId);
12365
+ const target29 = view.view;
12366
+ target29.setPointerCapture?.(event.pointerId);
11576
12367
  const move = (e) => {
11577
12368
  const { x, y } = view.clientToView(e.clientX, e.clientY);
11578
12369
  size = Math.max(0, Math.round((axis === "col" ? x : y) - start));
@@ -11580,9 +12371,9 @@ function startHeaderResize(view, axis, index, event) {
11580
12371
  guide.title = String(toFileSize(view, axis, size));
11581
12372
  };
11582
12373
  const up = (e) => {
11583
- target24.removeEventListener("pointermove", move, true);
11584
- target24.removeEventListener("pointerup", up, true);
11585
- target24.releasePointerCapture?.(e.pointerId);
12374
+ target29.removeEventListener("pointermove", move, true);
12375
+ target29.removeEventListener("pointerup", up, true);
12376
+ target29.releasePointerCapture?.(e.pointerId);
11586
12377
  guide.remove();
11587
12378
  const indices = resizeTargets(view, axis, index);
11588
12379
  const sheet = view.sheetIndex();
@@ -11590,8 +12381,8 @@ function startHeaderResize(view, axis, index, event) {
11590
12381
  else if (axis === "col") session.setColumnWidth(sheet, indices, toFileSize(view, "col", size));
11591
12382
  else session.setRowHeight(sheet, indices, toFileSize(view, "row", size));
11592
12383
  };
11593
- target24.addEventListener("pointermove", move, true);
11594
- target24.addEventListener("pointerup", up, true);
12384
+ target29.addEventListener("pointermove", move, true);
12385
+ target29.addEventListener("pointerup", up, true);
11595
12386
  }
11596
12387
  function autoFit(view, axis, index) {
11597
12388
  const session = view.ctx.session();
@@ -11681,8 +12472,8 @@ function wirePointer(host) {
11681
12472
  }, 40);
11682
12473
  };
11683
12474
  const onDown = (event) => {
11684
- const target24 = event.target;
11685
- if (target24.closest(".xg-editor-host, .xg-obj, .xg-dd, .xg-popup, .xg-assist")) return;
12475
+ const target29 = event.target;
12476
+ if (target29.closest(".xg-editor-host, .xg-obj, .xg-dd, .xg-popup, .xg-assist")) return;
11686
12477
  const { x, y } = view.clientToView(event.clientX, event.clientY);
11687
12478
  const g = view.geometry;
11688
12479
  const hit = g.hit(x, y);
@@ -11699,7 +12490,7 @@ function wirePointer(host) {
11699
12490
  event.preventDefault();
11700
12491
  const sheet = view.sheet();
11701
12492
  const editable = !view.ctx.readOnly();
11702
- if (target24.closest('[data-handle="fill"]') && editable) {
12493
+ if (target29.closest('[data-handle="fill"]') && editable) {
11703
12494
  drag = { kind: "fill", anchor: selection.get().active, pointer: event.pointerId, x, y };
11704
12495
  el3.setPointerCapture?.(event.pointerId);
11705
12496
  return;
@@ -11785,17 +12576,17 @@ function wirePointer(host) {
11785
12576
  drag = void 0;
11786
12577
  el3.releasePointerCapture?.(event.pointerId);
11787
12578
  if (finished.kind === "fill") {
11788
- const target24 = view.overlay.fillPreview;
12579
+ const target29 = view.overlay.fillPreview;
11789
12580
  view.overlay.fillPreview = void 0;
11790
12581
  const source = selection.get().ranges[selection.get().ranges.length - 1];
11791
- if (target24 && source) host.fill(source, target24);
12582
+ if (target29 && source) host.fill(source, target29);
11792
12583
  view.schedule();
11793
12584
  }
11794
12585
  if (finished.kind === "point") editor.focus();
11795
12586
  };
11796
12587
  const onDblClick = (event) => {
11797
- const target24 = event.target;
11798
- if (target24.closest(".xg-editor-host, .xg-obj, .xg-popup")) return;
12588
+ const target29 = event.target;
12589
+ if (target29.closest(".xg-editor-host, .xg-obj, .xg-popup")) return;
11799
12590
  const { x, y } = view.clientToView(event.clientX, event.clientY);
11800
12591
  const g = view.geometry;
11801
12592
  const hit = g.hit(x, y);
@@ -12146,12 +12937,12 @@ function paintCell(doc, node, item, zoom) {
12146
12937
  }
12147
12938
  }
12148
12939
  if (view.icon) {
12149
- const icon7 = svgNode(
12940
+ const icon9 = svgNode(
12150
12941
  doc,
12151
12942
  iconSvg(view.icon.set, view.icon.index, Math.round(16 * (zoom / 100)))
12152
12943
  );
12153
- icon7.setAttribute("class", "xg-ic");
12154
- node.append(icon7);
12944
+ icon9.setAttribute("class", "xg-ic");
12945
+ node.append(icon9);
12155
12946
  }
12156
12947
  if (item.text) {
12157
12948
  const box = h(doc, "div", "xg-t");
@@ -12779,8 +13570,8 @@ function wireTooltips(view) {
12779
13570
  tip.append(who, view.doc.createTextNode(reply.text));
12780
13571
  }
12781
13572
  } else if (link) {
12782
- const target24 = link.target ?? link.location ?? "";
12783
- tip.textContent = `${link.tooltip ?? target24}
13573
+ const target29 = link.target ?? link.location ?? "";
13574
+ tip.textContent = `${link.tooltip ?? target29}
12784
13575
  ${view.ctx.t("Ctrl+click to follow the link.")}`;
12785
13576
  }
12786
13577
  const g = view.geometry;
@@ -12815,8 +13606,8 @@ ${view.ctx.t("Ctrl+click to follow the link.")}`;
12815
13606
  tip.remove();
12816
13607
  };
12817
13608
  }
12818
- function workbookLocation(target24) {
12819
- const value = target24.trim();
13609
+ function workbookLocation(target29) {
13610
+ const value = target29.trim();
12820
13611
  if (value.startsWith("#")) return value.slice(1);
12821
13612
  return /^[a-z][a-z0-9+.-]+:/i.test(value) || /[\\/]/.test(value) ? void 0 : value;
12822
13613
  }
@@ -12846,13 +13637,13 @@ function goTo(view, selection, location) {
12846
13637
  if (!workbook) return false;
12847
13638
  const text3 = location.replace(/^#/, "");
12848
13639
  const name = workbook.definedNames.find((n) => n.name.toLowerCase() === text3.toLowerCase());
12849
- const target24 = referenceTarget(name ? name.formula : text3);
12850
- if (!target24) return false;
12851
- const sheetIndex = target24.sheet ? workbook.sheets.indexOf(sheetByName(workbook, target24.sheet)) : view.sheetIndex();
13640
+ const target29 = referenceTarget(name ? name.formula : text3);
13641
+ if (!target29) return false;
13642
+ const sheetIndex = target29.sheet ? workbook.sheets.indexOf(sheetByName(workbook, target29.sheet)) : view.sheetIndex();
12852
13643
  if (sheetIndex < 0) return false;
12853
13644
  if (sheetIndex !== view.sheetIndex()) view.ctx.setActiveSheet(sheetIndex);
12854
- const next = selectCell(sheetIndex, workbook.sheets[sheetIndex], target24.range.start);
12855
- selection.set({ ...next, ranges: [target24.range] }, target24.range.start);
13645
+ const next = selectCell(sheetIndex, workbook.sheets[sheetIndex], target29.range.start);
13646
+ selection.set({ ...next, ranges: [target29.range] }, target29.range.start);
12856
13647
  return true;
12857
13648
  }
12858
13649
 
@@ -13224,9 +14015,9 @@ function mountGrid(ctx, container) {
13224
14015
  selection,
13225
14016
  editor,
13226
14017
  followLink: (row2, col) => followLink(view, selection, row2, col),
13227
- fill(source, target24) {
13228
- ctx.session()?.fill(view.sheetIndex(), source, target24);
13229
- selection.set({ ...selection.get(), ranges: [target24] });
14018
+ fill(source, target29) {
14019
+ ctx.session()?.fill(view.sheetIndex(), source, target29);
14020
+ selection.set({ ...selection.get(), ranges: [target29] });
13230
14021
  }
13231
14022
  }),
13232
14023
  wireTooltips(view),
@@ -13415,10 +14206,10 @@ function createFormulaInput(ctx, doc, bar) {
13415
14206
  const onKey = (event) => {
13416
14207
  event.stopPropagation();
13417
14208
  if (assist.handleKey(event, field2)) return;
13418
- const editing7 = bridge.state().editing;
14209
+ const editing9 = bridge.state().editing;
13419
14210
  if (event.key === "Escape") {
13420
14211
  event.preventDefault();
13421
- if (editing7) bridge.cancel();
14212
+ if (editing9) bridge.cancel();
13422
14213
  else showCell();
13423
14214
  ctx.grid()?.focus();
13424
14215
  return;
@@ -13431,7 +14222,7 @@ function createFormulaInput(ctx, doc, bar) {
13431
14222
  onInput();
13432
14223
  return;
13433
14224
  }
13434
- if (!editing7) return;
14225
+ if (!editing9) return;
13435
14226
  if (event.key === "Enter") {
13436
14227
  event.preventDefault();
13437
14228
  if (event.ctrlKey || event.metaKey) bridge.commit("none", true);
@@ -14099,13 +14890,13 @@ function mountSheetTabs(ctx, container) {
14099
14890
  const visible = visibleSheetIndices(workbook);
14100
14891
  const at = visible.indexOf(sheet);
14101
14892
  const focusAt = (i) => {
14102
- const target25 = visible[Math.max(0, Math.min(visible.length - 1, i))];
14103
- if (target25 === void 0) return;
14104
- focusable = target25;
14893
+ const target30 = visible[Math.max(0, Math.min(visible.length - 1, i))];
14894
+ if (target30 === void 0) return;
14895
+ focusable = target30;
14105
14896
  for (const tab of strip.querySelectorAll(".xst-tab"))
14106
- tab.tabIndex = tab.dataset.sheet === String(target25) ? 0 : -1;
14107
- scrollIntoView(target25);
14108
- tabFor(strip, target25)?.focus();
14897
+ tab.tabIndex = tab.dataset.sheet === String(target30) ? 0 : -1;
14898
+ scrollIntoView(target30);
14899
+ tabFor(strip, target30)?.focus();
14109
14900
  };
14110
14901
  const moves = {
14111
14902
  ArrowLeft: at - 1,
@@ -14113,12 +14904,12 @@ function mountSheetTabs(ctx, container) {
14113
14904
  Home: 0,
14114
14905
  End: visible.length - 1
14115
14906
  };
14116
- const target24 = moves[event.key];
14907
+ const target29 = moves[event.key];
14117
14908
  const menuKey = event.key === "ContextMenu" || event.key === "F10" && event.shiftKey;
14118
- if (target24 === void 0 && !menuKey && !["Enter", " ", "F2"].includes(event.key)) return;
14909
+ if (target29 === void 0 && !menuKey && !["Enter", " ", "F2"].includes(event.key)) return;
14119
14910
  event.preventDefault();
14120
14911
  event.stopPropagation();
14121
- if (target24 !== void 0) focusAt(target24);
14912
+ if (target29 !== void 0) focusAt(target29);
14122
14913
  else if (event.key === "F2") rename(sheet);
14123
14914
  else if (menuKey) {
14124
14915
  const box = event.target.getBoundingClientRect();
@@ -14311,7 +15102,7 @@ function collectKeyTips(panel3) {
14311
15102
  };
14312
15103
  targets.push({ key: COMMAND_KEYS[labelOf(control)] ?? "", element: control, activate });
14313
15104
  }
14314
- assignKeyTips(targets, (target24) => target24.element.getAttribute("aria-label") ?? "");
15105
+ assignKeyTips(targets, (target29) => target29.element.getAttribute("aria-label") ?? "");
14315
15106
  return targets;
14316
15107
  }
14317
15108
  var runTips = (root, targets, onDone) => (
@@ -14329,7 +15120,7 @@ function showTabKeyTips(root, select2) {
14329
15120
  const id = panel3.dataset.tab ?? "";
14330
15121
  const tab = tabButton(root, id);
14331
15122
  if (!tab || isTabHidden(panel3)) continue;
14332
- const used = targets.map((target24) => target24.key);
15123
+ const used = targets.map((target29) => target29.key);
14333
15124
  let key = TAB_KEYS[id] ?? "";
14334
15125
  if (!key || used.includes(key))
14335
15126
  key = [...(tab.textContent ?? id).toUpperCase().replace(/[^A-Z]/g, "")].find(
@@ -14603,10 +15394,10 @@ function adjacentSheet(ctx, step2) {
14603
15394
  return void 0;
14604
15395
  }
14605
15396
  function shellCommands(handlers) {
14606
- const file = (id, label, command, icon7, shortcut) => ({
15397
+ const file = (id, label, command, icon9, shortcut) => ({
14607
15398
  id,
14608
15399
  label,
14609
- icon: icon7,
15400
+ icon: icon9,
14610
15401
  ...shortcut ? { shortcut } : {},
14611
15402
  enabled: (ctx) => command === "new" || command === "open" || hasWorkbook(ctx),
14612
15403
  run: () => handlers.fileCommand(command)
@@ -15164,9 +15955,9 @@ function buildShell(core) {
15164
15955
  if (action === "help") return help.open();
15165
15956
  if (action === "keytips") return ribbon.showKeyTips();
15166
15957
  if (action === "context-menu") {
15167
- const target24 = root.activeElement ?? gridHost;
15168
- const box = target24.getBoundingClientRect();
15169
- target24.dispatchEvent(
15958
+ const target29 = root.activeElement ?? gridHost;
15959
+ const box = target29.getBoundingClientRect();
15960
+ target29.dispatchEvent(
15170
15961
  new MouseEvent("contextmenu", {
15171
15962
  bubbles: true,
15172
15963
  composed: true,