@extend-ai/react-xlsx 0.13.3 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/dist/duke_sheets_wasm_bg.wasm +0 -0
- package/dist/index.cjs +874 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +133 -1
- package/dist/index.d.ts +133 -1
- package/dist/index.js +874 -84
- package/dist/index.js.map +1 -1
- package/dist/xlsx-worker.js +128 -0
- package/dist/xlsx-worker.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -3642,7 +3642,6 @@ var SPREADSHEET_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
|
3642
3642
|
var CONTENT_TYPES_NS = "http://schemas.openxmlformats.org/package/2006/content-types";
|
|
3643
3643
|
var DRAWING_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
|
|
3644
3644
|
var VML_DRAWING_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing";
|
|
3645
|
-
var CTRL_PROP_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp";
|
|
3646
3645
|
var IMAGE_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
|
|
3647
3646
|
var DRAWING_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.drawing+xml";
|
|
3648
3647
|
var EMU_PER_PIXEL2 = 9525;
|
|
@@ -5085,6 +5084,124 @@ function parseSpreadsheetBooleanNode(node) {
|
|
|
5085
5084
|
}
|
|
5086
5085
|
return parseSpreadsheetBooleanValue(node.getAttribute("val") ?? node.textContent);
|
|
5087
5086
|
}
|
|
5087
|
+
function mapDukeFormControlAnchor(anchor) {
|
|
5088
|
+
return {
|
|
5089
|
+
from: {
|
|
5090
|
+
col: anchor.fromCol,
|
|
5091
|
+
colOffsetEmu: anchor.fromColOffset,
|
|
5092
|
+
row: anchor.fromRow,
|
|
5093
|
+
rowOffsetEmu: anchor.fromRowOffset
|
|
5094
|
+
},
|
|
5095
|
+
kind: "two-cell",
|
|
5096
|
+
to: {
|
|
5097
|
+
col: anchor.toCol,
|
|
5098
|
+
colOffsetEmu: anchor.toColOffset,
|
|
5099
|
+
row: anchor.toRow,
|
|
5100
|
+
rowOffsetEmu: anchor.toRowOffset
|
|
5101
|
+
}
|
|
5102
|
+
};
|
|
5103
|
+
}
|
|
5104
|
+
function mapDukeFormControlKind(kind) {
|
|
5105
|
+
switch (kind.kind) {
|
|
5106
|
+
case "button":
|
|
5107
|
+
return { caption: kind.caption, kind: "button", label: normalizeControlLabel(kind.caption) };
|
|
5108
|
+
case "checkbox":
|
|
5109
|
+
return {
|
|
5110
|
+
caption: kind.caption,
|
|
5111
|
+
checked: kind.state === "checked",
|
|
5112
|
+
kind: "checkbox",
|
|
5113
|
+
label: normalizeControlLabel(kind.caption),
|
|
5114
|
+
linkedCell: kind.cellLink,
|
|
5115
|
+
no3D: kind.no3D,
|
|
5116
|
+
state: kind.state
|
|
5117
|
+
};
|
|
5118
|
+
case "optionButton":
|
|
5119
|
+
return {
|
|
5120
|
+
caption: kind.caption,
|
|
5121
|
+
checked: kind.state === "checked",
|
|
5122
|
+
firstInGroup: kind.firstInGroup,
|
|
5123
|
+
kind: "radio",
|
|
5124
|
+
label: normalizeControlLabel(kind.caption),
|
|
5125
|
+
linkedCell: kind.cellLink,
|
|
5126
|
+
no3D: kind.no3D,
|
|
5127
|
+
state: kind.state
|
|
5128
|
+
};
|
|
5129
|
+
case "label":
|
|
5130
|
+
return { caption: kind.caption, kind: "label", label: normalizeControlLabel(kind.caption) };
|
|
5131
|
+
case "groupBox":
|
|
5132
|
+
return {
|
|
5133
|
+
caption: kind.caption,
|
|
5134
|
+
kind: "group-box",
|
|
5135
|
+
label: normalizeControlLabel(kind.caption),
|
|
5136
|
+
no3D: kind.no3D
|
|
5137
|
+
};
|
|
5138
|
+
case "listBox":
|
|
5139
|
+
return {
|
|
5140
|
+
inputRange: kind.inputRange,
|
|
5141
|
+
kind: "listbox",
|
|
5142
|
+
linkedCell: kind.cellLink,
|
|
5143
|
+
no3D: kind.no3D,
|
|
5144
|
+
selected: [...kind.selected],
|
|
5145
|
+
selection: kind.selection
|
|
5146
|
+
};
|
|
5147
|
+
case "dropdown":
|
|
5148
|
+
return {
|
|
5149
|
+
inputRange: kind.inputRange,
|
|
5150
|
+
kind: "dropdown",
|
|
5151
|
+
lines: kind.lines,
|
|
5152
|
+
linkedCell: kind.cellLink,
|
|
5153
|
+
no3D: kind.no3D,
|
|
5154
|
+
selected: kind.selected
|
|
5155
|
+
};
|
|
5156
|
+
case "scrollbar":
|
|
5157
|
+
return {
|
|
5158
|
+
horizontal: kind.horizontal,
|
|
5159
|
+
increment: kind.increment,
|
|
5160
|
+
kind: "scrollbar",
|
|
5161
|
+
linkedCell: kind.cellLink,
|
|
5162
|
+
max: kind.max,
|
|
5163
|
+
min: kind.min,
|
|
5164
|
+
page: kind.page,
|
|
5165
|
+
value: kind.value
|
|
5166
|
+
};
|
|
5167
|
+
case "spinner":
|
|
5168
|
+
return {
|
|
5169
|
+
increment: kind.increment,
|
|
5170
|
+
kind: "spinner",
|
|
5171
|
+
linkedCell: kind.cellLink,
|
|
5172
|
+
max: kind.max,
|
|
5173
|
+
min: kind.min,
|
|
5174
|
+
value: kind.value
|
|
5175
|
+
};
|
|
5176
|
+
}
|
|
5177
|
+
}
|
|
5178
|
+
function mapDukeFormControl(control, controlIndex, workbookSheetIndex) {
|
|
5179
|
+
return {
|
|
5180
|
+
anchor: mapDukeFormControlAnchor(control.anchor),
|
|
5181
|
+
controlIndex,
|
|
5182
|
+
dukeAnchor: { ...control.anchor },
|
|
5183
|
+
editAs: control.anchor.editAs,
|
|
5184
|
+
hidden: false,
|
|
5185
|
+
id: `form-control-${workbookSheetIndex}-${controlIndex}`,
|
|
5186
|
+
locked: control.locked,
|
|
5187
|
+
name: control.name,
|
|
5188
|
+
printable: control.printable,
|
|
5189
|
+
sheetIndex: workbookSheetIndex,
|
|
5190
|
+
workbookSheetIndex,
|
|
5191
|
+
zIndex: controlIndex + 1,
|
|
5192
|
+
...mapDukeFormControlKind(control.kind)
|
|
5193
|
+
};
|
|
5194
|
+
}
|
|
5195
|
+
function collectWorkbookFormControls(workbook) {
|
|
5196
|
+
return Array.from({ length: workbook.sheetCount }, (_, workbookSheetIndex) => {
|
|
5197
|
+
try {
|
|
5198
|
+
const controls = workbook.getSheet(workbookSheetIndex).formControls;
|
|
5199
|
+
return Array.isArray(controls) ? controls.map((control, controlIndex) => mapDukeFormControl(control, controlIndex, workbookSheetIndex)) : [];
|
|
5200
|
+
} catch {
|
|
5201
|
+
return [];
|
|
5202
|
+
}
|
|
5203
|
+
});
|
|
5204
|
+
}
|
|
5088
5205
|
function parseFormControlKind(rawType) {
|
|
5089
5206
|
const normalized = (rawType ?? "").trim().toLowerCase();
|
|
5090
5207
|
switch (normalized) {
|
|
@@ -5850,27 +5967,10 @@ function parseSheetFormControlNodes(archive, sheetPath) {
|
|
|
5850
5967
|
}
|
|
5851
5968
|
return getLocalElements(sheetDocument, "control").map((controlNode) => ({
|
|
5852
5969
|
anchor: parseAnchor(getFirstDescendant(controlNode, "anchor") ?? controlNode),
|
|
5853
|
-
controlRelationshipId: getRelationshipId(controlNode),
|
|
5854
5970
|
name: controlNode.getAttribute("name") ?? void 0,
|
|
5855
5971
|
shapeId: parseFormControlShapeId(controlNode.getAttribute("shapeId"))
|
|
5856
5972
|
}));
|
|
5857
5973
|
}
|
|
5858
|
-
function parseCtrlPropDocument(archive, ctrlPropPath) {
|
|
5859
|
-
const xml = readArchiveText2(archive, ctrlPropPath);
|
|
5860
|
-
if (!xml) {
|
|
5861
|
-
return null;
|
|
5862
|
-
}
|
|
5863
|
-
const document2 = parseXml2(xml);
|
|
5864
|
-
const root = document2?.documentElement;
|
|
5865
|
-
if (!root) {
|
|
5866
|
-
return null;
|
|
5867
|
-
}
|
|
5868
|
-
return {
|
|
5869
|
-
checked: parseSpreadsheetBooleanValue(root.getAttribute("checked")),
|
|
5870
|
-
linkedCell: root.getAttribute("fmlaLink") ?? void 0,
|
|
5871
|
-
objectType: root.getAttribute("objectType") ?? void 0
|
|
5872
|
-
};
|
|
5873
|
-
}
|
|
5874
5974
|
function parseVmlFormControls(archive, vmlDrawingPath) {
|
|
5875
5975
|
const xml = readArchiveText2(archive, vmlDrawingPath);
|
|
5876
5976
|
if (!xml) {
|
|
@@ -5928,21 +6028,18 @@ function parseSheetFormControls(archive, sheetPath, sheetRelationships, workbook
|
|
|
5928
6028
|
if (!controlNode.anchor) {
|
|
5929
6029
|
return;
|
|
5930
6030
|
}
|
|
5931
|
-
const ctrlPropRelationship = controlNode.controlRelationshipId ? sheetRelationships.get(controlNode.controlRelationshipId) ?? null : null;
|
|
5932
|
-
const ctrlPropPath = ctrlPropRelationship?.type === CTRL_PROP_REL_TYPE ? ctrlPropRelationship.target : null;
|
|
5933
|
-
const ctrlProp = ctrlPropPath ? parseCtrlPropDocument(archive, ctrlPropPath) : null;
|
|
5934
6031
|
const vmlControl = controlNode.shapeId !== null ? vmlControlsByShapeId.get(controlNode.shapeId) ?? null : null;
|
|
5935
|
-
const kind = parseFormControlKind(
|
|
6032
|
+
const kind = parseFormControlKind(vmlControl?.objectType);
|
|
5936
6033
|
parsedControls.push({
|
|
5937
6034
|
anchor: controlNode.anchor,
|
|
5938
|
-
checked:
|
|
6035
|
+
checked: vmlControl?.checked,
|
|
5939
6036
|
fontFamily: vmlControl?.fontFamily,
|
|
5940
6037
|
fontSizePt: vmlControl?.fontSizePt,
|
|
5941
6038
|
hidden: vmlControl?.hidden ?? false,
|
|
5942
6039
|
id: `form-control-${workbookSheetIndex}-${index}`,
|
|
5943
6040
|
kind,
|
|
5944
6041
|
label: vmlControl?.label,
|
|
5945
|
-
linkedCell:
|
|
6042
|
+
linkedCell: vmlControl?.linkedCell,
|
|
5946
6043
|
name: controlNode.name,
|
|
5947
6044
|
sheetIndex: workbookSheetIndex,
|
|
5948
6045
|
textAlign: vmlControl?.textAlign,
|
|
@@ -6028,6 +6125,92 @@ function enrichFormControlsWithHiddenShapes(formControls, shapes, sheetState) {
|
|
|
6028
6125
|
};
|
|
6029
6126
|
});
|
|
6030
6127
|
}
|
|
6128
|
+
function getFormControlAnchorStart(anchor) {
|
|
6129
|
+
return anchor.kind === "absolute" ? null : { col: anchor.from.col, row: anchor.from.row };
|
|
6130
|
+
}
|
|
6131
|
+
function scoreParsedFormControlMatch(dukeControl, parsedControl, parsedIndex) {
|
|
6132
|
+
if (dukeControl.kind !== parsedControl.kind && parsedControl.kind !== "unknown") {
|
|
6133
|
+
return Number.NEGATIVE_INFINITY;
|
|
6134
|
+
}
|
|
6135
|
+
let score = 10;
|
|
6136
|
+
const dukeName = normalizeControlLabel(dukeControl.name)?.toLowerCase();
|
|
6137
|
+
const parsedName = normalizeControlLabel(parsedControl.name)?.toLowerCase();
|
|
6138
|
+
if (dukeName && parsedName) {
|
|
6139
|
+
if (dukeName !== parsedName) {
|
|
6140
|
+
return Number.NEGATIVE_INFINITY;
|
|
6141
|
+
}
|
|
6142
|
+
score += 100;
|
|
6143
|
+
}
|
|
6144
|
+
const dukeStart = getFormControlAnchorStart(dukeControl.anchor);
|
|
6145
|
+
const parsedStart = getFormControlAnchorStart(parsedControl.anchor);
|
|
6146
|
+
if (dukeStart && parsedStart && dukeStart.col === parsedStart.col && dukeStart.row === parsedStart.row) {
|
|
6147
|
+
score += 40;
|
|
6148
|
+
}
|
|
6149
|
+
if (dukeControl.controlIndex === parsedIndex) {
|
|
6150
|
+
score += 5;
|
|
6151
|
+
}
|
|
6152
|
+
return score;
|
|
6153
|
+
}
|
|
6154
|
+
function areDukeFormControlAnchorsEqual(left, right) {
|
|
6155
|
+
if (!left || !right) {
|
|
6156
|
+
return true;
|
|
6157
|
+
}
|
|
6158
|
+
return left.editAs === right.editAs && left.fromCol === right.fromCol && left.fromColOffset === right.fromColOffset && left.fromRow === right.fromRow && left.fromRowOffset === right.fromRowOffset && left.toCol === right.toCol && left.toColOffset === right.toColOffset && left.toRow === right.toRow && left.toRowOffset === right.toRowOffset;
|
|
6159
|
+
}
|
|
6160
|
+
function mergeDukeAndParsedFormControls(dukeControls, parsedControls, keepUnmatchedParsedControl = () => true) {
|
|
6161
|
+
const usedParsedIndexes = /* @__PURE__ */ new Set();
|
|
6162
|
+
const mergedControls = dukeControls.map((dukeControl) => {
|
|
6163
|
+
let bestIndex = -1;
|
|
6164
|
+
let bestScore = Number.NEGATIVE_INFINITY;
|
|
6165
|
+
parsedControls.forEach((parsedControl2, parsedIndex) => {
|
|
6166
|
+
if (usedParsedIndexes.has(parsedIndex)) {
|
|
6167
|
+
return;
|
|
6168
|
+
}
|
|
6169
|
+
const score = scoreParsedFormControlMatch(dukeControl, parsedControl2, parsedIndex);
|
|
6170
|
+
if (score > bestScore) {
|
|
6171
|
+
bestIndex = parsedIndex;
|
|
6172
|
+
bestScore = score;
|
|
6173
|
+
}
|
|
6174
|
+
});
|
|
6175
|
+
const parsedControl = bestIndex >= 0 && bestScore >= 10 ? parsedControls[bestIndex] : null;
|
|
6176
|
+
if (!parsedControl) {
|
|
6177
|
+
return dukeControl;
|
|
6178
|
+
}
|
|
6179
|
+
usedParsedIndexes.add(bestIndex);
|
|
6180
|
+
const dukeAnchorChanged = !areDukeFormControlAnchorsEqual(
|
|
6181
|
+
parsedControl.dukeAnchor,
|
|
6182
|
+
dukeControl.dukeAnchor
|
|
6183
|
+
);
|
|
6184
|
+
return {
|
|
6185
|
+
...parsedControl,
|
|
6186
|
+
...dukeControl,
|
|
6187
|
+
anchor: dukeAnchorChanged ? dukeControl.anchor : parsedControl.anchor,
|
|
6188
|
+
fontFamily: parsedControl.fontFamily,
|
|
6189
|
+
fontSizePt: parsedControl.fontSizePt,
|
|
6190
|
+
hidden: parsedControl.hidden,
|
|
6191
|
+
id: parsedControl.id,
|
|
6192
|
+
label: dukeControl.label ?? parsedControl.label,
|
|
6193
|
+
name: dukeControl.name ?? parsedControl.name,
|
|
6194
|
+
textAlign: parsedControl.textAlign,
|
|
6195
|
+
textColor: parsedControl.textColor,
|
|
6196
|
+
zIndex: parsedControl.zIndex
|
|
6197
|
+
};
|
|
6198
|
+
});
|
|
6199
|
+
parsedControls.forEach((parsedControl, parsedIndex) => {
|
|
6200
|
+
if (!usedParsedIndexes.has(parsedIndex) && keepUnmatchedParsedControl(parsedControl)) {
|
|
6201
|
+
mergedControls.push(parsedControl);
|
|
6202
|
+
}
|
|
6203
|
+
});
|
|
6204
|
+
return mergedControls.sort((left, right) => left.zIndex - right.zIndex);
|
|
6205
|
+
}
|
|
6206
|
+
function refreshWorkbookFormControls(workbook, currentControlsByWorkbookSheetIndex) {
|
|
6207
|
+
const dukeControlsByWorkbookSheetIndex = collectWorkbookFormControls(workbook);
|
|
6208
|
+
return dukeControlsByWorkbookSheetIndex.map((dukeControls, workbookSheetIndex) => mergeDukeAndParsedFormControls(
|
|
6209
|
+
dukeControls,
|
|
6210
|
+
currentControlsByWorkbookSheetIndex[workbookSheetIndex] ?? [],
|
|
6211
|
+
(control) => control.controlIndex === void 0
|
|
6212
|
+
));
|
|
6213
|
+
}
|
|
6031
6214
|
function revokeWorkbookImageAssets(assets) {
|
|
6032
6215
|
if (!assets) {
|
|
6033
6216
|
return;
|
|
@@ -6060,7 +6243,7 @@ function parseWorkbookStructureAssetsFromArchive(archive, options) {
|
|
|
6060
6243
|
workbookSheets
|
|
6061
6244
|
};
|
|
6062
6245
|
}
|
|
6063
|
-
function parseWorkbookImageAssets(bytes) {
|
|
6246
|
+
function parseWorkbookImageAssets(bytes, workbook) {
|
|
6064
6247
|
const archive = (0, import_fflate2.unzipSync)(bytes);
|
|
6065
6248
|
const {
|
|
6066
6249
|
contentTypes,
|
|
@@ -6079,6 +6262,7 @@ function parseWorkbookImageAssets(bytes) {
|
|
|
6079
6262
|
const shapesByWorkbookSheetIndex = [];
|
|
6080
6263
|
const sheetOrigins = [];
|
|
6081
6264
|
const imageOriginsById = /* @__PURE__ */ new Map();
|
|
6265
|
+
const dukeFormControlsByWorkbookSheetIndex = collectWorkbookFormControls(workbook);
|
|
6082
6266
|
workbookSheets.forEach((sheet, workbookSheetIndex) => {
|
|
6083
6267
|
const sheetRelationships = parseRelationships(archive, relsPathForDocument(sheet.path), sheet.path);
|
|
6084
6268
|
const attachments = [];
|
|
@@ -6124,7 +6308,10 @@ function parseWorkbookImageAssets(bytes) {
|
|
|
6124
6308
|
shapeList,
|
|
6125
6309
|
sheetStatesByWorkbookSheetIndex[workbookSheetIndex] ?? null
|
|
6126
6310
|
);
|
|
6127
|
-
formControlsByWorkbookSheetIndex[workbookSheetIndex] =
|
|
6311
|
+
formControlsByWorkbookSheetIndex[workbookSheetIndex] = mergeDukeAndParsedFormControls(
|
|
6312
|
+
dukeFormControlsByWorkbookSheetIndex[workbookSheetIndex] ?? [],
|
|
6313
|
+
enrichedFormControlList
|
|
6314
|
+
);
|
|
6128
6315
|
imagesByWorkbookSheetIndex[workbookSheetIndex] = imageList;
|
|
6129
6316
|
shapesByWorkbookSheetIndex[workbookSheetIndex] = visibleShapeList;
|
|
6130
6317
|
sheetOrigins[workbookSheetIndex] = attachments.length > 0 ? {
|
|
@@ -7199,6 +7386,144 @@ function parseA1RangeReference2(reference) {
|
|
|
7199
7386
|
}
|
|
7200
7387
|
return normalizeRange({ start, end });
|
|
7201
7388
|
}
|
|
7389
|
+
function resolveWorkbookReference(workbook, defaultWorkbookSheetIndex, rawReference, resolvingNamedRange = false) {
|
|
7390
|
+
const reference = rawReference.trim().replace(/^=/, "");
|
|
7391
|
+
if (!reference) {
|
|
7392
|
+
return null;
|
|
7393
|
+
}
|
|
7394
|
+
let workbookSheetIndex = defaultWorkbookSheetIndex;
|
|
7395
|
+
let rangeReference = reference;
|
|
7396
|
+
const bangIndex = reference.lastIndexOf("!");
|
|
7397
|
+
if (bangIndex >= 0) {
|
|
7398
|
+
let sheetName = reference.slice(0, bangIndex).trim();
|
|
7399
|
+
rangeReference = reference.slice(bangIndex + 1).trim();
|
|
7400
|
+
if (sheetName.startsWith("'") && sheetName.endsWith("'")) {
|
|
7401
|
+
sheetName = sheetName.slice(1, -1).replace(/''/g, "'");
|
|
7402
|
+
}
|
|
7403
|
+
const resolvedSheetIndex = workbook.sheetIndex(sheetName);
|
|
7404
|
+
if (resolvedSheetIndex === void 0) {
|
|
7405
|
+
return null;
|
|
7406
|
+
}
|
|
7407
|
+
workbookSheetIndex = resolvedSheetIndex;
|
|
7408
|
+
} else if (!resolvingNamedRange) {
|
|
7409
|
+
const namedRange = workbook.getNamedRange(reference);
|
|
7410
|
+
if (namedRange) {
|
|
7411
|
+
return resolveWorkbookReference(workbook, defaultWorkbookSheetIndex, namedRange, true);
|
|
7412
|
+
}
|
|
7413
|
+
}
|
|
7414
|
+
const range = parseA1RangeReference2(rangeReference.replace(/\$/g, ""));
|
|
7415
|
+
if (!range || workbookSheetIndex < 0 || workbookSheetIndex >= workbook.sheetCount) {
|
|
7416
|
+
return null;
|
|
7417
|
+
}
|
|
7418
|
+
try {
|
|
7419
|
+
return {
|
|
7420
|
+
range,
|
|
7421
|
+
workbookSheetIndex,
|
|
7422
|
+
worksheet: workbook.getSheet(workbookSheetIndex)
|
|
7423
|
+
};
|
|
7424
|
+
} catch {
|
|
7425
|
+
return null;
|
|
7426
|
+
}
|
|
7427
|
+
}
|
|
7428
|
+
function formControlInputFromDukeControl(control) {
|
|
7429
|
+
return {
|
|
7430
|
+
anchor: { ...control.anchor },
|
|
7431
|
+
kind: { ...control.kind },
|
|
7432
|
+
locked: control.locked,
|
|
7433
|
+
name: control.name,
|
|
7434
|
+
printable: control.printable
|
|
7435
|
+
};
|
|
7436
|
+
}
|
|
7437
|
+
function getFormControlCellLink(kind) {
|
|
7438
|
+
return "cellLink" in kind ? kind.cellLink : void 0;
|
|
7439
|
+
}
|
|
7440
|
+
function anchorContainsControl(group, control) {
|
|
7441
|
+
const groupAnchor = group.anchor;
|
|
7442
|
+
const controlAnchor = control.anchor;
|
|
7443
|
+
return controlAnchor.fromCol >= groupAnchor.fromCol && controlAnchor.fromCol <= groupAnchor.toCol && controlAnchor.fromRow >= groupAnchor.fromRow && controlAnchor.fromRow <= groupAnchor.toRow;
|
|
7444
|
+
}
|
|
7445
|
+
function resolveOptionButtonGroupIndexes(controls, targetIndex) {
|
|
7446
|
+
const target = controls[targetIndex];
|
|
7447
|
+
if (!target || target.kind.kind !== "optionButton") {
|
|
7448
|
+
return [];
|
|
7449
|
+
}
|
|
7450
|
+
if (target.kind.cellLink) {
|
|
7451
|
+
const targetCellLink = target.kind.cellLink;
|
|
7452
|
+
return controls.flatMap((control, index) => control.kind.kind === "optionButton" && control.kind.cellLink === targetCellLink ? [index] : []);
|
|
7453
|
+
}
|
|
7454
|
+
const containingGroups = controls.map((control, index) => ({ control, index })).filter(({ control }) => control.kind.kind === "groupBox" && anchorContainsControl(control, target)).sort((left, right) => {
|
|
7455
|
+
const leftArea = (left.control.anchor.toCol - left.control.anchor.fromCol) * (left.control.anchor.toRow - left.control.anchor.fromRow);
|
|
7456
|
+
const rightArea = (right.control.anchor.toCol - right.control.anchor.fromCol) * (right.control.anchor.toRow - right.control.anchor.fromRow);
|
|
7457
|
+
return leftArea - rightArea;
|
|
7458
|
+
});
|
|
7459
|
+
const containingGroup = containingGroups[0]?.control;
|
|
7460
|
+
if (containingGroup) {
|
|
7461
|
+
return controls.flatMap((control, index) => control.kind.kind === "optionButton" && anchorContainsControl(containingGroup, control) ? [index] : []);
|
|
7462
|
+
}
|
|
7463
|
+
const optionIndexes = controls.flatMap((control, index) => control.kind.kind === "optionButton" ? [index] : []);
|
|
7464
|
+
const targetPosition = optionIndexes.indexOf(targetIndex);
|
|
7465
|
+
if (targetPosition < 0) {
|
|
7466
|
+
return [];
|
|
7467
|
+
}
|
|
7468
|
+
let startPosition = targetPosition;
|
|
7469
|
+
while (startPosition > 0) {
|
|
7470
|
+
const control = controls[optionIndexes[startPosition] ?? -1];
|
|
7471
|
+
if (control?.kind.kind === "optionButton" && control.kind.firstInGroup) {
|
|
7472
|
+
break;
|
|
7473
|
+
}
|
|
7474
|
+
startPosition -= 1;
|
|
7475
|
+
}
|
|
7476
|
+
let endPosition = targetPosition + 1;
|
|
7477
|
+
while (endPosition < optionIndexes.length) {
|
|
7478
|
+
const control = controls[optionIndexes[endPosition] ?? -1];
|
|
7479
|
+
if (control?.kind.kind === "optionButton" && control.kind.firstInGroup) {
|
|
7480
|
+
break;
|
|
7481
|
+
}
|
|
7482
|
+
endPosition += 1;
|
|
7483
|
+
}
|
|
7484
|
+
return optionIndexes.slice(startPosition, endPosition);
|
|
7485
|
+
}
|
|
7486
|
+
function resolveLinkedCellValue(controls, controlIndex) {
|
|
7487
|
+
const control = controls[controlIndex];
|
|
7488
|
+
if (!control) {
|
|
7489
|
+
return void 0;
|
|
7490
|
+
}
|
|
7491
|
+
switch (control.kind.kind) {
|
|
7492
|
+
case "checkbox":
|
|
7493
|
+
return control.kind.state === "mixed" ? "#N/A" : control.kind.state === "checked";
|
|
7494
|
+
case "optionButton": {
|
|
7495
|
+
const groupIndexes = resolveOptionButtonGroupIndexes(controls, controlIndex);
|
|
7496
|
+
const checkedIndex = groupIndexes.find((index) => controls[index]?.kind.kind === "optionButton" && controls[index]?.kind.state === "checked");
|
|
7497
|
+
const groupPosition = checkedIndex === void 0 ? -1 : groupIndexes.indexOf(checkedIndex);
|
|
7498
|
+
return groupPosition >= 0 ? groupPosition + 1 : "";
|
|
7499
|
+
}
|
|
7500
|
+
case "dropdown":
|
|
7501
|
+
return control.kind.selected === void 0 ? "" : control.kind.selected + 1;
|
|
7502
|
+
case "listBox":
|
|
7503
|
+
return control.kind.selection === "single" && control.kind.selected.length === 1 ? (control.kind.selected[0] ?? -1) + 1 : "";
|
|
7504
|
+
case "scrollbar":
|
|
7505
|
+
case "spinner":
|
|
7506
|
+
return control.kind.value;
|
|
7507
|
+
default:
|
|
7508
|
+
return void 0;
|
|
7509
|
+
}
|
|
7510
|
+
}
|
|
7511
|
+
function syncFormControlLinkedCell(workbook, workbookSheetIndex, controls, controlIndex) {
|
|
7512
|
+
const control = controls[controlIndex];
|
|
7513
|
+
if (!control) {
|
|
7514
|
+
return;
|
|
7515
|
+
}
|
|
7516
|
+
const cellLink = getFormControlCellLink(control.kind);
|
|
7517
|
+
const value = resolveLinkedCellValue(controls, controlIndex);
|
|
7518
|
+
if (!cellLink || value === void 0) {
|
|
7519
|
+
return;
|
|
7520
|
+
}
|
|
7521
|
+
const target = resolveWorkbookReference(workbook, workbookSheetIndex, cellLink);
|
|
7522
|
+
if (!target || target.range.start.row !== target.range.end.row || target.range.start.col !== target.range.end.col) {
|
|
7523
|
+
return;
|
|
7524
|
+
}
|
|
7525
|
+
target.worksheet.setCell(cellAddressToA1(target.range.start), value);
|
|
7526
|
+
}
|
|
7202
7527
|
function parseWorksheetFreezePanes(worksheet) {
|
|
7203
7528
|
const rawFreezePanes = worksheet.freezePanes;
|
|
7204
7529
|
const row = typeof rawFreezePanes?.row === "number" && rawFreezePanes.row >= 0 ? rawFreezePanes.row : null;
|
|
@@ -7965,7 +8290,7 @@ function createBasicWorkbookAssets(workbook) {
|
|
|
7965
8290
|
const objectUrls = [];
|
|
7966
8291
|
return {
|
|
7967
8292
|
archive: {},
|
|
7968
|
-
formControlsByWorkbookSheetIndex:
|
|
8293
|
+
formControlsByWorkbookSheetIndex: collectWorkbookFormControls(workbook),
|
|
7969
8294
|
imageOriginsById: /* @__PURE__ */ new Map(),
|
|
7970
8295
|
imagesByWorkbookSheetIndex: collectWorksheetApiImages(workbook, objectUrls),
|
|
7971
8296
|
namedCellStyleByName: {},
|
|
@@ -7983,7 +8308,7 @@ function loadWorkbookImageAssets(bytes, workbook, skipXmlParsing = false) {
|
|
|
7983
8308
|
if (shouldSkipXmlParsingForWorkbook(bytes, skipXmlParsing) || !isZipWorkbook(bytes)) {
|
|
7984
8309
|
return createBasicWorkbookAssets(workbook);
|
|
7985
8310
|
}
|
|
7986
|
-
const parsedAssets = parseWorkbookImageAssets(bytes);
|
|
8311
|
+
const parsedAssets = parseWorkbookImageAssets(bytes, workbook);
|
|
7987
8312
|
const apiImagesByWorkbookSheetIndex = collectWorksheetApiImages(workbook, parsedAssets.objectUrls);
|
|
7988
8313
|
const imagesByWorkbookSheetIndex = Array.from(
|
|
7989
8314
|
{ length: Math.max(workbook.sheetCount, parsedAssets.imagesByWorkbookSheetIndex.length, apiImagesByWorkbookSheetIndex.length) },
|
|
@@ -8300,6 +8625,12 @@ function useXlsxViewerController(options) {
|
|
|
8300
8625
|
};
|
|
8301
8626
|
}, [skipXmlParsing]);
|
|
8302
8627
|
const refreshWorkbookState = React.useCallback((targetWorkbook) => {
|
|
8628
|
+
const currentFormControls = imageAssetsRef.current?.formControlsByWorkbookSheetIndex ?? [];
|
|
8629
|
+
const nextFormControls = refreshWorkbookFormControls(targetWorkbook, currentFormControls);
|
|
8630
|
+
if (imageAssetsRef.current) {
|
|
8631
|
+
imageAssetsRef.current.formControlsByWorkbookSheetIndex = nextFormControls;
|
|
8632
|
+
}
|
|
8633
|
+
setFormControlsByWorkbookSheetIndex(nextFormControls);
|
|
8303
8634
|
const nextSheets = buildSheetList(
|
|
8304
8635
|
targetWorkbook,
|
|
8305
8636
|
imageAssetsRef.current?.sheetStatesByWorkbookSheetIndex,
|
|
@@ -8427,6 +8758,7 @@ function useXlsxViewerController(options) {
|
|
|
8427
8758
|
setChartsheets(snapshot.chartsheets);
|
|
8428
8759
|
setTabs(snapshot.tabs);
|
|
8429
8760
|
chartAssetsRef.current = null;
|
|
8761
|
+
setFormControlsByWorkbookSheetIndex(snapshot.formControlsByWorkbookSheetIndex);
|
|
8430
8762
|
setWorkerTablesByWorkbookSheetIndex(snapshot.tablesByWorkbookSheetIndex);
|
|
8431
8763
|
setShouldAutoCalculate(false);
|
|
8432
8764
|
setIsWorkerBacked(true);
|
|
@@ -8646,6 +8978,7 @@ function useXlsxViewerController(options) {
|
|
|
8646
8978
|
setChartsheets(snapshot.chartsheets);
|
|
8647
8979
|
setTabs(snapshot.tabs);
|
|
8648
8980
|
chartAssetsRef.current = null;
|
|
8981
|
+
setFormControlsByWorkbookSheetIndex(snapshot.formControlsByWorkbookSheetIndex);
|
|
8649
8982
|
setWorkerTablesByWorkbookSheetIndex(snapshot.tablesByWorkbookSheetIndex);
|
|
8650
8983
|
setShouldAutoCalculate(false);
|
|
8651
8984
|
setIsWorkerBacked(true);
|
|
@@ -8767,6 +9100,20 @@ function useXlsxViewerController(options) {
|
|
|
8767
9100
|
}
|
|
8768
9101
|
return workbook.getSheet(activeSheet.workbookSheetIndex);
|
|
8769
9102
|
}, [activeSheet, workbook]);
|
|
9103
|
+
const getFormControlWorksheet = React.useCallback((sheetIndex = activeSheetIndex) => {
|
|
9104
|
+
const targetSheet = sheets[sheetIndex];
|
|
9105
|
+
if (!workbook || !targetSheet) {
|
|
9106
|
+
return null;
|
|
9107
|
+
}
|
|
9108
|
+
try {
|
|
9109
|
+
return {
|
|
9110
|
+
workbookSheetIndex: targetSheet.workbookSheetIndex,
|
|
9111
|
+
worksheet: workbook.getSheet(targetSheet.workbookSheetIndex)
|
|
9112
|
+
};
|
|
9113
|
+
} catch {
|
|
9114
|
+
return null;
|
|
9115
|
+
}
|
|
9116
|
+
}, [activeSheetIndex, sheets, workbook]);
|
|
8770
9117
|
const tables = React.useMemo(
|
|
8771
9118
|
() => isWorkerBacked ? workerTablesByWorkbookSheetIndex[activeSheet?.workbookSheetIndex ?? -1] ?? [] : mapWorksheetTables(getActiveWorksheet()),
|
|
8772
9119
|
[activeSheet?.workbookSheetIndex, getActiveWorksheet, isWorkerBacked, revision, workerTablesByWorkbookSheetIndex]
|
|
@@ -8906,6 +9253,28 @@ function useXlsxViewerController(options) {
|
|
|
8906
9253
|
return (formControlsByWorkbookSheetIndex[targetSheet.workbookSheetIndex] ?? []).map(mapPublicFormControl);
|
|
8907
9254
|
}, [activeSheetIndex, formControlsByWorkbookSheetIndex, mapPublicFormControl, sheets]);
|
|
8908
9255
|
const formControls = React.useMemo(() => getSheetFormControls(activeSheetIndex), [activeSheetIndex, getSheetFormControls]);
|
|
9256
|
+
const getFormControlItems = React.useCallback((controlIndex, sheetIndex = activeSheetIndex) => {
|
|
9257
|
+
const target = getFormControlWorksheet(sheetIndex);
|
|
9258
|
+
if (!workbook || !target) {
|
|
9259
|
+
return [];
|
|
9260
|
+
}
|
|
9261
|
+
const control = target.worksheet.formControls[controlIndex];
|
|
9262
|
+
const inputRange = control?.kind.kind === "listBox" || control?.kind.kind === "dropdown" ? control.kind.inputRange : void 0;
|
|
9263
|
+
if (!inputRange) {
|
|
9264
|
+
return [];
|
|
9265
|
+
}
|
|
9266
|
+
const source = resolveWorkbookReference(workbook, target.workbookSheetIndex, inputRange);
|
|
9267
|
+
if (!source) {
|
|
9268
|
+
return [];
|
|
9269
|
+
}
|
|
9270
|
+
const items = [];
|
|
9271
|
+
for (let row = source.range.start.row; row <= source.range.end.row; row += 1) {
|
|
9272
|
+
for (let col = source.range.start.col; col <= source.range.end.col; col += 1) {
|
|
9273
|
+
items.push(source.worksheet.getFormattedValueAt(row, col));
|
|
9274
|
+
}
|
|
9275
|
+
}
|
|
9276
|
+
return items;
|
|
9277
|
+
}, [activeSheetIndex, getFormControlWorksheet, workbook]);
|
|
8909
9278
|
const getSheetShapes = React.useCallback((sheetIndex = activeSheetIndex) => {
|
|
8910
9279
|
const targetSheet = sheets[sheetIndex];
|
|
8911
9280
|
if (!targetSheet) {
|
|
@@ -9303,6 +9672,89 @@ function useXlsxViewerController(options) {
|
|
|
9303
9672
|
redoStackRef.current = [];
|
|
9304
9673
|
setHistoryRevision((current) => current + 1);
|
|
9305
9674
|
}, [createHistoryEntry]);
|
|
9675
|
+
const addFormControl = React.useCallback((input, sheetIndex = activeSheetIndex) => {
|
|
9676
|
+
const target = getFormControlWorksheet(sheetIndex);
|
|
9677
|
+
if (readOnly || !workbook || !target) {
|
|
9678
|
+
return null;
|
|
9679
|
+
}
|
|
9680
|
+
recordHistoryBeforeMutation();
|
|
9681
|
+
const controlIndex = target.worksheet.addFormControl(input);
|
|
9682
|
+
const controls = target.worksheet.formControls;
|
|
9683
|
+
const addedControl = controls[controlIndex];
|
|
9684
|
+
if (addedControl?.kind.kind === "optionButton" && addedControl.kind.state === "checked") {
|
|
9685
|
+
const groupIndexes = resolveOptionButtonGroupIndexes(controls, controlIndex);
|
|
9686
|
+
for (const siblingIndex of groupIndexes) {
|
|
9687
|
+
if (siblingIndex === controlIndex) {
|
|
9688
|
+
continue;
|
|
9689
|
+
}
|
|
9690
|
+
const sibling = target.worksheet.formControls[siblingIndex];
|
|
9691
|
+
if (sibling?.kind.kind === "optionButton" && sibling.kind.state !== "unchecked") {
|
|
9692
|
+
target.worksheet.setFormControl(siblingIndex, {
|
|
9693
|
+
...formControlInputFromDukeControl(sibling),
|
|
9694
|
+
kind: { ...sibling.kind, state: "unchecked" }
|
|
9695
|
+
});
|
|
9696
|
+
}
|
|
9697
|
+
}
|
|
9698
|
+
}
|
|
9699
|
+
syncFormControlLinkedCell(
|
|
9700
|
+
workbook,
|
|
9701
|
+
target.workbookSheetIndex,
|
|
9702
|
+
target.worksheet.formControls,
|
|
9703
|
+
controlIndex
|
|
9704
|
+
);
|
|
9705
|
+
maybeRecalculateWorkbook(workbook);
|
|
9706
|
+
refreshWorkbookState(workbook);
|
|
9707
|
+
return controlIndex;
|
|
9708
|
+
}, [activeSheetIndex, getFormControlWorksheet, maybeRecalculateWorkbook, readOnly, recordHistoryBeforeMutation, refreshWorkbookState, workbook]);
|
|
9709
|
+
const updateFormControl = React.useCallback((controlIndex, patch, sheetIndex = activeSheetIndex) => {
|
|
9710
|
+
const target = getFormControlWorksheet(sheetIndex);
|
|
9711
|
+
const currentControl = target?.worksheet.formControls[controlIndex];
|
|
9712
|
+
if (readOnly || !workbook || !target || !currentControl) {
|
|
9713
|
+
return false;
|
|
9714
|
+
}
|
|
9715
|
+
recordHistoryBeforeMutation();
|
|
9716
|
+
const nextInput = {
|
|
9717
|
+
...formControlInputFromDukeControl(currentControl),
|
|
9718
|
+
...patch,
|
|
9719
|
+
anchor: patch.anchor ? { ...patch.anchor } : { ...currentControl.anchor },
|
|
9720
|
+
kind: patch.kind ? { ...patch.kind } : { ...currentControl.kind }
|
|
9721
|
+
};
|
|
9722
|
+
if (nextInput.kind.kind === "optionButton" && nextInput.kind.state === "checked") {
|
|
9723
|
+
const groupIndexes = resolveOptionButtonGroupIndexes(target.worksheet.formControls, controlIndex);
|
|
9724
|
+
for (const siblingIndex of groupIndexes) {
|
|
9725
|
+
if (siblingIndex === controlIndex) {
|
|
9726
|
+
continue;
|
|
9727
|
+
}
|
|
9728
|
+
const sibling = target.worksheet.formControls[siblingIndex];
|
|
9729
|
+
if (sibling?.kind.kind === "optionButton" && sibling.kind.state !== "unchecked") {
|
|
9730
|
+
target.worksheet.setFormControl(siblingIndex, {
|
|
9731
|
+
...formControlInputFromDukeControl(sibling),
|
|
9732
|
+
kind: { ...sibling.kind, state: "unchecked" }
|
|
9733
|
+
});
|
|
9734
|
+
}
|
|
9735
|
+
}
|
|
9736
|
+
}
|
|
9737
|
+
target.worksheet.setFormControl(controlIndex, nextInput);
|
|
9738
|
+
syncFormControlLinkedCell(
|
|
9739
|
+
workbook,
|
|
9740
|
+
target.workbookSheetIndex,
|
|
9741
|
+
target.worksheet.formControls,
|
|
9742
|
+
controlIndex
|
|
9743
|
+
);
|
|
9744
|
+
maybeRecalculateWorkbook(workbook);
|
|
9745
|
+
refreshWorkbookState(workbook);
|
|
9746
|
+
return true;
|
|
9747
|
+
}, [activeSheetIndex, getFormControlWorksheet, maybeRecalculateWorkbook, readOnly, recordHistoryBeforeMutation, refreshWorkbookState, workbook]);
|
|
9748
|
+
const removeFormControl = React.useCallback((controlIndex, sheetIndex = activeSheetIndex) => {
|
|
9749
|
+
const target = getFormControlWorksheet(sheetIndex);
|
|
9750
|
+
if (readOnly || !workbook || !target || !target.worksheet.formControls[controlIndex]) {
|
|
9751
|
+
return false;
|
|
9752
|
+
}
|
|
9753
|
+
recordHistoryBeforeMutation();
|
|
9754
|
+
target.worksheet.removeFormControl(controlIndex);
|
|
9755
|
+
refreshWorkbookState(workbook);
|
|
9756
|
+
return true;
|
|
9757
|
+
}, [activeSheetIndex, getFormControlWorksheet, readOnly, recordHistoryBeforeMutation, refreshWorkbookState, workbook]);
|
|
9306
9758
|
const recordCellEditHistory = React.useCallback((cell, before, after) => {
|
|
9307
9759
|
if (!activeSheet || isApplyingHistoryRef.current) {
|
|
9308
9760
|
return;
|
|
@@ -10111,8 +10563,15 @@ function useXlsxViewerController(options) {
|
|
|
10111
10563
|
}
|
|
10112
10564
|
workbook.addSheet(candidate);
|
|
10113
10565
|
sheetOriginsRef.current = [...sheetOriginsRef.current, null];
|
|
10566
|
+
setFormControlsByWorkbookSheetIndex((current) => [...current, []]);
|
|
10114
10567
|
setImagesByWorkbookSheetIndex((current) => [...current, []]);
|
|
10115
10568
|
setShapesByWorkbookSheetIndex((current) => [...current, []]);
|
|
10569
|
+
if (imageAssetsRef.current) {
|
|
10570
|
+
imageAssetsRef.current.formControlsByWorkbookSheetIndex = [
|
|
10571
|
+
...imageAssetsRef.current.formControlsByWorkbookSheetIndex,
|
|
10572
|
+
[]
|
|
10573
|
+
];
|
|
10574
|
+
}
|
|
10116
10575
|
const nextSheets = buildSheetList(
|
|
10117
10576
|
workbook,
|
|
10118
10577
|
imageAssetsRef.current?.sheetStatesByWorkbookSheetIndex,
|
|
@@ -10142,9 +10601,13 @@ function useXlsxViewerController(options) {
|
|
|
10142
10601
|
recordHistoryBeforeMutation();
|
|
10143
10602
|
workbook.removeSheet(activeSheet.workbookSheetIndex);
|
|
10144
10603
|
sheetOriginsRef.current = sheetOriginsRef.current.filter((_, index) => index !== activeSheet.workbookSheetIndex);
|
|
10604
|
+
setFormControlsByWorkbookSheetIndex((current) => current.filter((_, index) => index !== activeSheet.workbookSheetIndex));
|
|
10145
10605
|
setImagesByWorkbookSheetIndex((current) => current.filter((_, index) => index !== activeSheet.workbookSheetIndex));
|
|
10146
10606
|
setShapesByWorkbookSheetIndex((current) => current.filter((_, index) => index !== activeSheet.workbookSheetIndex));
|
|
10147
10607
|
if (imageAssetsRef.current) {
|
|
10608
|
+
imageAssetsRef.current.formControlsByWorkbookSheetIndex = imageAssetsRef.current.formControlsByWorkbookSheetIndex.filter(
|
|
10609
|
+
(_, index) => index !== activeSheet.workbookSheetIndex
|
|
10610
|
+
);
|
|
10148
10611
|
imageAssetsRef.current.sheetStatesByWorkbookSheetIndex = imageAssetsRef.current.sheetStatesByWorkbookSheetIndex.filter(
|
|
10149
10612
|
(_, index) => index !== activeSheet.workbookSheetIndex
|
|
10150
10613
|
);
|
|
@@ -10445,6 +10908,7 @@ function useXlsxViewerController(options) {
|
|
|
10445
10908
|
activeSheetIndex,
|
|
10446
10909
|
activeTab,
|
|
10447
10910
|
activeTabIndex,
|
|
10911
|
+
addFormControl,
|
|
10448
10912
|
addSheet,
|
|
10449
10913
|
canRedo,
|
|
10450
10914
|
canDownload: Boolean(file ?? src),
|
|
@@ -10484,6 +10948,7 @@ function useXlsxViewerController(options) {
|
|
|
10484
10948
|
getClipboardData,
|
|
10485
10949
|
getCellDisplayValue: getCellDisplayValue2,
|
|
10486
10950
|
getCellFormula,
|
|
10951
|
+
getFormControlItems,
|
|
10487
10952
|
getCellSnapshotAsync: isWorkerBacked ? getCellSnapshotAsync : void 0,
|
|
10488
10953
|
getActiveWorksheet,
|
|
10489
10954
|
getRowsBatchAsync: isWorkerBacked ? getRowsBatchAsync : void 0,
|
|
@@ -10501,6 +10966,7 @@ function useXlsxViewerController(options) {
|
|
|
10501
10966
|
pasteStructuredClipboardData,
|
|
10502
10967
|
pasteText,
|
|
10503
10968
|
removeActiveSheet,
|
|
10969
|
+
removeFormControl,
|
|
10504
10970
|
readOnly,
|
|
10505
10971
|
recalculate,
|
|
10506
10972
|
redo,
|
|
@@ -10551,6 +11017,7 @@ function useXlsxViewerController(options) {
|
|
|
10551
11017
|
undo,
|
|
10552
11018
|
unmergeSelection,
|
|
10553
11019
|
updateChart,
|
|
11020
|
+
updateFormControl,
|
|
10554
11021
|
workbook,
|
|
10555
11022
|
zoomIn,
|
|
10556
11023
|
zoomOut,
|
|
@@ -10563,6 +11030,7 @@ function useXlsxViewerController(options) {
|
|
|
10563
11030
|
activeSheetIndex,
|
|
10564
11031
|
activeTab,
|
|
10565
11032
|
activeTabIndex,
|
|
11033
|
+
addFormControl,
|
|
10566
11034
|
addSheet,
|
|
10567
11035
|
canLoadDeferred,
|
|
10568
11036
|
canRedo,
|
|
@@ -10599,6 +11067,7 @@ function useXlsxViewerController(options) {
|
|
|
10599
11067
|
getClipboardData,
|
|
10600
11068
|
getCellDisplayValue2,
|
|
10601
11069
|
getCellFormula,
|
|
11070
|
+
getFormControlItems,
|
|
10602
11071
|
getCellSnapshotAsync,
|
|
10603
11072
|
getActiveWorksheet,
|
|
10604
11073
|
historyRevision,
|
|
@@ -10616,6 +11085,7 @@ function useXlsxViewerController(options) {
|
|
|
10616
11085
|
pasteStructuredClipboardData,
|
|
10617
11086
|
pasteText,
|
|
10618
11087
|
removeActiveSheet,
|
|
11088
|
+
removeFormControl,
|
|
10619
11089
|
readOnly,
|
|
10620
11090
|
recalculate,
|
|
10621
11091
|
redo,
|
|
@@ -10666,6 +11136,7 @@ function useXlsxViewerController(options) {
|
|
|
10666
11136
|
undo,
|
|
10667
11137
|
unmergeSelection,
|
|
10668
11138
|
updateChart,
|
|
11139
|
+
updateFormControl,
|
|
10669
11140
|
workbook,
|
|
10670
11141
|
zoomIn,
|
|
10671
11142
|
zoomOut,
|
|
@@ -21637,13 +22108,90 @@ function renderConditionalIcon(icon, scale = 1) {
|
|
|
21637
22108
|
}
|
|
21638
22109
|
);
|
|
21639
22110
|
}
|
|
21640
|
-
function
|
|
22111
|
+
function isFormControlChecked(control) {
|
|
22112
|
+
return control.state ? control.state === "checked" : Boolean(control.checked);
|
|
22113
|
+
}
|
|
22114
|
+
function isFormControlMixed(control) {
|
|
22115
|
+
return control.state === "mixed";
|
|
22116
|
+
}
|
|
22117
|
+
function buildFormControlKindInput(control) {
|
|
22118
|
+
switch (control.kind) {
|
|
22119
|
+
case "button":
|
|
22120
|
+
return { caption: control.caption ?? control.label ?? "", kind: "button" };
|
|
22121
|
+
case "checkbox":
|
|
22122
|
+
return {
|
|
22123
|
+
caption: control.caption ?? control.label ?? "",
|
|
22124
|
+
cellLink: control.linkedCell,
|
|
22125
|
+
kind: "checkbox",
|
|
22126
|
+
no3D: control.no3D ?? false,
|
|
22127
|
+
state: control.state ?? (control.checked ? "checked" : "unchecked")
|
|
22128
|
+
};
|
|
22129
|
+
case "radio":
|
|
22130
|
+
return {
|
|
22131
|
+
caption: control.caption ?? control.label ?? "",
|
|
22132
|
+
cellLink: control.linkedCell,
|
|
22133
|
+
firstInGroup: control.firstInGroup,
|
|
22134
|
+
kind: "optionButton",
|
|
22135
|
+
no3D: control.no3D ?? false,
|
|
22136
|
+
state: control.state === "checked" ? "checked" : "unchecked"
|
|
22137
|
+
};
|
|
22138
|
+
case "label":
|
|
22139
|
+
return { caption: control.caption ?? control.label ?? "", kind: "label" };
|
|
22140
|
+
case "group-box":
|
|
22141
|
+
return {
|
|
22142
|
+
caption: control.caption ?? control.label ?? "",
|
|
22143
|
+
kind: "groupBox",
|
|
22144
|
+
no3D: control.no3D ?? false
|
|
22145
|
+
};
|
|
22146
|
+
case "listbox":
|
|
22147
|
+
return {
|
|
22148
|
+
cellLink: control.linkedCell,
|
|
22149
|
+
inputRange: control.inputRange,
|
|
22150
|
+
kind: "listBox",
|
|
22151
|
+
no3D: control.no3D ?? false,
|
|
22152
|
+
selected: Array.isArray(control.selected) ? control.selected : control.selected === void 0 ? [] : [control.selected],
|
|
22153
|
+
selection: control.selection ?? "single"
|
|
22154
|
+
};
|
|
22155
|
+
case "dropdown":
|
|
22156
|
+
return {
|
|
22157
|
+
cellLink: control.linkedCell,
|
|
22158
|
+
inputRange: control.inputRange,
|
|
22159
|
+
kind: "dropdown",
|
|
22160
|
+
lines: control.lines ?? 8,
|
|
22161
|
+
no3D: control.no3D ?? false,
|
|
22162
|
+
selected: typeof control.selected === "number" ? control.selected : void 0
|
|
22163
|
+
};
|
|
22164
|
+
case "scrollbar":
|
|
22165
|
+
return {
|
|
22166
|
+
cellLink: control.linkedCell,
|
|
22167
|
+
horizontal: control.horizontal ?? true,
|
|
22168
|
+
increment: control.increment ?? 1,
|
|
22169
|
+
kind: "scrollbar",
|
|
22170
|
+
max: control.max ?? 100,
|
|
22171
|
+
min: control.min ?? 0,
|
|
22172
|
+
page: control.page ?? 10,
|
|
22173
|
+
value: control.value ?? control.min ?? 0
|
|
22174
|
+
};
|
|
22175
|
+
case "spinner":
|
|
22176
|
+
return {
|
|
22177
|
+
cellLink: control.linkedCell,
|
|
22178
|
+
increment: control.increment ?? 1,
|
|
22179
|
+
kind: "spinner",
|
|
22180
|
+
max: control.max ?? 100,
|
|
22181
|
+
min: control.min ?? 0,
|
|
22182
|
+
value: control.value ?? control.min ?? 0
|
|
22183
|
+
};
|
|
22184
|
+
default:
|
|
22185
|
+
return null;
|
|
22186
|
+
}
|
|
22187
|
+
}
|
|
22188
|
+
function renderCheckboxControl(checked, palette, scale = 1, mixed = false) {
|
|
21641
22189
|
const stroke = paletteIsDark(palette) ? "#cbd5e1" : "#475569";
|
|
21642
|
-
const fill = checked ? paletteIsDark(palette) ? "#60a5fa" : "#2563eb" : "transparent";
|
|
22190
|
+
const fill = checked || mixed ? paletteIsDark(palette) ? "#60a5fa" : "#2563eb" : "transparent";
|
|
21643
22191
|
const check = paletteIsDark(palette) ? "#020617" : "#ffffff";
|
|
21644
22192
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { "aria-hidden": "true", height: 14 * scale, style: { display: "block" }, viewBox: "0 0 16 16", width: 14 * scale, children: [
|
|
21645
22193
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("rect", { fill, height: 11, rx: 2, ry: 2, stroke, strokeWidth: 1.2, width: 11, x: 2.5, y: 2.5 }),
|
|
21646
|
-
checked ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
22194
|
+
mixed ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M5 8h6", fill: "none", stroke: check, strokeLinecap: "round", strokeWidth: 1.8 }) : checked ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
21647
22195
|
"path",
|
|
21648
22196
|
{
|
|
21649
22197
|
d: "M5 8.1 7.1 10.2 11.3 5.8",
|
|
@@ -21813,6 +22361,8 @@ function drawStaticFormControl(context, control, rect, palette, zoomFactor, shee
|
|
|
21813
22361
|
const textColor = control.textColor ?? "#000000";
|
|
21814
22362
|
const fontSizePx = Math.max(9 * zoomFactor, (control.fontSizePt ?? 9) * 96 / 72 * zoomFactor);
|
|
21815
22363
|
const iconSize = Math.min(14 * zoomFactor, Math.max(0, rect.height - 4 * zoomFactor));
|
|
22364
|
+
const controlChecked = isFormControlChecked(control);
|
|
22365
|
+
const controlMixed = isFormControlMixed(control);
|
|
21816
22366
|
context.save();
|
|
21817
22367
|
context.font = `400 ${fontSizePx}px ${control.fontFamily ?? "Calibri, sans-serif"}`;
|
|
21818
22368
|
context.textBaseline = "middle";
|
|
@@ -21853,14 +22403,19 @@ function drawStaticFormControl(context, control, rect, palette, zoomFactor, shee
|
|
|
21853
22403
|
const textRightInset = control.kind === "dropdown" ? 18 * zoomFactor : 6 * zoomFactor;
|
|
21854
22404
|
if (control.kind === "checkbox") {
|
|
21855
22405
|
context.strokeRect(rect.left + 2 * zoomFactor, rect.top + (rect.height - iconSize) / 2, iconSize, iconSize);
|
|
21856
|
-
if (
|
|
22406
|
+
if (controlChecked || controlMixed) {
|
|
21857
22407
|
context.fillStyle = paletteIsDark(palette) ? "#60a5fa" : "#2563eb";
|
|
21858
22408
|
context.fillRect(rect.left + 2 * zoomFactor + 1.5, rect.top + (rect.height - iconSize) / 2 + 1.5, Math.max(0, iconSize - 3), Math.max(0, iconSize - 3));
|
|
21859
22409
|
context.strokeStyle = paletteIsDark(palette) ? "#020617" : "#ffffff";
|
|
21860
22410
|
context.beginPath();
|
|
21861
|
-
|
|
21862
|
-
|
|
21863
|
-
|
|
22411
|
+
if (controlMixed) {
|
|
22412
|
+
context.moveTo(rect.left + 2 * zoomFactor + iconSize * 0.25, rect.top + rect.height / 2);
|
|
22413
|
+
context.lineTo(rect.left + 2 * zoomFactor + iconSize * 0.75, rect.top + rect.height / 2);
|
|
22414
|
+
} else {
|
|
22415
|
+
context.moveTo(rect.left + 2 * zoomFactor + iconSize * 0.24, rect.top + rect.height / 2 + iconSize * 0.06);
|
|
22416
|
+
context.lineTo(rect.left + 2 * zoomFactor + iconSize * 0.45, rect.top + rect.height / 2 + iconSize * 0.26);
|
|
22417
|
+
context.lineTo(rect.left + 2 * zoomFactor + iconSize * 0.8, rect.top + rect.height / 2 - iconSize * 0.2);
|
|
22418
|
+
}
|
|
21864
22419
|
context.stroke();
|
|
21865
22420
|
}
|
|
21866
22421
|
textLeft += iconSize + 4 * zoomFactor;
|
|
@@ -21868,7 +22423,7 @@ function drawStaticFormControl(context, control, rect, palette, zoomFactor, shee
|
|
|
21868
22423
|
context.beginPath();
|
|
21869
22424
|
context.arc(rect.left + 2 * zoomFactor + iconSize / 2, rect.top + rect.height / 2, iconSize / 2, 0, Math.PI * 2);
|
|
21870
22425
|
context.stroke();
|
|
21871
|
-
if (
|
|
22426
|
+
if (controlChecked) {
|
|
21872
22427
|
context.fillStyle = paletteIsDark(palette) ? "#60a5fa" : "#2563eb";
|
|
21873
22428
|
context.beginPath();
|
|
21874
22429
|
context.arc(rect.left + 2 * zoomFactor + iconSize / 2, rect.top + rect.height / 2, iconSize * 0.25, 0, Math.PI * 2);
|
|
@@ -22504,6 +23059,8 @@ function XlsxGrid({
|
|
|
22504
23059
|
getCellStyle,
|
|
22505
23060
|
loadingComponent,
|
|
22506
23061
|
loadingState,
|
|
23062
|
+
onFormControlAction,
|
|
23063
|
+
onFormControlChange,
|
|
22507
23064
|
renderChartLoading,
|
|
22508
23065
|
palette,
|
|
22509
23066
|
renderImage,
|
|
@@ -22541,6 +23098,7 @@ function XlsxGrid({
|
|
|
22541
23098
|
getRowsBatchAsync,
|
|
22542
23099
|
getClipboardData,
|
|
22543
23100
|
getCellDisplayValue: getControllerCellDisplayValue,
|
|
23101
|
+
getFormControlItems,
|
|
22544
23102
|
images,
|
|
22545
23103
|
shapes,
|
|
22546
23104
|
isLoadDeferred,
|
|
@@ -22578,9 +23136,13 @@ function XlsxGrid({
|
|
|
22578
23136
|
sortTable,
|
|
22579
23137
|
tables,
|
|
22580
23138
|
undo,
|
|
23139
|
+
updateFormControl,
|
|
22581
23140
|
workbook,
|
|
22582
23141
|
zoomScale
|
|
22583
23142
|
} = controller;
|
|
23143
|
+
const formControlItemsById = React4.useMemo(() => new Map(
|
|
23144
|
+
formControls.flatMap((control) => control.controlIndex !== void 0 && (control.kind === "dropdown" || control.kind === "listbox") ? [[control.id, getFormControlItems(control.controlIndex, control.sheetIndex)]] : [])
|
|
23145
|
+
), [formControls, getFormControlItems]);
|
|
22584
23146
|
const canResizeHeaders = !readOnly || allowResizeInReadOnly;
|
|
22585
23147
|
const scrollRef = React4.useRef(null);
|
|
22586
23148
|
const wrapperRef = React4.useRef(null);
|
|
@@ -25088,7 +25650,7 @@ function XlsxGrid({
|
|
|
25088
25650
|
return "";
|
|
25089
25651
|
}
|
|
25090
25652
|
const shapeSignature = bakedShapeRects.map(({ rect, shape }) => `s:${shape.id}:${shape.zIndex}:${Math.round(rect.left)}:${Math.round(rect.top)}:${Math.round(rect.width)}:${Math.round(rect.height)}`).join("|");
|
|
25091
|
-
const controlSignature = bakedFormControlRects.map(({ control, rect }) => `f:${control.id}:${control.zIndex}:${Boolean(control.checked)}:${Math.round(rect.left)}:${Math.round(rect.top)}:${Math.round(rect.width)}:${Math.round(rect.height)}`).join("|");
|
|
25653
|
+
const controlSignature = bakedFormControlRects.map(({ control, rect }) => `f:${control.id}:${control.zIndex}:${control.state ?? Boolean(control.checked)}:${Math.round(rect.left)}:${Math.round(rect.top)}:${Math.round(rect.width)}:${Math.round(rect.height)}`).join("|");
|
|
25092
25654
|
const imageSignature = bakedImageRects.map(({ image, rect }) => `i:${image.id}:${image.src}:${image.zIndex}:${Math.round(rect.left)}:${Math.round(rect.top)}:${Math.round(rect.width)}:${Math.round(rect.height)}`).join("|");
|
|
25093
25655
|
return `${revision}:${canvasImageLoadVersion}:${shapeSignature}:${controlSignature}:${imageSignature}`;
|
|
25094
25656
|
}, [
|
|
@@ -26789,6 +27351,8 @@ function XlsxGrid({
|
|
|
26789
27351
|
const textColor = control.textColor ?? "#000000";
|
|
26790
27352
|
const fontSizePx = Math.max(9 * zoomFactor, (control.fontSizePt ?? 9) * 96 / 72 * zoomFactor);
|
|
26791
27353
|
const iconSize = Math.min(14 * zoomFactor, Math.max(0, rect.height - 4 * zoomFactor));
|
|
27354
|
+
const controlChecked = isFormControlChecked(control);
|
|
27355
|
+
const controlMixed = isFormControlMixed(control);
|
|
26792
27356
|
context.save();
|
|
26793
27357
|
context.font = `400 ${fontSizePx}px ${control.fontFamily ?? "Calibri, sans-serif"}`;
|
|
26794
27358
|
context.textBaseline = "middle";
|
|
@@ -26829,14 +27393,19 @@ function XlsxGrid({
|
|
|
26829
27393
|
const textRightInset = control.kind === "dropdown" ? 18 * zoomFactor : 6 * zoomFactor;
|
|
26830
27394
|
if (control.kind === "checkbox") {
|
|
26831
27395
|
context.strokeRect(rect.left + 2 * zoomFactor, rect.top + (rect.height - iconSize) / 2, iconSize, iconSize);
|
|
26832
|
-
if (
|
|
27396
|
+
if (controlChecked || controlMixed) {
|
|
26833
27397
|
context.fillStyle = paletteIsDark(palette) ? "#60a5fa" : "#2563eb";
|
|
26834
27398
|
context.fillRect(rect.left + 2 * zoomFactor + 1.5, rect.top + (rect.height - iconSize) / 2 + 1.5, Math.max(0, iconSize - 3), Math.max(0, iconSize - 3));
|
|
26835
27399
|
context.strokeStyle = paletteIsDark(palette) ? "#020617" : "#ffffff";
|
|
26836
27400
|
context.beginPath();
|
|
26837
|
-
|
|
26838
|
-
|
|
26839
|
-
|
|
27401
|
+
if (controlMixed) {
|
|
27402
|
+
context.moveTo(rect.left + 2 * zoomFactor + iconSize * 0.25, rect.top + rect.height / 2);
|
|
27403
|
+
context.lineTo(rect.left + 2 * zoomFactor + iconSize * 0.75, rect.top + rect.height / 2);
|
|
27404
|
+
} else {
|
|
27405
|
+
context.moveTo(rect.left + 2 * zoomFactor + iconSize * 0.24, rect.top + rect.height / 2 + iconSize * 0.06);
|
|
27406
|
+
context.lineTo(rect.left + 2 * zoomFactor + iconSize * 0.45, rect.top + rect.height / 2 + iconSize * 0.26);
|
|
27407
|
+
context.lineTo(rect.left + 2 * zoomFactor + iconSize * 0.8, rect.top + rect.height / 2 - iconSize * 0.2);
|
|
27408
|
+
}
|
|
26840
27409
|
context.stroke();
|
|
26841
27410
|
}
|
|
26842
27411
|
textLeft += iconSize + 4 * zoomFactor;
|
|
@@ -26844,7 +27413,7 @@ function XlsxGrid({
|
|
|
26844
27413
|
context.beginPath();
|
|
26845
27414
|
context.arc(rect.left + 2 * zoomFactor + iconSize / 2, rect.top + rect.height / 2, iconSize / 2, 0, Math.PI * 2);
|
|
26846
27415
|
context.stroke();
|
|
26847
|
-
if (
|
|
27416
|
+
if (controlChecked) {
|
|
26848
27417
|
context.fillStyle = paletteIsDark(palette) ? "#60a5fa" : "#2563eb";
|
|
26849
27418
|
context.beginPath();
|
|
26850
27419
|
context.arc(rect.left + 2 * zoomFactor + iconSize / 2, rect.top + rect.height / 2, iconSize * 0.25, 0, Math.PI * 2);
|
|
@@ -27023,8 +27592,7 @@ function XlsxGrid({
|
|
|
27023
27592
|
const canvasCellStyle = cellData.canvas ?? buildCanvasCellStyleCache(cellStyle);
|
|
27024
27593
|
const fillColor = cellData.conditionalColorScale?.color ?? (typeof cellStyle.backgroundColor === "string" ? cellStyle.backgroundColor : sheetSurface);
|
|
27025
27594
|
const gradientFill = !cellData.conditionalColorScale && typeof cellStyle.backgroundImage === "string" ? resolveCanvasGradientFill(paneContext, localRect, cellStyle.backgroundImage) : null;
|
|
27026
|
-
|
|
27027
|
-
if (hasExplicitCellFill || cellData.chartHighlight) {
|
|
27595
|
+
if (cellData.chartHighlight) {
|
|
27028
27596
|
flushPendingGridlines();
|
|
27029
27597
|
}
|
|
27030
27598
|
paneContext.fillStyle = gradientFill ?? fillColor;
|
|
@@ -27072,7 +27640,7 @@ function XlsxGrid({
|
|
|
27072
27640
|
const bottomNeighborTopBorder = bottomNeighborData?.isMergedSecondary ? null : bottomNeighborData?.canvas?.topBorder ?? parseCanvasBorderDeclaration(bottomNeighborData?.style.borderTop);
|
|
27073
27641
|
const resolvedRightBorder = resolveCanvasBoundaryBorder(rightBorder, rightNeighborLeftBorder);
|
|
27074
27642
|
const resolvedBottomBorder = resolveCanvasBoundaryBorder(bottomBorder, bottomNeighborTopBorder);
|
|
27075
|
-
if (showGridLines &&
|
|
27643
|
+
if (showGridLines && (!resolvedRightBorder || !resolvedBottomBorder)) {
|
|
27076
27644
|
enqueueGridlinePath();
|
|
27077
27645
|
if (!resolvedRightBorder) {
|
|
27078
27646
|
paneContext.moveTo(localRect.left + localRect.width - 0.5, localRect.top);
|
|
@@ -28160,10 +28728,22 @@ function XlsxGrid({
|
|
|
28160
28728
|
const fontSizePx = Math.max(9 * zoomFactor, (control.fontSizePt ?? 9) * 96 / 72 * zoomFactor);
|
|
28161
28729
|
const stroke = paletteIsDark(palette) ? "#cbd5e1" : "#475569";
|
|
28162
28730
|
const textColor = control.textColor ?? "#000000";
|
|
28731
|
+
const canMutateControl = !readOnly && control.controlIndex !== void 0 && [
|
|
28732
|
+
"checkbox",
|
|
28733
|
+
"dropdown",
|
|
28734
|
+
"listbox",
|
|
28735
|
+
"radio",
|
|
28736
|
+
"scrollbar",
|
|
28737
|
+
"spinner"
|
|
28738
|
+
].includes(control.kind);
|
|
28739
|
+
const canActivateButton = !readOnly && control.kind === "button" && Boolean(onFormControlAction);
|
|
28740
|
+
const isInteractiveControl = canMutateControl || canActivateButton;
|
|
28741
|
+
const controlItems = formControlItemsById.get(control.id) ?? [];
|
|
28163
28742
|
const commonStyle = {
|
|
28164
28743
|
alignItems: control.kind === "group-box" ? "stretch" : "center",
|
|
28165
28744
|
color: textColor,
|
|
28166
28745
|
contain: "layout paint",
|
|
28746
|
+
cursor: isInteractiveControl ? "pointer" : void 0,
|
|
28167
28747
|
display: "flex",
|
|
28168
28748
|
fontFamily: control.fontFamily ?? "Calibri, sans-serif",
|
|
28169
28749
|
fontSize: fontSizePx,
|
|
@@ -28174,12 +28754,28 @@ function XlsxGrid({
|
|
|
28174
28754
|
left: rect.left,
|
|
28175
28755
|
lineHeight: 1.2,
|
|
28176
28756
|
overflow: "hidden",
|
|
28177
|
-
pointerEvents: "none",
|
|
28757
|
+
pointerEvents: isInteractiveControl ? "auto" : "none",
|
|
28178
28758
|
position: "absolute",
|
|
28179
28759
|
top: rect.top,
|
|
28180
28760
|
width: rect.width,
|
|
28181
28761
|
zIndex: isFrozenDrawing ? control.zIndex + 20 : control.zIndex
|
|
28182
28762
|
};
|
|
28763
|
+
const stopControlPointerEvent = (event) => {
|
|
28764
|
+
event.stopPropagation();
|
|
28765
|
+
};
|
|
28766
|
+
const commitControlKind = (kind, nextControl) => {
|
|
28767
|
+
if (control.controlIndex === void 0) {
|
|
28768
|
+
return;
|
|
28769
|
+
}
|
|
28770
|
+
const didUpdate = updateFormControl(control.controlIndex, { kind }, control.sheetIndex);
|
|
28771
|
+
if (didUpdate) {
|
|
28772
|
+
onFormControlChange?.({
|
|
28773
|
+
control: { ...control, ...nextControl },
|
|
28774
|
+
previousControl: control,
|
|
28775
|
+
type: "change"
|
|
28776
|
+
});
|
|
28777
|
+
}
|
|
28778
|
+
};
|
|
28183
28779
|
if (control.kind === "group-box") {
|
|
28184
28780
|
const hasLabel = controlLabel.length > 0;
|
|
28185
28781
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -28221,15 +28817,88 @@ function XlsxGrid({
|
|
|
28221
28817
|
`${pane}-${control.id}`
|
|
28222
28818
|
);
|
|
28223
28819
|
}
|
|
28224
|
-
let content;
|
|
28225
28820
|
if (control.kind === "radio") {
|
|
28226
|
-
|
|
28227
|
-
|
|
28228
|
-
|
|
28229
|
-
|
|
28821
|
+
const checked = isFormControlChecked(control);
|
|
28822
|
+
const kind = buildFormControlKindInput(control);
|
|
28823
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
28824
|
+
"button",
|
|
28825
|
+
{
|
|
28826
|
+
"aria-checked": checked,
|
|
28827
|
+
disabled: readOnly || control.controlIndex === void 0,
|
|
28828
|
+
onClick: (event) => {
|
|
28829
|
+
event.stopPropagation();
|
|
28830
|
+
if (!checked && kind?.kind === "optionButton") {
|
|
28831
|
+
commitControlKind(
|
|
28832
|
+
{ ...kind, state: "checked" },
|
|
28833
|
+
{ checked: true, state: "checked" }
|
|
28834
|
+
);
|
|
28835
|
+
}
|
|
28836
|
+
},
|
|
28837
|
+
onPointerDown: stopControlPointerEvent,
|
|
28838
|
+
role: "radio",
|
|
28839
|
+
style: {
|
|
28840
|
+
...commonStyle,
|
|
28841
|
+
background: "transparent",
|
|
28842
|
+
border: 0,
|
|
28843
|
+
boxSizing: "border-box",
|
|
28844
|
+
padding: `0 ${Math.max(1, zoomFactor)}px`
|
|
28845
|
+
},
|
|
28846
|
+
type: "button",
|
|
28847
|
+
children: [
|
|
28848
|
+
renderRadioControl(checked, palette, zoomFactor),
|
|
28849
|
+
controlLabel ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: controlLabel }) : null
|
|
28850
|
+
]
|
|
28851
|
+
},
|
|
28852
|
+
`${pane}-${control.id}`
|
|
28853
|
+
);
|
|
28854
|
+
}
|
|
28855
|
+
if (control.kind === "checkbox") {
|
|
28856
|
+
const checked = isFormControlChecked(control);
|
|
28857
|
+
const mixed = isFormControlMixed(control);
|
|
28858
|
+
const kind = buildFormControlKindInput(control);
|
|
28859
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
28860
|
+
"button",
|
|
28861
|
+
{
|
|
28862
|
+
"aria-checked": mixed ? "mixed" : checked,
|
|
28863
|
+
disabled: readOnly || control.controlIndex === void 0,
|
|
28864
|
+
onClick: (event) => {
|
|
28865
|
+
event.stopPropagation();
|
|
28866
|
+
if (kind?.kind === "checkbox") {
|
|
28867
|
+
const nextState = checked && !mixed ? "unchecked" : "checked";
|
|
28868
|
+
commitControlKind(
|
|
28869
|
+
{ ...kind, state: nextState },
|
|
28870
|
+
{ checked: nextState === "checked", state: nextState }
|
|
28871
|
+
);
|
|
28872
|
+
}
|
|
28873
|
+
},
|
|
28874
|
+
onPointerDown: stopControlPointerEvent,
|
|
28875
|
+
role: "checkbox",
|
|
28876
|
+
style: {
|
|
28877
|
+
...commonStyle,
|
|
28878
|
+
background: "transparent",
|
|
28879
|
+
border: 0,
|
|
28880
|
+
boxSizing: "border-box",
|
|
28881
|
+
padding: `0 ${Math.max(1, zoomFactor)}px`
|
|
28882
|
+
},
|
|
28883
|
+
type: "button",
|
|
28884
|
+
children: [
|
|
28885
|
+
renderCheckboxControl(checked, palette, zoomFactor, mixed),
|
|
28886
|
+
controlLabel ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: controlLabel }) : null
|
|
28887
|
+
]
|
|
28888
|
+
},
|
|
28889
|
+
`${pane}-${control.id}`
|
|
28890
|
+
);
|
|
28891
|
+
}
|
|
28892
|
+
if (control.kind === "button") {
|
|
28230
28893
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
28231
|
-
"
|
|
28894
|
+
"button",
|
|
28232
28895
|
{
|
|
28896
|
+
disabled: readOnly || !onFormControlAction,
|
|
28897
|
+
onClick: (event) => {
|
|
28898
|
+
event.stopPropagation();
|
|
28899
|
+
onFormControlAction?.({ control, type: "activate" });
|
|
28900
|
+
},
|
|
28901
|
+
onPointerDown: stopControlPointerEvent,
|
|
28233
28902
|
style: {
|
|
28234
28903
|
...commonStyle,
|
|
28235
28904
|
background: "linear-gradient(180deg, #f8fafc 0%, #e2e8f0 100%)",
|
|
@@ -28240,68 +28909,168 @@ function XlsxGrid({
|
|
|
28240
28909
|
padding: `0 ${6 * zoomFactor}px`,
|
|
28241
28910
|
textAlign: "center"
|
|
28242
28911
|
},
|
|
28912
|
+
type: "button",
|
|
28243
28913
|
children: controlLabel
|
|
28244
28914
|
},
|
|
28245
28915
|
`${pane}-${control.id}`
|
|
28246
28916
|
);
|
|
28247
|
-
}
|
|
28917
|
+
}
|
|
28918
|
+
if (control.kind === "dropdown") {
|
|
28919
|
+
const kind = buildFormControlKindInput(control);
|
|
28920
|
+
const selected = typeof control.selected === "number" ? control.selected : void 0;
|
|
28248
28921
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
28249
|
-
"
|
|
28922
|
+
"select",
|
|
28250
28923
|
{
|
|
28924
|
+
"aria-label": controlLabel || control.name || "Dropdown form control",
|
|
28925
|
+
disabled: readOnly || control.controlIndex === void 0 || controlItems.length === 0,
|
|
28926
|
+
onChange: (event) => {
|
|
28927
|
+
event.stopPropagation();
|
|
28928
|
+
if (kind?.kind === "dropdown") {
|
|
28929
|
+
const nextSelected = event.currentTarget.value === "" ? void 0 : Number(event.currentTarget.value);
|
|
28930
|
+
commitControlKind(
|
|
28931
|
+
{ ...kind, selected: nextSelected },
|
|
28932
|
+
{ selected: nextSelected }
|
|
28933
|
+
);
|
|
28934
|
+
}
|
|
28935
|
+
},
|
|
28936
|
+
onClick: stopControlPointerEvent,
|
|
28937
|
+
onPointerDown: stopControlPointerEvent,
|
|
28251
28938
|
style: {
|
|
28252
28939
|
...commonStyle,
|
|
28940
|
+
backgroundColor: SHEET_SURFACE,
|
|
28253
28941
|
border: `${Math.max(1, zoomFactor)}px solid ${stroke}`,
|
|
28254
28942
|
borderRadius: 2 * zoomFactor,
|
|
28255
28943
|
boxSizing: "border-box",
|
|
28256
|
-
|
|
28257
|
-
padding: `0 ${6 * zoomFactor}px`
|
|
28944
|
+
padding: `0 ${4 * zoomFactor}px`
|
|
28258
28945
|
},
|
|
28946
|
+
value: selected === void 0 ? "" : String(selected),
|
|
28259
28947
|
children: [
|
|
28260
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("
|
|
28261
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("
|
|
28948
|
+
selected === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: controlLabel }) : null,
|
|
28949
|
+
controlItems.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: index, children: item }, index))
|
|
28262
28950
|
]
|
|
28263
28951
|
},
|
|
28264
28952
|
`${pane}-${control.id}`
|
|
28265
28953
|
);
|
|
28266
|
-
}
|
|
28954
|
+
}
|
|
28955
|
+
if (control.kind === "listbox") {
|
|
28956
|
+
const kind = buildFormControlKindInput(control);
|
|
28957
|
+
const selected = Array.isArray(control.selected) ? control.selected : control.selected === void 0 ? [] : [control.selected];
|
|
28958
|
+
const allowsMultipleSelection = (control.selection ?? "single") !== "single";
|
|
28267
28959
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
28268
|
-
"
|
|
28960
|
+
"select",
|
|
28269
28961
|
{
|
|
28962
|
+
"aria-label": controlLabel || control.name || "List box form control",
|
|
28963
|
+
disabled: readOnly || control.controlIndex === void 0 || controlItems.length === 0,
|
|
28964
|
+
multiple: allowsMultipleSelection,
|
|
28965
|
+
onChange: (event) => {
|
|
28966
|
+
event.stopPropagation();
|
|
28967
|
+
if (kind?.kind === "listBox") {
|
|
28968
|
+
const nextSelected = Array.from(event.currentTarget.selectedOptions, (option) => Number(option.value));
|
|
28969
|
+
commitControlKind(
|
|
28970
|
+
{ ...kind, selected: nextSelected },
|
|
28971
|
+
{ selected: nextSelected }
|
|
28972
|
+
);
|
|
28973
|
+
}
|
|
28974
|
+
},
|
|
28975
|
+
onClick: stopControlPointerEvent,
|
|
28976
|
+
onPointerDown: stopControlPointerEvent,
|
|
28977
|
+
size: Math.max(2, Math.min(controlItems.length || 2, Math.floor(rect.height / Math.max(1, fontSizePx * 1.45)))),
|
|
28270
28978
|
style: {
|
|
28271
28979
|
...commonStyle,
|
|
28980
|
+
alignItems: void 0,
|
|
28981
|
+
backgroundColor: SHEET_SURFACE,
|
|
28272
28982
|
border: `${Math.max(1, zoomFactor)}px solid ${stroke}`,
|
|
28273
28983
|
borderRadius: 2 * zoomFactor,
|
|
28274
28984
|
boxSizing: "border-box",
|
|
28275
|
-
|
|
28985
|
+
display: "block",
|
|
28986
|
+
padding: 0
|
|
28276
28987
|
},
|
|
28277
|
-
|
|
28988
|
+
value: allowsMultipleSelection ? selected.map(String) : selected[0] === void 0 ? "" : String(selected[0]),
|
|
28989
|
+
children: controlItems.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: index, children: item }, index))
|
|
28278
28990
|
},
|
|
28279
28991
|
`${pane}-${control.id}`
|
|
28280
28992
|
);
|
|
28281
|
-
} else {
|
|
28282
|
-
content = null;
|
|
28283
28993
|
}
|
|
28284
|
-
|
|
28994
|
+
if (control.kind === "scrollbar") {
|
|
28995
|
+
const kind = buildFormControlKindInput(control);
|
|
28996
|
+
const min = control.min ?? 0;
|
|
28997
|
+
const max = Math.max(min, control.max ?? 100);
|
|
28998
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
28999
|
+
"input",
|
|
29000
|
+
{
|
|
29001
|
+
"aria-label": controlLabel || control.name || "Scrollbar form control",
|
|
29002
|
+
disabled: readOnly || control.controlIndex === void 0,
|
|
29003
|
+
max,
|
|
29004
|
+
min,
|
|
29005
|
+
onChange: (event) => {
|
|
29006
|
+
event.stopPropagation();
|
|
29007
|
+
if (kind?.kind === "scrollbar") {
|
|
29008
|
+
const value = event.currentTarget.valueAsNumber;
|
|
29009
|
+
commitControlKind({ ...kind, value }, { value });
|
|
29010
|
+
}
|
|
29011
|
+
},
|
|
29012
|
+
onClick: stopControlPointerEvent,
|
|
29013
|
+
onPointerDown: stopControlPointerEvent,
|
|
29014
|
+
step: Math.max(1, control.increment ?? 1),
|
|
29015
|
+
style: {
|
|
29016
|
+
...commonStyle,
|
|
29017
|
+
accentColor: paletteIsDark(palette) ? "#60a5fa" : "#2563eb",
|
|
29018
|
+
boxSizing: "border-box",
|
|
29019
|
+
padding: 0,
|
|
29020
|
+
writingMode: control.horizontal === false ? "vertical-lr" : void 0
|
|
29021
|
+
},
|
|
29022
|
+
type: "range",
|
|
29023
|
+
value: Math.max(min, Math.min(max, control.value ?? min))
|
|
29024
|
+
},
|
|
29025
|
+
`${pane}-${control.id}`
|
|
29026
|
+
);
|
|
29027
|
+
}
|
|
29028
|
+
if (control.kind === "spinner") {
|
|
29029
|
+
const kind = buildFormControlKindInput(control);
|
|
29030
|
+
const min = control.min ?? 0;
|
|
29031
|
+
const max = Math.max(min, control.max ?? 100);
|
|
29032
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
29033
|
+
"input",
|
|
29034
|
+
{
|
|
29035
|
+
"aria-label": controlLabel || control.name || "Spinner form control",
|
|
29036
|
+
disabled: readOnly || control.controlIndex === void 0,
|
|
29037
|
+
max,
|
|
29038
|
+
min,
|
|
29039
|
+
onChange: (event) => {
|
|
29040
|
+
event.stopPropagation();
|
|
29041
|
+
if (kind?.kind === "spinner" && Number.isFinite(event.currentTarget.valueAsNumber)) {
|
|
29042
|
+
const value = Math.max(min, Math.min(max, event.currentTarget.valueAsNumber));
|
|
29043
|
+
commitControlKind({ ...kind, value }, { value });
|
|
29044
|
+
}
|
|
29045
|
+
},
|
|
29046
|
+
onClick: stopControlPointerEvent,
|
|
29047
|
+
onPointerDown: stopControlPointerEvent,
|
|
29048
|
+
step: Math.max(1, control.increment ?? 1),
|
|
29049
|
+
style: {
|
|
29050
|
+
...commonStyle,
|
|
29051
|
+
backgroundColor: SHEET_SURFACE,
|
|
29052
|
+
border: `${Math.max(1, zoomFactor)}px solid ${stroke}`,
|
|
29053
|
+
borderRadius: 2 * zoomFactor,
|
|
29054
|
+
boxSizing: "border-box",
|
|
29055
|
+
padding: `0 ${4 * zoomFactor}px`
|
|
29056
|
+
},
|
|
29057
|
+
type: "number",
|
|
29058
|
+
value: Math.max(min, Math.min(max, control.value ?? min))
|
|
29059
|
+
},
|
|
29060
|
+
`${pane}-${control.id}`
|
|
29061
|
+
);
|
|
29062
|
+
}
|
|
29063
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
28285
29064
|
"div",
|
|
28286
29065
|
{
|
|
28287
29066
|
style: {
|
|
28288
29067
|
...commonStyle,
|
|
29068
|
+
border: control.kind === "editbox" || control.kind === "unknown" ? `${Math.max(1, zoomFactor)}px solid ${stroke}` : void 0,
|
|
29069
|
+
borderRadius: 2 * zoomFactor,
|
|
29070
|
+
boxSizing: "border-box",
|
|
28289
29071
|
padding: `0 ${Math.max(1, zoomFactor)}px`
|
|
28290
29072
|
},
|
|
28291
|
-
children:
|
|
28292
|
-
content,
|
|
28293
|
-
controlLabel ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
28294
|
-
"span",
|
|
28295
|
-
{
|
|
28296
|
-
style: {
|
|
28297
|
-
overflow: "hidden",
|
|
28298
|
-
textOverflow: "ellipsis",
|
|
28299
|
-
whiteSpace: "nowrap"
|
|
28300
|
-
},
|
|
28301
|
-
children: controlLabel
|
|
28302
|
-
}
|
|
28303
|
-
) : null
|
|
28304
|
-
]
|
|
29073
|
+
children: controlLabel ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: controlLabel }) : null
|
|
28305
29074
|
},
|
|
28306
29075
|
`${pane}-${control.id}`
|
|
28307
29076
|
);
|
|
@@ -29864,6 +30633,8 @@ function XlsxViewerInner({
|
|
|
29864
30633
|
isDark = false,
|
|
29865
30634
|
loadingComponent,
|
|
29866
30635
|
loadingState,
|
|
30636
|
+
onFormControlAction,
|
|
30637
|
+
onFormControlChange,
|
|
29867
30638
|
renderChartLoading,
|
|
29868
30639
|
renderImage,
|
|
29869
30640
|
renderImageSelection,
|
|
@@ -29926,6 +30697,8 @@ function XlsxViewerInner({
|
|
|
29926
30697
|
getCellStyle,
|
|
29927
30698
|
loadingComponent,
|
|
29928
30699
|
loadingState,
|
|
30700
|
+
onFormControlAction,
|
|
30701
|
+
onFormControlChange,
|
|
29929
30702
|
palette,
|
|
29930
30703
|
renderChartLoading,
|
|
29931
30704
|
renderImage,
|
|
@@ -30032,6 +30805,7 @@ function useXlsxViewerZoom() {
|
|
|
30032
30805
|
}
|
|
30033
30806
|
function useXlsxViewerEditing() {
|
|
30034
30807
|
const {
|
|
30808
|
+
addFormControl,
|
|
30035
30809
|
addSheet,
|
|
30036
30810
|
canRedo,
|
|
30037
30811
|
canUndo,
|
|
@@ -30039,14 +30813,18 @@ function useXlsxViewerEditing() {
|
|
|
30039
30813
|
copySelectionToClipboard,
|
|
30040
30814
|
defineNamedRange,
|
|
30041
30815
|
fillSelection,
|
|
30816
|
+
formControls,
|
|
30042
30817
|
getClipboardData,
|
|
30043
30818
|
getCellDisplayValue: getCellDisplayValue2,
|
|
30044
30819
|
getCellFormula,
|
|
30820
|
+
getFormControlItems,
|
|
30821
|
+
getSheetFormControls,
|
|
30045
30822
|
mergeSelection,
|
|
30046
30823
|
pasteFromClipboard,
|
|
30047
30824
|
pasteStructuredClipboardData,
|
|
30048
30825
|
pasteText,
|
|
30049
30826
|
removeActiveSheet,
|
|
30827
|
+
removeFormControl,
|
|
30050
30828
|
readOnly,
|
|
30051
30829
|
redo,
|
|
30052
30830
|
selectedCellFormula,
|
|
@@ -30063,10 +30841,12 @@ function useXlsxViewerEditing() {
|
|
|
30063
30841
|
setSelectedCellStyle,
|
|
30064
30842
|
setSelectedCellValue,
|
|
30065
30843
|
undo,
|
|
30066
|
-
unmergeSelection
|
|
30844
|
+
unmergeSelection,
|
|
30845
|
+
updateFormControl
|
|
30067
30846
|
} = useXlsxViewer();
|
|
30068
30847
|
return React4.useMemo(
|
|
30069
30848
|
() => ({
|
|
30849
|
+
addFormControl,
|
|
30070
30850
|
addSheet,
|
|
30071
30851
|
canRedo,
|
|
30072
30852
|
canUndo,
|
|
@@ -30074,14 +30854,18 @@ function useXlsxViewerEditing() {
|
|
|
30074
30854
|
copySelectionToClipboard,
|
|
30075
30855
|
defineNamedRange,
|
|
30076
30856
|
fillSelection,
|
|
30857
|
+
formControls,
|
|
30077
30858
|
getClipboardData,
|
|
30078
30859
|
getCellDisplayValue: getCellDisplayValue2,
|
|
30079
30860
|
getCellFormula,
|
|
30861
|
+
getFormControlItems,
|
|
30862
|
+
getSheetFormControls,
|
|
30080
30863
|
mergeSelection,
|
|
30081
30864
|
pasteFromClipboard,
|
|
30082
30865
|
pasteStructuredClipboardData,
|
|
30083
30866
|
pasteText,
|
|
30084
30867
|
removeActiveSheet,
|
|
30868
|
+
removeFormControl,
|
|
30085
30869
|
readOnly,
|
|
30086
30870
|
redo,
|
|
30087
30871
|
selectedCellFormula,
|
|
@@ -30098,9 +30882,11 @@ function useXlsxViewerEditing() {
|
|
|
30098
30882
|
setSelectedCellStyle,
|
|
30099
30883
|
setSelectedCellValue,
|
|
30100
30884
|
undo,
|
|
30101
|
-
unmergeSelection
|
|
30885
|
+
unmergeSelection,
|
|
30886
|
+
updateFormControl
|
|
30102
30887
|
}),
|
|
30103
30888
|
[
|
|
30889
|
+
addFormControl,
|
|
30104
30890
|
addSheet,
|
|
30105
30891
|
canRedo,
|
|
30106
30892
|
canUndo,
|
|
@@ -30108,14 +30894,18 @@ function useXlsxViewerEditing() {
|
|
|
30108
30894
|
copySelectionToClipboard,
|
|
30109
30895
|
defineNamedRange,
|
|
30110
30896
|
fillSelection,
|
|
30897
|
+
formControls,
|
|
30111
30898
|
getClipboardData,
|
|
30112
30899
|
getCellDisplayValue2,
|
|
30113
30900
|
getCellFormula,
|
|
30901
|
+
getFormControlItems,
|
|
30902
|
+
getSheetFormControls,
|
|
30114
30903
|
mergeSelection,
|
|
30115
30904
|
pasteFromClipboard,
|
|
30116
30905
|
pasteStructuredClipboardData,
|
|
30117
30906
|
pasteText,
|
|
30118
30907
|
removeActiveSheet,
|
|
30908
|
+
removeFormControl,
|
|
30119
30909
|
readOnly,
|
|
30120
30910
|
redo,
|
|
30121
30911
|
selectedCellFormula,
|
|
@@ -30132,7 +30922,8 @@ function useXlsxViewerEditing() {
|
|
|
30132
30922
|
setSelectedCellStyle,
|
|
30133
30923
|
setSelectedCellValue,
|
|
30134
30924
|
undo,
|
|
30135
|
-
unmergeSelection
|
|
30925
|
+
unmergeSelection,
|
|
30926
|
+
updateFormControl
|
|
30136
30927
|
]
|
|
30137
30928
|
);
|
|
30138
30929
|
}
|
|
@@ -30718,7 +31509,6 @@ function useXlsxViewerThumbnails(options = {}) {
|
|
|
30718
31509
|
const canvasCellStyle = cellData.canvas ?? buildCanvasCellStyleCache(cellData.style);
|
|
30719
31510
|
const gradientFill = typeof cellData.style.backgroundImage === "string" ? resolveCanvasGradientFill(context, rect, cellData.style.backgroundImage) : null;
|
|
30720
31511
|
const fillColor = cellData.conditionalColorScale?.color ?? (typeof cellData.style.backgroundColor === "string" ? cellData.style.backgroundColor : thumbnailSheetSurface);
|
|
30721
|
-
const hasExplicitCellFill = cellData.conditionalColorScale !== null || gradientFill !== null || typeof cellData.style.backgroundColor === "string" && cellData.style.backgroundColor !== thumbnailSheetSurface;
|
|
30722
31512
|
context.fillStyle = gradientFill ?? fillColor;
|
|
30723
31513
|
context.fillRect(rect.left, rect.top, rect.width, rect.height);
|
|
30724
31514
|
if (cellData.conditionalDataBar) {
|
|
@@ -30743,7 +31533,7 @@ function useXlsxViewerThumbnails(options = {}) {
|
|
|
30743
31533
|
}
|
|
30744
31534
|
}
|
|
30745
31535
|
}
|
|
30746
|
-
if (showGridLines
|
|
31536
|
+
if (showGridLines) {
|
|
30747
31537
|
context.strokeStyle = palette.border;
|
|
30748
31538
|
context.lineWidth = 1;
|
|
30749
31539
|
context.beginPath();
|